(转)使用Tensorflow框架完美保存并实现调用训练好的模型(是模型不是参数哦、全网首篇)

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,[None28 * 28],name ='input_x')#输入图像shape:[?,784]
    ys = tf.placeholder(tf.float32,[None10],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的
    步幅=(22),#池化操作的步幅
    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,[ -  17 * 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(100print(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,如下图:


点击SOFTMAX后效果图

可以看到,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!大功告成!*

猜你喜欢

转载自blog.csdn.net/zyb418/article/details/88636609