windows下编译 tensorflow1.10.0 源码 用其c++接口调用训练好的模型

最近在研究如何用 tensorflow 的 python 库训练模型,生成 pb 文件,再在 c++ 中调用这个模型,完成前向的预测;所以就要使用其 c++ 接口,这需要从源码编译 tensorflow 。
 
根据官网给出的编译器对应关系(详见我的另一篇博客),最新版(1.12版)的 tensorflow 需要用bazel去编译,官网的编译教程也给的是用 bazel 编译,但是我弄了半天然后失败了。所以我就用cmake去编译旧版(1.10版),网上说1.4.0版本也能成功。


一、环境准备

1.操作系统:windows
2.安装 git
3.安装 visual studio 2015(即vs14)
4.安装 python3.5 或 3.6
5.下载 swig
6.安装 cmake,版本号需要>=3.6.3
7.科学上网(否则一些依赖的文件可能下载不下来导致编译失败,错误信息为:error downloading xxx failed)


二、编译 tensorflow1.10.0
1. 用git下载源码(或者直接去tensorflow的github地址下载其源码的zip包
git clone -b v1.10.0 https://github.com/tensorflow/tensorflow.git
2. 使用 Cmake 编译 tensorflow

选择 source code 的文件夹,以及 build the binary 的目录,build 文件夹需要创建。

点击 Configure 之后选择 VS2015 x64,之后点击 Finish
在这里插入图片描述
之后会报一个 swig 的错误,搜索:SWIG_EXECUTABLEValue 设置成自己的 swig.exe 的目录。
在这里插入图片描述
继续点击 Configure,成功后点击 Generate,成功后的输出如下:
在这里插入图片描述

3. 使用 VS2015 编译 tensorflow1.10.0

用 vs 打开 D:\src\tensorflow1.10.0\tensorflow\contrib\cmake\build 中的 tensorflow.sln,分别将前面这几个以下划线开头的项目的属性修改一下,方法:右击项目→属性→配置属性→链接器→常规→附加库目录,添加$(SolutionDir)$(Configuration); 如图所示。 不这样做的话,编译这几个项目时会报错,错误信息: fatal error LNK1181: 无法打开输入文件“\pywrap_tensorflow_internal.lib”

在这里插入图片描述

注意:
① 设置最多并行生成几个项目,方法:菜单栏中的工具(T)→选项(O)→项目和解决方案→生成并运行,本来是12,可以改小一点,我改成了2。 不这样做的话,编译时会导致堆内存被耗尽,错误信息: fatal error C1060: 编译器的堆空间不足
在这里插入图片描述

翻好墙,关掉360,关掉防火墙,关掉其他程序给编译腾出内存空间,现在可以开始生成 ALL_BUILD了,右键 ALL_BUILD,点击生成。大约要等3个小时左右,如下:
在这里插入图片描述
注意:
如果显示 re2 报错,错误信息: error C2001: 常量中有换行符,那就用vs打开D:\src\tensorflow1.10.0\tensorflow\contrib\cmake\build\re2\src\re2 中的 re2.sln,分别将 re2_test.cc 和 search_test.cc 的编码方式修改掉,方法: 打开cc文件→单击菜单栏中的文件(F)→高级保存选项(文件下拉菜单中没有高级保存选项的请自行百度一下,设置一下就有了),改成 UTF-8 的签名,如图所示。
在这里插入图片描述
然后生成 re2 的ALL_BUILD。


三、Tensorflow1.10.0 与 VS2015 的配置与测试

这里强调一下,由于公司网络原因,所以编译的时候下载东西总是不通过,就直接在CSDN上下载了一个编译好了的 tensorflow1.8.0 的 CPU 版本,就直接上来先用上吧。

  • 添加环境变量(重启后才能生效):
    tensorflow.dll 所在的目录,或者将 tensorflow.dll 复制到工程目录下。

  • 将以下目录,添加到“包含目录中”
    D:\env\tensorflow180_cpu\include

  • 将以下目录添加到 “库目录中”
    D:\env\tensorflow180_cpu\lib

  • tensorflow.lib 添加到“附加依赖库中”

这是一个 mnist 的手写数字模型的例子 ↓↓↓↓↓

#include <fstream>
#include <utility>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <iostream>

#include "tensorflow/cc/ops/const_op.h"
#include "tensorflow/cc/ops/image_ops.h"
#include "tensorflow/cc/ops/standard_ops.h"

#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/tensor.h"

#include "tensorflow/core/graph/default_device.h"
#include "tensorflow/core/graph/graph_def_builder.h"

#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/stringprintf.h"

#include "tensorflow/core/public/session.h"
#include "tensorflow/core/util/command_line_flags.h"

#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"

#include "opencv2/opencv.hpp"

using namespace tensorflow::ops;
using namespace tensorflow;
using namespace std;
using namespace cv;
using tensorflow::Flag;
using tensorflow::Tensor;
using tensorflow::Status;
using tensorflow::string;
using tensorflow::int32;

// 定义一个函数讲OpenCV的Mat数据转化为tensor,python里面只要对cv2.read读进来的矩阵进行np.reshape之后,
// 数据类型就成了一个tensor,即tensor与矩阵一样,然后就可以输入到网络的入口了,但是C++版本,我们网络开放的入口
// 也需要将输入图片转化成一个tensor,所以如果用OpenCV读取图片的话,就是一个Mat,然后就要考虑怎么将Mat转化为
// Tensor了
void CVMat_to_Tensor(Mat img, Tensor* output_tensor, int input_rows, int input_cols)
{
	//imshow("input image",img);
	//图像进行resize处理
	resize(img, img, cv::Size(input_cols, input_rows));
	//imshow("resized image",img);

	//归一化
	img.convertTo(img, CV_32FC1);
	img = 1 - img / 255;

	//创建一个指向tensor的内容的指针
	float *p = output_tensor->flat<float>().data();

	//创建一个Mat,与tensor的指针绑定,改变这个Mat的值,就相当于改变tensor的值
	cv::Mat tempMat(input_rows, input_cols, CV_32FC1, p);
	img.convertTo(tempMat, CV_32FC1);

	//    waitKey(0);

}

int main(int argc, char** argv)
{
	/*--------------------------------配置关键信息------------------------------*/
	
	string model_path = "D://code//PyCharmProject//ChangeModelProject//models//my_model_ep20.pb";
	string image_path = "D://code//PyCharmProject//ChangeModelProject//images//1.jpg";
	int input_height = 28;
	int input_width = 28;
	string input_tensor_name = "conv2d_1_input:0";
	string output_tensor_name = "dense_2/Softmax:0";

	/*--------------------------------创建session------------------------------*/
	
	Session* session;
	Status status = NewSession(SessionOptions(), &session);//创建新会话Session

	/*--------------------------------从pb文件中读取模型--------------------------------*/
	
	GraphDef graphdef; //Graph Definition for current model
	Status status_load = ReadBinaryProto(Env::Default(), model_path, &graphdef); //从pb文件中读取图模型;

	if (!status_load.ok()) {
		cout << "ERROR: Loading model failed..." << model_path << std::endl;
		cout << status_load.ToString() << "\n";
		return -1;
	}
	Status status_create = session->Create(graphdef); //将模型导入会话Session中;
	if (!status_create.ok()) {
		cout << "ERROR: Creating graph in session failed..." << status_create.ToString() << std::endl;
		return -1;
	}

	cout << "<----Successfully created session and load graph.------->" << endl;

	/*---------------------------------载入测试图片-------------------------------------*/

	cout << endl << "<------------loading test_image-------------->" << endl;
	Mat img = imread(image_path, 0);

	if (img.empty())
	{
		cout << "can't open the image!!!!!!!" << endl;
		return -1;
	}

	//创建一个tensor作为输入网络的接口
	Tensor resized_tensor(DT_FLOAT, TensorShape({ 1,input_height,input_width,1 }));

	//将Opencv的Mat格式的图片存入tensor
	CVMat_to_Tensor(img, &resized_tensor, input_height, input_width);

	cout << resized_tensor.DebugString() << endl;

	/*-----------------------------------用网络进行测试-----------------------------------------*/
	
	cout << endl << "<-------------Running the model with test_image--------------->" << endl;
	//前向运行,输出结果一定是一个tensor的vector
	vector<tensorflow::Tensor> outputs;
	string output_node = output_tensor_name;
	Status status_run = session->Run({ { input_tensor_name, resized_tensor } }, { output_node }, {}, &outputs);

	if (!status_run.ok()) {
		cout << "ERROR: RUN failed..." << std::endl;
		cout << status_run.ToString() << "\n";
		return -1;
	}

	//把输出值给提取出来
	cout << "Output tensor size:" << outputs.size() << std::endl;
	for (std::size_t i = 0; i < outputs.size(); i++) {
		cout << outputs[i].DebugString() << endl;
	}

	Tensor t = outputs[0];                   // Fetch the first 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

											 // 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++)
	{
		cout << "Class " << j << " prob:" << tmap(0, j) << "," << std::endl;
		if (tmap(0, j) >= output_prob) {
			output_class_id = j;
			output_prob = tmap(0, j);
		}
	}

	// 输出结果
	cout << "Final class id: " << output_class_id << std::endl;
	cout << "Final class prob: " << output_prob << std::endl;

	system("pause");

	return 0;
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值