https://blog.csdn.net/rainmaple20186/article/details/80464178
1.模型的保存
模型的保存通常有两种方法,一种是Tensorflow老版本中的t.trans.saver,另一种是新版本中的tf.saved_model.builder,博主使用的是后者,所以对于第一种方法也就一带而过。
1.1 tf.train.saver这种方法是使用较多的,但是呢,这种方法更多地是用来保存变量(变量)的,所以博主也就没有了解太多,下文po一段典型代码:
将tensorflow导入为tf
...
#在这里构建网络
...
#开始保存模型
与tf.Session()作为sess:
sess.run(tf.global_variables_initializer())#一定要先初始化整个流
#在这里训练网络
...
#保存参数
saver = tf.train.Saver()
saver.save(sess,PATH)#PATH就是要保存的路径
1.2 tf.saved_model.builder
下文只放出保存模型的关键代码,至于训练的过程,会在后续一并放出,整体分析。
将tensorflow导入为tf
...
#构建网络
...
用tf.Session()作为sess:
sess.run(tf.global_variables_initializer())#一定要先初始化整个流
#在这里训练网络
...
#保存参数
builder = tf.saved_model.builder.SaveModelBuilder(PATH)#PATH是保存路径
builder.add_meta_graph_and_variables(sess,[tf.saved_model.tag_constants.TRAINING])#保存整张网络及其变量,这种方法是可以保存多张网络的,在此不作介绍,可自行了解
builder.save()#完成保存
2.模型的调用
以上就简单介绍了两种保存模型的方法,接下来介绍一下读取模型的方法,只讲基于tf.saved_model.builder方法的读取模型了>划重点!完整调用并使用一个模型,分为加载网络和加载关键节点两个部分。幸运的是,使用tf.saved_model.builder保存和调用模型,这一切都变得非常简单~~~
2.1加载网络废话不多说,直接PO出代码:
将tensorflow导入为tf
用tf.Session(graph = tf.Graph())作为sess:
tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.TRAINING],PATH)#PATH还是路径
...
...
emmmm ......只要通过这么几句代码,就可以完成模型的调用了,但是呢,想要真正地使用这个网络,关键点在于加载网络中的关键节点,如:输入,输出
2.2加载张量(节点,张量,变量)神经元,可以是加载张量,也可以是加载节点,变量,代码也非常简单,在上节的基础上,加载张量的代码就只有一句话:
#以加载输入变量为例吧
input_x = sess.graph.get_tensor_by_name('input / input_x:0')#传入的参数会在后文讲到的
3.使用训练好的网络
当把输入的变量以及输出的变量都加载后,就可以使用网络了,假设输出变量为输出,输入变量为X和Y,那么使用这个网络的代码就可以表示如下:
sess.run(output,{x:_x,y:_y})#大括号的内容就是feed_dict了,使用方法类似于占位符
简要的思路
就结合我的代码来具体分析一下整个过程吧,先说一下简要的思路:
- 训练网络,并构建TensorBoard中的图形图,用于确定网络的关键节点,保存整个网络;
- 通过TensorBoard查找整个的数据流向,确定输入节点,输出节点;
以下是CNN网络的训练和保存部分:
将tensorflow导入为tf
from tensorflow.examples.tutorials.mnist import input_data
将numpy导入numpy
将matplotlib.pyplot导入为plt
#整个网络结构:卷积 - >池化 - >卷积 - >池化 - >全连接 - > dropout->全连接 - > SOFTMAX
#MINST数据
mnist = input_data.read_data_sets('MNIST_data',one_hot = True)
#
#define占位符
与tf.name_scope('input'):#输入采用了name_scope的形式,也可以不采用,直接从图上得到
xs = tf.placeholder(tf.float32,[None,28 * 28],name ='input_x')#输入图像shape:[?,784]
ys = tf.placeholder(tf.float32,[None,10],name ='input_y')#标签
keep_prob = tf.placeholder(tf.float32)
x_image = tf.reshape(xs,[-1,28,28,1])
#卷积图层1
conv1 = tf.layers.conv2d(
输入= x_image,
filters = 16,#输出空间的维数
kernel_size =(5,5),#二维卷积窗口的高度和宽度strides =(
1,1),#沿高度和宽度的卷积步长
padding ='same',#相同或有效
activation = tf .nn.relu
)#[ - 1,28,28,16] #max
池
pool1 = tf.layers.max_pooling2d(
inputs = conv1,
pool_size =(2,2),#pooling操作strides的
步幅=(2,2),#池化操作的步幅
padding ='same'#same或valid
)#[ - 1,14,14,16]#卷积
二层
conv2 = tf.layers.conv2d(pool1,32,5,(1,1),'same',activation = tf.nn.relu)#[ - 1,14,14,32] #max
轮询
POOL2 = tf.layers.max_pooling2d(CONV2,(2,2),(2,2),'相同')#[ - 1,7,7,32]
#平坦
扁平= tf.reshape(POOL2,[ - 1,7 * 7 * 32])
#完全连接的层1
dense1 = tf.layers.dense(
输入=平,#张量输入
单元= 256,则输出空间的维数#
活化= tf.nn.relu
)
#漏失
dense_drop = tf.layers.dropout(
inputs = dense1,
rate = keep_prob
)
#预测
#与tf.name_scope( '输出'):#可以通过name_scope来确定变量域,但是博主是直接根据图来看的
预测= tf。layers.dense(dense_drop,10)#输出结果
#损失
损失= tf.losses.softmax_cross_entropy(
onehot_labels = YS,
logits =预测
)
#火车
train_op = tf.train.AdamOptimizer(0.005).minimize(loss)
# 准确性
准确性= tf.metrics.accuracy(#创建两个局部变量
labels = tf.argmax(ys,1),
预测= tf.argmax(预测,1)
)[1]
成本= []#损失信息
sess = tf.Session()
“””
local_variables_initializer用于计算精度
“””
sess.run(tf.group(tf.global_variables_initializer(),tf.local_variables_initializer()))
writer = tf.summary.FileWriter('./ logs /',sess.graph)#构建TensorBoard的Graph,不作详细介绍
#训练
我在范围内(1001):
train_images,train_labels = mnist.train.next_batch(100)
_,loss_out = sess.run([train_op,loss],{xs:train_images,ys:train_labels,keep_prob:0.5})
如果我%50 == 0:#测试精确度
cost.append(loss_out)
test_imges,test_label = mnist.test.next_batch(100)
print(i,sess.run(准确性,{xs:test_imges,ys:test_label}))
print(sess.run(tf.argmax(prediction,1),{xs:mnist.train.images [0:10,:]}))
print(sess.run(tf.argmax(mnist.train.labels [0:10,:],1)))
#训练完成,保存训练好的网络
builder = tf.saved_model.builder.SavedModelBuilder('./ Models /')#保存前需要保证这个文件夹为空或者不存在
builder.add_meta_graph_and_variables(sess,[tf.saved_model.tag_constants.TRAINING])
builder.save()
若要调用这个训练好的网络,那么关键的节点有上述程序的XS和预测,XS是输入待识别的图像,而预测则是以one_hot的形式输出识别结果,因此这两个点是比较关键的。上文提到,可以通过
input _ x = sess.graph.get _ tensor _ by _ name('input / input_x:0')的方式加载关键的节点
对于这些行代码,括号的参数就是得到的节点在tensorflow的图中的名字,以input / input _ x:0为例,说明该变量是输入域(name _ scope或variable _ scope)的输入_ x变量,如果没有采用name_scope的方式,需要通过TensorBoard来自行查找变量名,因此这篇博客也详细介绍了这个过程下图是上传代码生成的TensorBoard的图图:
解释一下这张图,非常明确地反映了我们CNN网络的构成,由下至上,按照数据流动方向依次是数据输入(name_scope:输入),然后是第一个卷积层,接max_pooling池化,接第二个卷积层(在此名字叫做conv2d_1),接第二个max_pooling,之后经过重塑的过程进入全连接层,这是一个最普通的神经网络层,叫做密(看上文代码是可以看出来的),经过漏失进入第二个密,这个致密的输出就是整个网络的输出预测了,也就是我们想要的关键点。那么,我们可通过双击dense_1来查看这层的详细的数据流动,如下图:
再回顾一下代码,
准确性= tf.metrics.accuracy(#创建两个局部变量
labels = tf.argmax(ys,1),
预测= tf.argmax(预测,1)
)[1]
在计算精度时,预测作为了argmax的输入参数,而预测又是dense_1层输出的,所以dense_1和argmax之间的张量就是我们要的预测。这下我们就找到了输出的数据在哪了,那在图中的变量名是啥呢......
刚说到prediciton流动在dense_1的输出和argmax的输入之间,那么单击这两个模块看看呗,可以看到他们的输入和输出,我点击了argmax,如下图:
可以看到,INOUT有两个,第二个是一个维度,明显不是我们想要的输出,第一个是dense_1 / BiasAdd,那么就是这个了,它在图中的变量名就是* dense_1 / BiasAdd: 0 *,至于为什么会有:0呢,这或许是tensotflow本身的机制吧!
到这里为止,我们就得到了输出节点的名字,相同,可以得到输入节点的名字分别是输入/ input_x:0 和输入/ input_y:0。
接下来,PO出加载模型的代码:
python
将tensorflow导入为tf
from tensorflow.examples.tutorials.mnist import input_data
进口操作系统
将matplotlib.pyplot导入为plt
将numpy导入numpy
#读取数据
mnist = input_data.read_data_sets('MNIST_data',one_hot = True)
#加载模型
图,ax = plt.subplots(1,1)
用tf.Session(graph = tf.Graph())作为sess:
tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.TRAINING],'./Models')
#sess.run(tf.global_variables_initializer())#加了这句话就会导致图初始化
input_x = sess.graph.get_tensor_by_name('input / input_x:0')
input_y = sess.graph.get_tensor_by_name('input / input_y:0')
output = sess.graph.get_tensor_by_name('dense_1 / BiasAdd:0')
代码中注释了sess.run(tf.global_variables_初始化())这句话,因为这是一个大坑哦!!!!如果加了,模型的数据就会乱,也就是,无论如何数据都会是错的,一定要注意!!!到此为止,模型就加载出来了,如果要调用模型,假设已知的数据是x,想要得到结果,就可以通过> sess.run(output,{input_x: X})来得到了是不是很简单为了验证博主代码的正确性,采用训练集的前十张图像进行测试,并与理想的结果进行对比!
python
print(sess.run(tf.argmax(output,1),{input_x:mnist .train.images [0:10 ,:]]))
print(sess.run(tf.argmax(mnist.train.labels [0:10,:],1)))
爽快地给出代码运行的结果:
[7 3 4 6 1 8 1 0 9 8] [7 3 4 6 1 8 1 0 9 8]
网络输出和理想值一致!OK!大功告成!*