用C++调用tensorflow在python下训练好的模型(centos7)

本文主要参考博客https://blog.csdn.net/luoyexuge/article/details/80399265 [1] 
bazel安装参考:https://blog.csdn.net/luoyi131420/article/details/78585989 [2]

首先介绍下自己的环境是centos7,tensorflow版本是1.7,python是3.6(anaconda3)。

要调用tensorflow c++接口,首先要编译tensorflow,要装bazel,要装protobuf,要装Eigen;然后是用python训练模型并保存,最后才是调用训练好的模型,整体过程还是比较麻烦,下面按步骤一步步说明。

1.安装bazel 
以下是引用的[2]

首先安装bazel依赖的环境:
sudo add-apt-repository ppa:webupd8team/javasudo apt-get install openjdk-8-jdk openjdk-8-source sudo apt-get install pkg-config zip g++ zlib1g-dev unzip 注意:如果你没有安装add-apt-repository命令,需要执行sudo apt-get install software-properties-common命令。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

实际上我自己只缺jdk工具,加上我没有sudo权限,我自己是在网上直接下的jdk-8,链接是 
http://www.oracle.com/technetwork/java/javase/downloads/java-archive-javase8-2177648.html 
然后解压,最后将其路径添加到环境变量中: 
export JAVA_HOME=/home/guozitao001/tools/jdk1.8.0_171 
export PATH=$JAVA_HOME/bin:$PATH

然后去git上下载bazel的安装文件https://github.com/bazelbuild/bazel/releases,具体是文件bazel-0.15.0-installer-linux-x86_64.sh。 
(1) 终端切换到.sh文件存放的路径,文件添加可执行权限: 
$ chmod +x bazel-0.5.3-installer-linux-x86_64.sh 
(2)然后执行该文件: 
$ ./bazel-0.5.3-installer-linux-x86_64.sh –user 
注意:–user选项表示bazel安装到HOME/bin目录下,并设置.bazelrc的路径为HOME/.bazelrc。 
安装完成后执行bazel看是否安装成功,这里我并没有添加环境变量就可以直接运行,大家根据自己需要添加。

2.安装protobuf

下载地址:https://github.com/google/protobuf/releases ,我下载的是3.5.1版本,如果你是下载新版的tensorflow,请确保protobuf版本也是最新的,安装步骤:
cd /protobuf
./configure
make
sudo make install
安装之后查看protobuf版本:
protoc --version
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

根据[1]的作者采坑经历所说,protoc一定要注意版本要和tensorflow匹配,总之这里3.5.1的protoc和tensorflow1.7是能够匹配的。

3.安装Eigen

wget http://bitbucket.org/eigen/eigen/get/3.3.4.tar.bz2 下载之后解压放在重新命名为eigen3,我存放的路径是,/Users/zhoumeixu/Downloads/eigen3
  • 1
  • 2

这个没什么好多说的,如果wget失败就直接用浏览器或者迅雷下载就是了。

4.tensorflow下载以及编译: 
1下载TensorFlow ,使用 git clone - –recursive https://github.com/tensorflow/tensorflow 
2.下载bazel工具(mac下载installer-darwin、linux用installer-linux) 
3. 进入tensorflow的根目录 
3.1 执行./configure 根据提示配置一下环境变量,这个不大重要。 
要GPU的话要下载nvidia驱动的 尽量装最新版的驱动吧 还有cudnn version为5以上的 这些在官网都有提及的 
3.2 有显卡的执行 ” bazel build –config=opt –config=cuda //tensorflow:libtensorflow_cc.so ” 
没显卡的 ” –config=cuda ” 就不要加了 
bazel build –config=opt //tensorflow:libtensorflow_cc.so。 
编译成功后会有bazel成功的提示。 
3.3这里编译完过后,最后调用tensorflow模型的时候的时候提示文件tensorflow/tensorflow/core/platform/default/mutex.h缺2个头文件:nsync_cv.h,nsync_mu.h,仔细查找后,发现这两个头文件在python的site-papackages里面,它只是没找到而已,所以我们在mutex.h中将这两个头文件的路径补充完整: 
这里写图片描述
这样之后调用就不会提示缺少头文件了。

4.python训练tensorflow模型: 
下面训练tensorflow模型的pb模型,[1]作者做了个简单的线性回归模型及生成pb格式模型代码:

# coding:utf-8
# python 3.6
import tensorflow as  tf
import numpy as np import os tf.app.flags.DEFINE_integer('training_iteration', 1000, 'number of training iterations.') tf.app.flags.DEFINE_integer('model_version', 1, 'version number of the model.') tf.app.flags.DEFINE_string('work_dir', 'model/', 'Working directory.') FLAGS = tf.app.flags.FLAGS sess = tf.InteractiveSession() x = tf.placeholder('float', shape=[None, 5],name="inputs") y_ = tf.placeholder('float', shape=[None, 1]) w = tf.get_variable('w', shape=[5, 1], initializer=tf.truncated_normal_initializer) b = tf.get_variable('b', shape=[1], initializer=tf.zeros_initializer) sess.run(tf.global_variables_initializer()) y = tf.add(tf.matmul(x, w) , b,name="outputs") ms_loss = tf.reduce_mean((y - y_) ** 2) train_step = tf.train.GradientDescentOptimizer(0.005).minimize(ms_loss) train_x = np.random.randn(1000, 5) # let the model learn the equation of y = x1 * 1 + x2 * 2 + x3 * 3 train_y = np.sum(train_x * np.array([1, 2, 3,4,5]) + np.random.randn(1000, 5) / 100, axis=1).reshape(-1, 1) for i in range(FLAGS.training_iteration): loss, _ = sess.run([ms_loss, train_step], feed_dict={x: train_x, y_: train_y}) if i%100==0: print("loss is:",loss) graph = tf.graph_util.convert_variables_to_constants(sess, sess.graph_def, ["inputs", "outputs"]) tf.train.write_graph(graph, ".", FLAGS.work_dir + "liner.pb", as_text=False) print('Done exporting!') 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

注意这里一定要把需要输入和输出的变量要以string形式的name在tf.graph_util.convert_variables_to_constants中进行保存,比如说这里的inputs和outputs。得到一个后缀为pb的文件 
然后加载该模型,验证是否成功保存模型:

import tensorflow as tf
import  numpy as np
logdir = '/Users/zhoumeixu/Documents/python/credit-nlp-ner/model/'
output_graph_path = logdir+'liner.pb'
with tf.Graph().as_default(): output_graph_def = tf.GraphDef() with open(output_graph_path, "rb") as f: output_graph_def.ParseFromString(f.read()) _ = tf.import_graph_def(output_graph_def,name="") with tf.Session() as sess: input = sess.graph.get_tensor_by_name("inputs:0") output = sess.graph.get_tensor_by_name("outputs:0") result = sess.run(output, feed_dict={input: np.reshape([1.0,1.0,1.0,1.0,1.0],[-1,5])}) print(result) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

运行结果:[[14.998546]], 该结果完全符合预期。

5.C++项目代码,一共有4个文件

model_loader_base.h:

#ifndef CPPTENSORFLOW_MODEL_LOADER_BASE_H
#define CPPTENSORFLOW_MODEL_LOADER_BASE_H
#include <iostream>
#include <vector>
#include "tensorflow/core/public/session.h" #include "tensorflow/core/platform/env.h" using namespace tensorflow; namespace tf_model { /** * Base Class for feature adapter, common interface convert input format to tensors * */ class FeatureAdapterBase{ public: FeatureAdapterBase() {}; virtual ~FeatureAdapterBase() {}; virtual void assign(std::string, std::vector<double>*) = 0; // tensor_name, tensor_double_vector std::vector<std::pair<std::string, tensorflow::Tensor> > input; }; class ModelLoaderBase { public: ModelLoaderBase() {}; virtual ~ModelLoaderBase() {}; virtual int load(tensorflow::Session*, const std::string) = 0; //pure virutal function load method virtual int predict(tensorflow::Session*, const FeatureAdapterBase&, const std::string, double*) = 0; tensorflow::GraphDef graphdef; //Graph Definition for current model }; } #endif //CPPTENSORFLOW_MODEL_LOADER_BASE_H 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

ann_model_loader.h:

#ifndef CPPTENSORFLOW_ANN_MODEL_LOADER_H
#define CPPTENSORFLOW_ANN_MODEL_LOADER_H#include "model_loader_base.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/platform/env.h" using namespace tensorflow; namespace tf_model { /** * @brief: Model Loader for Feed Forward Neural Network * */ class ANNFeatureAdapter: public FeatureAdapterBase { public: ANNFeatureAdapter(); ~ANNFeatureAdapter(); void assign(std::string tname, std::vector<double>*) override; // (tensor_name, tensor) }; class ANNModelLoader: public ModelLoaderBase { public: ANNModelLoader(); ~ANNModelLoader(); int load(tensorflow::Session*, const std::string) override; //Load graph file and new session int predict(tensorflow::Session*, const FeatureAdapterBase&, const std::string, double*) override; }; } #endif //CPPTENSORFLOW_ANN_MODEL_LOADER_H 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

ann_model_loader.cpp:

#include <iostream>
#include <vector>
#include <map>
#include "ann_model_loader.h"
//#include <tensor_shape.h> using namespace tensorflow; namespace tf_model { /** * ANNFeatureAdapter Implementation * */ ANNFeatureAdapter::ANNFeatureAdapter() { } ANNFeatureAdapter::~ANNFeatureAdapter() { } /* * @brief: Feature Adapter: convert 1-D double vector to Tensor, shape [1, ndim] * @param: std::string tname, tensor name; * @parma: std::vector<double>*, input vector; * */ void ANNFeatureAdapter::assign(std::string tname, std::vector<double>* vec) { //Convert input 1-D double vector to Tensor int ndim = vec->size(); if (ndim == 0) { std::cout << "WARNING: Input Vec size is 0 ..." << std::endl; return; } // Create New tensor and set value Tensor x(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, ndim})); // New Tensor shape [1, ndim] auto x_map = x.tensor<float, 2>(); for (int j = 0; j < ndim; j++) { x_map(0, j) = (*vec)[j]; } // Append <tname, Tensor> to input input.push_back(std::pair<std::string, tensorflow::Tensor>(tname, x)); } /** * ANN Model Loader Implementation * */ ANNModelLoader::ANNModelLoader() { } ANNModelLoader::~ANNModelLoader() { } /** * @brief: load the graph and add to Session * @param: Session* session, add the graph to the session * @param: model_path absolute path to exported protobuf file *.pb * */ int ANNModelLoader::load(tensorflow::Session* session, const std::string model_path) { //Read the pb file into the grapgdef member tensorflow::Status status_load = ReadBinaryProto(Env::Default(), model_path, &graphdef); if (!status_load.ok()) { std::cout << "ERROR: Loading model failed..." << model_path << std::endl; std::cout << status_load.ToString() << "\n"; return -1; } // Add the graph to the session tensorflow::Status status_create = session->Create(graphdef); if (!status_create.ok()) { std::cout << "ERROR: Creating graph in session failed..." << status_create.ToString() << std::endl; return -1; } return 0; } /** * @brief: Making new prediction * @param: Session* session * @param: FeatureAdapterBase, common interface of input feature * @param: std::string, output_node, tensorname of output node * @param: double, prediction values * */ int ANNModelLoader::predict(tensorflow::Session* session, const FeatureAdapterBase& input_feature, const std::string output_node, double* prediction) { // The session will initialize the outputs std::vector<tensorflow::Tensor> outputs; //shape [batch_size] // @input: vector<pair<string, tensor> >, feed_dict // @output_node: std::string, name of the output node op, defined in the protobuf file tensorflow::Status status = session->Run(input_feature.input, {output_node}, {}, &outputs); if (!status.ok()) { std::cout << "ERROR: prediction failed..." << status.ToString() << std::endl; return -1; } //Fetch output value std::cout << "Output tensor size:" << outputs.size() << std::endl; for (std::size_t i = 0; i < outputs.size(); i++) { std::cout << outputs[i].DebugString(); } std::cout << std::endl; Tensor t = outputs[0]; // Fetch the first tensor int ndim = t.shape().dims(); // Get the dimension of the tensor auto tmap = t.tensor<float, 2>(); // Tensor Shape: [batch_size, target_class_num] int output_dim = t.shape().dim_size(1); // Get the target_class_num from 1st dimension std::vector<double> tout; // Argmax: Get Final Prediction Label and Probability int output_class_id = -1; double output_prob = 0.0; for (int j = 0; j < output_dim; j++) { std::cout << "Class " << j << " prob:" << tmap(0, j) << "," << std::endl; if (tmap(0, j) >= output_prob) { output_class_id = j; output_prob = tmap(0, j); } } // Log std::cout << "Final class id: " << output_class_id << std::endl; std::cout << "Final value is: " << output_prob << std::endl; (*prediction) = output_prob; // Assign the probability to prediction return 0; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133

main.cpp:

#include <iostream>
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/platform/env.h"
#include "ann_model_loader.h"using namespace tensorflow; int main(int argc, char* argv[]) { if (argc != 2) { std::cout << "WARNING: Input Args missing" << std::endl; return 0; } std::string model_path = argv[1]; // Model_path *.pb file // TensorName pre-defined in python file, Need to extract values from tensors std::string input_tensor_name = "inputs"; std::string output_tensor_name = "outputs"; // Create New Session Session* session; Status status = NewSession(SessionOptions(), &session); if (!status.ok()) { std::cout << status.ToString() << "\n"; return 0; } // Create prediction demo tf_model::ANNModelLoader model; //Create demo for prediction if (0 != model.load(session, model_path)) { std::cout << "Error: Model Loading failed..." << std::endl; return 0; } // Define Input tensor and Feature Adapter // Demo example: [1.0, 1.0, 1.0, 1.0, 1.0] for Iris Example, including bias int ndim = 5; std::vector<double> input; for (int i = 0; i < ndim; i++) { input.push_back(1.0); } // New Feature Adapter to convert vector to tensors dictionary tf_model::ANNFeatureAdapter input_feat; input_feat.assign(input_tensor_name, &input); //Assign vec<double> to tensor // Make New Prediction double prediction = 0.0; if (0 != model.predict(session, input_feat, output_tensor_name, &prediction)) { std::cout << "WARNING: Prediction failed..." << std::endl; } std::cout << "Output Prediction Value:" << prediction << std::endl; return 0; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

将这四个文件放在同一个路径下,然后还需要添加一个Cmake的txt文件:


cmake_minimum_required(VERSION 2.8) project(cpptensorflow) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x -g -fopenmp -fno-strict-aliasing") link_directories(/home/xxx/tensorflow/bazel-bin/tensorflow) include_directories( /home/xxx/tensorflow /home/xxx/tensorflow/bazel-genfiles /home/xxx/tensorflow/bazel-bin/tensorflow /home/xxx/tools/eigen3 ) add_executable(cpptensorflow main.cpp ann_model_loader.h model_loader_base.h ann_model_loader.cpp) target_link_libraries(cpptensorflow tensorflow_cc tensorflow_framework) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这里注意cmake_minimum_required(VERSION 2.8)要和自己系统的cmake最低版本相符合。

然后在当前目录下建立一个build的空文件夹: 
这里写图片描述

mkdir  build
cd  build
cmake ..
make 
生成cpptensorflow执行文件,后接保存的模型pb文件路径:
./cpptensorflow /Users/zhoumeixu/Documents/python/credit-nlp-ner/model/liner.pb
Final value is: 14.9985
Output Prediction Value:14.9985
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

到此基本就结束了,最后感谢下作者[1],我真是差点被搞疯了。。。

 

原文:https://blog.csdn.net/gzt940726/article/details/81053378

转载于:https://www.cnblogs.com/Ph-one/p/9516490.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367669.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

纯CSS实现圆角边框

HTML部分&#xff1a;<body><div> <b class”t1″></b> <b class”t2″></b> <b class”t3″></b> <b class”t4″></b> <div class”cont”>这边输入实际内容</div> <b clas…

ActiveMQ producer同步/异步发送消息

http://activemq.apache.org/async-sends.html producer发送消息有同步和异步两种模式&#xff0c;可以通过代码配置&#xff1a; ((ActiveMQConnection)connection).setUseAsyncSend(true); producer默认是异步发送消息。在没有开启事务的情况下&#xff0c;producer发送持久化…

Java Priority Queue(PriorityQueue)示例

我们知道&#xff0c; 队列如下&#xff1a;F irst- 我正˚First-UT模型&#xff0c;但有时我们需要处理的基础上&#xff0c;优先级队列中的对象。 例如&#xff0c;假设我们有一个应用程序可以为日常交易生成股票报告&#xff0c;并处理大量数据并花费时间来处理它。 因此&am…

css未知尺寸的图片的水平和垂直居中

纯CSS实现未知尺寸的图片水平和垂直居中.box { /*非IE的主流浏览器识别的垂直居中的方法*/ display: table-cell; vertical-align:middle; /*设置水平居中*/ text-align:center; /* 针对IE的Hack */ *display: block; *font-size:26…

heap 的一些用法

noip 合并果子 #include<bits/stdc.h> using namespace std; int heap[maxn]; int size0; void input(int d) {heap[size]d;push_heap(heap,heapsize,greater<int>()); } int get() {pop_heap(heap,heapsize,greater<int>());//pop_heap(heap,heapsize);ret…

java 反射 new class_Java高级特性-反射:不写死在代码,还怎么 new 对象?

反射是 Java 的一个高级特性&#xff0c;大量用在各种开源框架上。在开源框架中&#xff0c;往往以同一套算法&#xff0c;来应对不同的数据结构。比如&#xff0c;Spring 的依赖注入&#xff0c;我们不用自己 new 对象了&#xff0c;这工作交给 Spring 去做。然而&#xff0c;…

EF Core利用Scaffold从根据数据库生成代码

在EF6 之前的时代&#xff0c;如果需要从数据库中生成代码&#xff0c;是可以直接在界面上操作的&#xff0c;而到了EF Core的时代&#xff0c;操作方式又有更简便的方式了&#xff0c;我们只需要记住以下这条指令。 Scaffold-DbContext "Server服务器地址;Database数据库…

如何通过CSS开启硬件加速来提高网站性能

你知道我们可以在浏览器中用css开启硬件加速&#xff0c;使GPU (Graphics Processing Unit) 发挥功能&#xff0c;从而提升性能吗&#xff1f; 现在大多数电脑的显卡都支持硬件加速。鉴于此&#xff0c;我们可以发挥GPU的力量&#xff0c;从而使我们的网站或应用表现的更为流畅…

Spring Security应用程序中的su和sudo

很久以前&#xff0c;我从事的项目具有很强大的功能。 有两个角色&#xff1a;用户和主管。 主管可以以任何方式更改系统中的任何文档&#xff0c;而用户则更受工作流约束的限制。 当普通用户对当前正在编辑和存储在HTTP会话中的文档有疑问时&#xff0c;主管可以介入&#xff…

示例介绍:JavaFX 8打印

我有一段时间没有写博客了&#xff0c;我想与其他人分享有关JavaFX的所有信息&#xff08;我的日常工作和家庭可能是借口&#xff09;。 对于那些是本博客的新手&#xff0c;我是JavaFX 2 Introduction by Example&#xff08;JIBE&#xff09;的作者&#xff0c; Java 7 Recip…

placeholder的使用

1.定义 placeholder 属性提供可描述输入字段预期值的提示信息 该提示会在输入字段为空时显示&#xff0c;并会在字段获得焦点时消失。 注释&#xff1a;placeholder 属性适用于以下的 <input> 类型&#xff1a;text, search, url, telephone, email 以及 password。 2.用…

字符串练习

字符串练习&#xff1a; http://news.gzcc.cn/html/2017/xiaoyuanxinwen_1027/8443.html 取得校园新闻的编号 trhttp://news.gzcc.cn/html/2017/xiaoyuanxinwen_1027/8443.html print(a[-14:-5])https://docs.python.org/3/library/turtle.html 产生python文档的网址 trhttps:/…

CSS清除行内元素之间的HTML空白

至今我还记得年轻是在IE6上开发的那些苦逼日子,特别希望IE浏览器采用 inline-block 的显示方式.行内块(inline-block)是非常有用的,特别是想要不用block和float来控制这些行内元素的margin,padding之时。问题来了,HTML源码中行内元素之间的空白有时候显示在屏幕上那是相当的讨厌…

int64 java_为什么json 不能使用 int64类型

json 简介jsON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集 。 JSON采用完全独立于语言的文本格式&#xff0…

Spring MVC自定义验证注释

在上一教程中&#xff0c;我展示了如何使用注释来验证表单 。 这对于简单的验证非常有用&#xff0c;但是最终&#xff0c;您需要验证一些现成的注释中没有的自定义规则。 例如&#xff0c;如果您需要根据输入的出生日期来验证用户已超过21岁&#xff0c;或者可能需要验证用户的…

Best Time to Buy and Sell Stock with Cooldown

https://soulmachine.gitbooks.io/algorithm-essentials/java/dp/best-time-to-buy-and-sell-stock-with-cooldown.html转载于:https://www.cnblogs.com/ZhiHao-queue/p/9521933.html

前期

转载于:https://www.cnblogs.com/joker157/p/8618091.html

解决IE8下body{ overflow:hidden;}无效的解决办法

css中IE8 body{ overflow:hidden;}无效的解决办法&#xff1a; 在页面html中使用: body{ overflow:hidden; } 在ie8下无效 &#xff0c;仍然有滚动条。 解决的办法如下&#xff1a; 替换为如下: html { overflow:hidden; } 这样就可以实现隐藏滚动条了 而且兼容目前所有的浏览器…

0基础能学mysql数据库吗_mysql学习入门:零基础如何使用mysql创建数据库表?

零基础如何自学Mysql创建数据库&#xff0c;是Mysql学习者必经之路&#xff0c;Mysql是受欢迎的关系数据库管理系统,WEB应用方面MySQL是很好的RDBMS应用软件之一。如何使用Mysql创建数据库表&#xff0c;打开Mysql学习进阶大门&#xff0c;就是今天MYSQL学习教程丁光辉博客认为…

使用ANTLR和Java创建外部DSL

在以前的一段时间里&#xff0c;我曾写过有关使用Java的内部DSL的文章。 在Martin Fowler撰写的《 领域特定语言 》一书中&#xff0c;他讨论了另一种称为外部DSL的DSL&#xff0c;其中DSL是用另一种语言编写的&#xff0c;然后由宿主语言进行解析以填充语义模型。 在前面的示…