最近在研究如何用C++ 调用基于python库训练的tensorflow模型,完成模型预测。具体步骤如下:

  • 在python中,用tensorflow的python库,训练模型,并生成pb文件;
  • 准备好tensorflow的c++库(重点);
  • 在c++中用tensorflow的API来调用这个pb文件。

1.编译Tensorflow源码

关于编译tensorflow源码的方法有两种:CMake和Bazel,不管哪一种编译的方法都会遇到一些坑,当然如果不想自己踩坑,也可以选择第三种方法,使用tensorflow的编译好版本文件,具体查看方法三。

根据官网给出的编译器对应关系:https://tensorflow.google.cn/install/source,tensorflow 1.12版以后需要用bazel去编译,cmake只能去编译1.12版以前的旧版,大家看自己的需求自行选择吧!

1.1 使用cmake编译

操作系统:windows
安装git,
安装visual studio 2015(即vs14)
安装python3.5或3.6(或直接安装anaconda,下载地址)并加入环境变量
下载swig,
安装cmake,版本号需要>=3.6.3,
科学上网(最好有,否则一些依赖的文件可能下载不下来导致编译失败,错误信息为:error downloading xxx failed)

遇到的问题

2.C++调用tensorflow model

训练就不多说了,不过要留意整个计算图中的输入输出的tensor的名称,例如我的网络有两个输入,叫’input1’和’input2’,有两个输出,叫’output1’和’output2’,这些名字后面要用到。

生成pb文件可以添加如下代码:

constant_graph = tf.graph_util.convert_variables_to_constants(sess, sess.graph_def,['output1','output2']) with tf.gfile.FastGFile('weight.pb', mode='wb') as f:     f.write(constant_graph.SerializeToString()) 

请注意上述代码第一行中需要写上输出tensor的名称列表(输入tensor不用写)。

1.编译成功后我们可以用这些头文件以及tensorflow.lib/dll来编写自己的测试工程了。

#pragma once  //这一句防止重复include头文件   #define COMPILER_MSVC #define NOMINMAX  //这一句防止max/min函数命名冲突 

2.源文件为TestTensorFlow.cpp

#include "TestTensorFlow.h"   #include "tensorflow/cc/client/client_session.h" #include "tensorflow/cc/ops/standard_ops.h" #include "tensorflow/core/framework/tensor.h"   int main() { 	using namespace tensorflow; 	using namespace tensorflow::ops; 	Scope root = Scope::NewRootScope(); 	// Matrix A = [3 2; -1 0] 	auto A = Const(root, { { 3.f, 2.f },{ -1.f, 0.f } }); 	// Vector b = [3 5] 	auto b = Const(root, { { 3.f, 5.f } }); 	// v = Ab^T 	auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true)); 	std::vector<Tensor> outputs; 	ClientSession session(root); 	// Run and fetch v 	TF_CHECK_OK(session.Run({ v }, &outputs)); 	// Expect outputs[0] == [19; -3] 	LOG(INFO) << outputs[0].matrix<float>(); 	return 0; } 

遇到的问题

C2589 “(”:“::”右边的非法标记

第一种办法:设置项目属性,在预定义处理器中添加定义NOMINMAX来禁止使用Visual C++的min/max宏定义。 项目属性 ——> C/C++ ——> 预处理器 ——> 预处理器定义 (此处添加预定义编译开关 NOMINMAX)
但是visual C++中定义能自动匹配double和int,如果进行了上述设置,代码中手动将int型的数据乘以1.0来达到double的目的。
第二种办法: 加上括号,与Vsual C++的min/max宏定义区分开

你得到一个LNK1181错误在Visual Studio LIB或.obj文件指定在连接在当前目录没有发现,任何指定的目录LIBPATH链接器选项,或任何的LIB环境变量中指定的目录。
您可以添加包含libclamav的目录。lib库文件到LIBPATH解决这个问题(这个说明可能会有所不同,取决于你的Visual Studio版本):

在“解决方案资源管理器”中,右键单击项目,然后单击“属性”。
在“属性页”对话框中展开“链接器”,然后单击“常规”。
在附加库目录字段中,指定libclamav所在的路径,libclamav.lib
当LIBPATH包含空格时也可能发生错误。如果是这种情况,请将库移动到没有空格的路径上,或者在路径周围加上引号。

我希望我能给你1000个赞!我试图更新一个遗留项目,LIBPATH中有空格!我已经找了好几个小时了,没人告诉我。我不知道它在原来的开发环境中是如何工作的!也许他们碰巧也有它在LIB环境……无论如何,我不知道更现代的VS版本是如何处理这个问题的,但是vc++ 6(别问了!)并没有优雅表示。- 5月19日14时9分12秒
为了防止别人无意中发现我的错误,我犯了一个更基本、更愚蠢的错误。我试图在“仅在项目中”构建。确保先构建您的依赖项!右键点击你的项目文件,然后点击build。

问题:找不到tensorflow.dll文件,无法继续执行代码

解决:把dll文件放到.cpp,.h等文件的目录下,不要放到解决方案的目录下。

参考文章

  • 版权声明:文章来源于网络采集,版权归原创者所有,均已注明来源,如未注明可能来源未知,如有侵权请联系管理员删除。

发表回复

后才能评论