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:搭网络,导出模型,运行模型的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。