tensorflow 20:搭网络,导出模型,运行模型的实例
概述
以前自己都利用别人搭好的工程,修改过来用,很少把模型搭建、导出模型、加载模型运行走一遍,搞了一遍才知道这个事情也不是那么简单的。
搭建模型和导出模型
参考《TensorFlow固化模型》,导出固化的模型有两种方式.
方式1:导出pb图结构和ckpt文件,然后用freeze_graph工具冻结生成一个pb(包含结构和参数)
在我的代码里测试了生成pb图结构和ckpt文件,但是没接着往下走,感觉有点麻烦。我用的是第二种方法。
注意我这里只在最后保存了一次ckpt,实际应该在训练中每隔一段时间就保存一次的。
saver=tf.train.Saver(max_to_keep=5)
#tf.train.write_graph(session.graph_def,FLAGS.model_dir,"nn_model.pbtxt",as_text=True)
withtf.Session()assess:
sess.run(tf.global_variables_initializer())
max_step=2000
foriinrange(max_step):
batch=mnist.train.next_batch(50)
ifi%100==0:
train_accuracy=accuracy.eval(feed_dict={
x:batch[0],y_:batch[1],keep_prob:1.0})
print('step%d,trainingaccuracy%g'%(i,train_accuracy))
train_step.run(feed_dict={x:batch[0],y_:batch[1],keep_prob:0.5})
print('testaccuracy%g'%accuracy.eval(feed_dict={
x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))
#保存pb和ckpt
print('savepbfileandckptfile')
tf.train.write_graph(sess.graph_def,graph_location,"graph.pb",as_text=False)
checkpoint_path=os.path.join(graph_location,"model.ckpt")
saver.save(sess,checkpoint_path,global_step=max_step)
方式2:convert_variables_to_constants
我实际使用的就是这种方法。
看名字也知道,就是把变量转化为常量保存,这样就可以愉快的加载使用了。
注意这里需要指明保存的输出节点,我的输出节点为'out/fc2'(我猜测会根据输出节点的依赖推断哪些部分是训练用到的,推理时用不到)。关于输出节点的名字是有规律的,其中out是一个name_scope名字,fc2是op节点的名字。
withtf.Session()assess:
sess.run(tf.global_variables_initializer())
max_step=2000
foriinrange(max_step):
batch=mnist.train.next_batch(50)
ifi%100==0:
train_accuracy=accuracy.eval(feed_dict={
x:batch[0],y_:batch[1],keep_prob:1.0})
print('step%d,trainingaccuracy%g'%(i,train_accuracy))
train_step.run(feed_dict={x:batch[0],y_:batch[1],keep_prob:0.5})
print('testaccuracy%g'%accuracy.eval(feed_dict={
x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))
print('savefrozenfile')
pb_path=os.path.join(graph_location,'frozen_graph.pb')
print('pb_path:{}'.format(pb_path))
#固化模型
output_graph_def=convert_variables_to_constants(sess,sess.graph_def,output_node_names=['out/fc2'])
withtf.gfile.FastGFile(pb_path,mode='wb')asf:
f.write(output_graph_def.SerializeToString())
上述代码会在训练后把训练好的计算图和参数保存到frozen_graph.pb文件。后续就可以用这个模型来测试图片了。
方式2的完整训练和保存模型代码
主要看main函数就行。另外注意deepnn函数最后节点的名字。
"""AdeepMNISTclassifierusingconvolutionallayers.
Seeextensivedocumentationat
https://www.tensorflow.org/get_started/mnist/pros
"""
#Disablelinterwarningstomaintainconsistencywithtutorial.
#pylint:disable=invalid-name
#pylint:disable=g-bad-import-order
from__future__importabsolute_import
from__future__importdivision
from__future__importprint_function
importargparse
importsys
importtempfile
importos
fromtensorflow.examples.tutorials.mnistimportinput_data
fromtensorflow.python.framework.graph_utilimportconvert_variables_to_constants
importtensorflowastf
FLAGS=None
defdeepnn(x):
"""deepnnbuildsthegraphforadeepnetforclassifyingdigits.
Args:
x:aninputtensorwiththedimensions(N_examples,784),where784isthe
numberofpixelsinastandardMNISTimage.
Returns:
Atuple(y,keep_prob).yisatensorofshape(N_examples,10),withvalues
equaltothelogitsofclassifyingthedigitintooneof10classes(the
digits0-9).keep_probisascalarplaceholderfortheprobabilityof
dropout.
"""
#Reshapetousewithinaconvolutionalneuralnet.
#Lastdimensionisfor"features"-thereisonlyonehere,sinceimagesare
#grayscale--itwouldbe3foranRGBimage,4forRGBA,etc.
withtf.name_scope('reshape'):
x_image=tf.reshape(x,[-1,28,28,1])
#Firstconvolutionallayer-mapsonegrayscaleimageto32featuremaps.
withtf.name_scope('conv1'):
W_conv1=weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
#Poolinglayer-downsamplesby2X.
withtf.name_scope('pool1'):
h_pool1=max_pool_2x2(h_conv1)
#Secondconvolutionallayer--maps32featuremapsto64.
withtf.name_scope('conv2'):
W_conv2=weight_variable([5,5,32,64])
b_conv2=bias_variable([64])
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)
#Secondpoolinglayer.
withtf.name_scope('pool2'):
h_pool2=max_pool_2x2(h_conv2)
#Fullyconnectedlayer1--after2roundofdownsampling,our28x28image
#isdownto7x7x64featuremaps--mapsthisto1024features.
withtf.name_scope('fc1'):
W_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)
#Dropout-controlsthecomplexityofthemodel,preventsco-adaptationof
#features.
withtf.name_scope('dropout'):
keep_prob=tf.placeholder(tf.float32,name='ratio')
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
#Mapthe1024featuresto10classes,oneforeachdigit
withtf.name_scope('out'):
W_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
y_conv=tf.add(tf.matmul(h_fc1_drop,W_fc2),b_fc2,name='fc2')
returny_conv,keep_prob
defconv2d(x,W):
"""conv2dreturnsa2dconvolutionlayerwithfullstride."""
returntf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')
defmax_pool_2x2(x):
"""max_pool_2x2downsamplesafeaturemapby2X."""
returntf.nn.max_pool(x,ksize=[1,2,2,1],
strides=[1,2,2,1],padding='SAME')
defweight_variable(shape):
"""weight_variablegeneratesaweightvariableofagivenshape."""
initial=tf.truncated_normal(shape,stddev=0.1)
returntf.Variable(initial)
defbias_variable(shape):
"""bias_variablegeneratesabiasvariableofagivenshape."""
initial=tf.constant(0.1,shape=shape)
returntf.Variable(initial)
defmain(_):
#Importdata
mnist=input_data.read_data_sets(FLAGS.data_dir)
#Createthemodel
withtf.name_scope('input'):
x=tf.placeholder(tf.float32,[None,784],name='x')
#Definelossandoptimizer
y_=tf.placeholder(tf.int64,[None])
#Buildthegraphforthedeepnet
y_conv,keep_prob=deepnn(x)
withtf.name_scope('loss'):
cross_entropy=tf.losses.sparse_softmax_cross_entropy(
labels=y_,logits=y_conv)
cross_entropy=tf.reduce_mean(cross_entropy)
withtf.name_scope('adam_optimizer'):
train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
withtf.name_scope('accuracy'):
correct_prediction=tf.equal(tf.argmax(y_conv,1),y_)
correct_prediction=tf.cast(correct_prediction,tf.float32)
accuracy=tf.reduce_mean(correct_prediction)
graph_location='./model'
print('Savinggraphto:%s'%graph_location)
train_writer=tf.summary.FileWriter(graph_location)
train_writer.add_graph(tf.get_default_graph())
saver=tf.train.Saver(max_to_keep=5)
#tf.train.write_graph(session.graph_def,FLAGS.model_dir,"nn_model.pbtxt",as_text=True)
withtf.Session()assess:
sess.run(tf.global_variables_initializer())
max_step=2000
foriinrange(max_step):
batch=mnist.train.next_batch(50)
ifi%100==0:
train_accuracy=accuracy.eval(feed_dict={
x:batch[0],y_:batch[1],keep_prob:1.0})
print('step%d,trainingaccuracy%g'%(i,train_accuracy))
train_step.run(feed_dict={x:batch[0],y_:batch[1],keep_prob:0.5})
print('testaccuracy%g'%accuracy.eval(feed_dict={
x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))
#savepbfileandckptfile
#print('savepbfileandckptfile')
#tf.train.write_graph(sess.graph_def,graph_location,"graph.pb",as_text=False)
#checkpoint_path=os.path.join(graph_location,"model.ckpt")
#saver.save(sess,checkpoint_path,global_step=max_step)
print('savefrozenfile')
pb_path=os.path.join(graph_location,'frozen_graph.pb')
print('pb_path:{}'.format(pb_path))
output_graph_def=convert_variables_to_constants(sess,sess.graph_def,output_node_names=['out/fc2'])
withtf.gfile.FastGFile(pb_path,mode='wb')asf:
f.write(output_graph_def.SerializeToString())
if__name__=='__main__':
parser=argparse.ArgumentParser()
parser.add_argument('--data_dir',type=str,
default='./data',
help='Directoryforstoringinputdata')
FLAGS,unparsed=parser.parse_known_args()
tf.app.run(main=main,argv=[sys.argv[0]]+unparsed)
加载模型进行推理
上一节已经训练并导出了frozen_graph.pb。
这一节把它运行起来。
加载模型
下方的代码用来加载模型。推理时计算图里共两个placeholder需要填充数据,一个是图片(这不废话吗),一个是drouout_ratio,drouout_ratio用一个常量作为输入,后续就只需要输入图片了。
graph_location='./model'
pb_path=os.path.join(graph_location,'frozen_graph.pb')
print('pb_path:{}'.format(pb_path))
newInput_X=tf.placeholder(tf.float32,[None,784],name="X")
drouout_ratio=tf.constant(1.,name="drouout")
withopen(pb_path,'rb')asf:
graph_def=tf.GraphDef()
graph_def.ParseFromString(f.read())
output=tf.import_graph_def(graph_def,
input_map={'input/x:0':newInput_X,'dropout/ratio:0':drouout_ratio},
return_elements=['out/fc2:0'])
input_map参数并不是必须的。如果不用input_map,可以在run之前用tf.get_default_graph().get_tensor_by_name获取tensor的句柄。但是我觉得这种方法不是很友好,我这里没用这种方法。
注意input_map里的tensor名字是和搭计算图时的name_scope和op名字有关的,而且后面要补一个‘:0'(这点我还没细究)。
同时要注意,newInput_X的形状是[None,784],第一维是batch大小,推理时和训练要一致。
(我用的是mnist图片,训练时每个bacth的形状是[batchsize,784],每个图片是28x28)
运行模型
我是一张张图片单独测试的,运行模型之前先把图片变为[1,784],以符合newInput_X的维数。
withtf.Session()assess:
file_list=os.listdir(test_image_dir)
#遍历文件
forfileinfile_list:
full_path=os.path.join(test_image_dir,file)
print('full_path:{}'.format(full_path))
#只要黑白的,大小控制在(28,28)
img=cv2.imread(full_path,cv2.IMREAD_GRAYSCALE)
res_img=cv2.resize(img,(28,28),interpolation=cv2.INTER_CUBIC)
#变成长784的一维数据
new_img=res_img.reshape((784))
#增加一个维度,变为[1,784]
image_np_expanded=np.expand_dims(new_img,axis=0)
image_np_expanded.astype('float32')#类型也要满足要求
print('image_np_expandedshape:{}'.format(image_np_expanded.shape))
#注意注意,我要调用模型了
result=sess.run(output,feed_dict={newInput_X:image_np_expanded})
#出来的结果去掉没用的维度
result=np.squeeze(result)
print('result:{}'.format(result))
#print('result:{}'.format(sess.run(output,feed_dict={newInput_X:image_np_expanded})))
#输出结果是长度为10(对应0-9)的一维数据,最大值的下标就是预测的数字
print('result:{}'.format((np.where(result==np.max(result)))[0][0]))
注意模型的输出是一个长度为10的一维数组,也就是计算图里全连接的输出。这里没有softmax,只要取最大值的下标即可得到结果。
输出结果:
full_path:./test_images/97_7.jpg image_np_expandedshape:(1,784) result:[-1340.37145996-283.724365231305.03320312437.6053772-413.69961548 -1218.08166504-1004.838073731953.3398437542.00457001-504.43829346] result:7 full_path:./test_images/98_6.jpg image_np_expandedshape:(1,784) result:[567.4041748-550.20904541623.83496094-1152.56884766-217.92695618 1033.452392582496.44750977-1139.23620605-5.64091825-615.28491211] result:6 full_path:./test_images/99_9.jpg image_np_expandedshape:(1,784) result:[-532.26409912-1429.47277832-368.58096313505.82876587358.42163086 -317.48199463-1108.68298341198.08752441289.122863773083.52539062] result:9
加载模型进行推理的完整代码
importsys
importos
importcv2
importnumpyasnp
importtensorflowastf
test_image_dir='./test_images/'
graph_location='./model'
pb_path=os.path.join(graph_location,'frozen_graph.pb')
print('pb_path:{}'.format(pb_path))
newInput_X=tf.placeholder(tf.float32,[None,784],name="X")
drouout_ratio=tf.constant(1.,name="drouout")
withopen(pb_path,'rb')asf:
graph_def=tf.GraphDef()
graph_def.ParseFromString(f.read())
#output=tf.import_graph_def(graph_def)
output=tf.import_graph_def(graph_def,
input_map={'input/x:0':newInput_X,'dropout/ratio:0':drouout_ratio},
return_elements=['out/fc2:0'])
withtf.Session()assess:
file_list=os.listdir(test_image_dir)
#遍历文件
forfileinfile_list:
full_path=os.path.join(test_image_dir,file)
print('full_path:{}'.format(full_path))
#只要黑白的,大小控制在(28,28)
img=cv2.imread(full_path,cv2.IMREAD_GRAYSCALE)
res_img=cv2.resize(img,(28,28),interpolation=cv2.INTER_CUBIC)
#变成长784的一维数据
new_img=res_img.reshape((784))
#增加一个维度,变为[1,784]
image_np_expanded=np.expand_dims(new_img,axis=0)
image_np_expanded.astype('float32')#类型也要满足要求
print('image_np_expandedshape:{}'.format(image_np_expanded.shape))
#注意注意,我要调用模型了
result=sess.run(output,feed_dict={newInput_X:image_np_expanded})
#出来的结果去掉没用的维度
result=np.squeeze(result)
print('result:{}'.format(result))
#print('result:{}'.format(sess.run(output,feed_dict={newInput_X:image_np_expanded})))
#输出结果是长度为10(对应0-9)的一维数据,最大值的下标就是预测的数字
print('result:{}'.format((np.where(result==np.max(result)))[0][0]))
以上这篇tensorflow20:搭网络,导出模型,运行模型的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。