vs2015调用tensorflow.dll实现mnist识别

1.准备文件

一共需要三个文件,dll文件,lib文件,和tensorflow源码,其中源码指的是build目录底下已经生成过工程文件并成功编译的,因为有很多接下来项目中包含的头文件是在编译之后产生的。准备文件
建议把三个文件放到后面新建的vs2015项目的sln文件所在目录下。

2. 新建vs2015项目, 并配置项目的属性,主要四个部分:

(1) 附加包含目录(添加头文件所在目录)
(2) 附加库目录(添加lib文件所在目录)
(3) 附加依赖项(添加lib文件具体文件名)
(4) 运行时环境(添加dll所在目录)

新建vs2015项目后,右键项目->属性:
项目属性
选择平台,由于我之前编译tensorflow.dll文件时选择的是release64位,因此这里配置平台选择release和x64:
选择平台
接下来是

(1) 附加包含目录(添加头文件所在目录)

点击C/C++ ->附加包含目录 ->编辑:
输入下面的包含目录

C:\eigen
$(SolutionDir)tensorflow-r1.6
$(SolutionDir)tensorflow-r1.6\tensorflow\contrib\cmake\build
$(SolutionDir)tensorflow-r1.6\tensorflow\contrib\cmake\build\protobuf\src\protobuf\src
$(SolutionDir)tensorflow-r1.6\tensorflow\contrib\cmake\build\external\nsync\public
$(SolutionDir)tensorflow-r1.6\tensorflow\contrib\cmake\build\external\eigen_archive

其中C:\eigen表示eigen所在目录,eigen下载地址,下载完成解压即可。
$(SolutionDir)表示项目解决方案sln文件所在目录。
tensorflow-r1.6是tensorflow编译后源码的根目录。

在这里插入图片描述
附加包含目录

(2) 附加库目录(添加lib文件所在目录)

链接器 -> 常规 -> 附加库目录 -> 编辑,输入:

$(SolutionDir)

这里因为tensorflow.lib文件在项目根目录下,所以输入$(SolutionDir),由于项目用到了opencv,因此还要输入opencv的lib所在目录。
附加库目录

(3) 附加依赖项(添加lib文件具体文件名)

链接器 -> 输入 -> 附加依赖项 -> 编辑,步骤与上面的附加库目录相同,输入:

扫描二维码关注公众号,回复: 4522182 查看本文章

tensorflow.lib

(4) 运行时环境(添加dll所在目录)

配置属性 -> 调试 -> 环境 -> 编辑,输入

path = $(SolutionDir)

运行时环境

3.转换tensorflow模型(ckpt->pb)

一般tensorflow通过saver进行模型保存的时候,会将模型的参数和图结构分开存储。如图:
ckpt格式
其中meta是模型图结构,data是模型权值参数。而pb模型则是将图结构和权值参数绑定到一起,具体来说就是将data里的变量参数转成常量参数写到pb文件中去。那么如何将ckpt格式的模型转换成pb模型呢?
理论和详细介绍参见博客。这里具体讲一下如何实现。

(1)确定输出节点

在转换ckpt文件到pb文件过程中,需要确定输出节点。一般来说,训练模型的源代码里面会定义节点名字。如果没办法获得源码,或者源码里面没有定义节点名字的话,可以通过以下代码加载ckpt格式的模型,打印出所有的节点。

#encoding=utf-8
import tensorflow as tf
input_checkpoint = './model.ckpt'#模型路径
#恢复图的结构
saver = tf.train.import_meta_graph(input_checkpoint + '.meta', clear_devices=True)
 
with tf.Session() as sess:
    saver.restore(sess, input_checkpoint) #恢复图并得到数据
    for op in tf.get_default_graph().get_operations():
        print(op.name, op.values()) #打印节点名字和张量维度信息
        

本项目中mnist模型打印出的节点如图所示(部分):
打印出的节点

tensorflow 每调用一次类似 tf.XXX()函数,就代表了生成一个节点,那么tf.variable()就会生成一个Variable节点,如果调用了很多次,就生成Variable_1,Variable_2…以此类推。
我们看一个简单例子:

#encoding=utf-8
import tensorflow as tf

#下面代码定义了两个constant常量i1和i3,
#两个Variable变量i2和i4
#两个Add操作tf.add_n()

def test_ops():
	#定义命名空间”input1"
	with tf.name_scope("input1"):
		i1 = tf.constant([1.0, 2.0, 3.0],name="input1")

	i2 = tf.Variable(tf.random_uniform([3]))
	i3 = tf.constant([1.0, 2.0, 4.0])
	i4 = tf.Variable(tf.random_uniform([3], name="input2"))

	output = tf.add_n([i1,i2],name = "add")
	output1 = tf.add_n([i3,i4])

	#将图结构写入log,以便tensorboard调用可视化
	writer = tf.summary.FileWriter("./log",tf.get_default_graph())
	writer.close()

test_ops()

可视化节点如下:
可视化节点
每一个 tf.XXX()函数都产生了一个节点,包括tf.random_uniform(),所以i2和i4可以看成是两个节点产生的一个张量。而i1由于定义了名字input,所以没有显示默认的Const节点名,第一个tf.add_n()函数定义了名字“add”所以直接显示名字,第二个add_n()就显示了默认的AddN。

从例子可以看出,我们需要从打印出的所有节点中,根据shape和变量名,推测出最终输出的节点,将推理出该节点的所有节点涉及到的变量固化(常量化)。例如mnist的最终输出肯定是一个维度为(,10)的张量。

猜你喜欢

转载自blog.csdn.net/Coderwhw/article/details/84785871
今日推荐