Tensorflow工程化记录,使用C++调用模型,摒弃Python等依赖环境
大多数情况下,训练模型是在Python环境下,需要安装一大堆环境,非常繁琐,且无法交给别人使用。在Python环境下模型训练完成后,如何供别人使用是一个大问题。
最近,项目需要,实现了Tensorflow的工程化。期间,有太多的坑要填。在此,作简单记录。
环境:
1.VS2015 (一定是VS2015,过高、过低都不行);
2.CMake3.8(正常的话,3.5以上就可以,需要看Tensorflow的CMake文件所需的最小版本);
3.Tensoseflow版本:1.8(建议),刚开始用的版本是1.4,session在run的时候会出错;
首先,编译Tensorflow。没有什么注意的,如图:
这里要注意,修改PREFIX为非C盘,否则,可能会因为权限问题,无法写入文件,而出错。
Generate后生成tensorflow.sln文件,用vs2015打开,生成ALLBUILD项目,等待1个多小时生成结束后,再次,单独生成tf_core_kernels,等待生成结束,再次单独编译tensorflow_static,生成结束后,最后单独生成tensorflow。便可获得tensorflow.lib和tensorflow.dll。到此,完成编译。
其次,固化模型:
固化模型可在Python环境中进行。
def freeze_graph():
dir = os.path.dirname(os.path.realpath(__file__))
checkpoint = tf.train.get_checkpoint_state(dir + '/experiments/OutModel')
input_checkpoint = checkpoint.model_checkpoint_path
print(input_checkpoint)
input_checkpoint = checkpoint.model_checkpoint_path
absolute_model = '/'.join(input_checkpoint.split('/')[:-1])
print(absolute_model)
output_grap = absolute_model + "/frozen_model.pb"
with tf.Session(graph=tf.Graph()) as sess:
saver = tf.train.import_meta_graph(input_checkpoint + '.meta',
clear_devices=True)
saver.restore(sess, input_checkpoint)
# 打印图中的变量,查看要保存的
for op in tf.get_default_graph().get_operations():
print(op.name + '\t' + str(op.values()))
output_grap_def = tf.graph_util.convert_variables_to_constants(sess, tf.get_default_graph().as_graph_def(), output_node_names=['output'])
with tf.gfile.GFile(output_grap, 'wb') as f:
f.write(output_grap_def.SerializeToString())
print("%d ops in the final graph." % len(output_grap_def.node))
其中,输出节点必须定义,而这个节点在网络里很难找。办法是通过tensorboard去分析和寻找,从而生成*.pb文件,也就是固化模型。
最后,需要通过第三方库读取图像,转化为Tensor,在VS中创建工程,读取Tensor作为输入。
void CVMatToTensor(cv::Mat img, Tensor* output_tensor, int input_rows, int input_cols)
{
resize(img, img, cv::Size(input_cols, input_rows));
img.convertTo(img, CV_32FC3);
float *pTensor = output_tensor->flat<float>().data();
cv::Mat tempMat(input_rows, input_cols, CV_32FC3, pTensor);
img.convertTo(tempMat, CV_32FC3);
}
创建Graph,设定输入和输出,session->run()即可获得结果;run()函数有四个参数,输入节点、张量,输出节点、{}、输出。
备注:在这个过程中,一定会遇到无数坑的,需要一点一点填平。这里可以说明的是,工程化一定可以实现,不同的网络可能会遇到不同的问题。