summarize
In the past, I used to use other people to build a good project, modify it to use, rarely to build the model, export the model, load the model to run a walk through, messed up to realize that this thing is not so simple.
Building models and exporting models
Reference to theTensorFlow curing modelThere are two ways to export a solidified model.
Approach 1: Export the pb graph structure and ckpt file, then use the freeze_graph tool to freeze-generate a pb (with structure and parameters)
I tested generating the pb graph structure and ckpt file in my code, but didn't proceed to the next step, which felt a bit cumbersome. I used the second method.
Note that I only saved ckpt once at the end here, it should have actually been saved every so often during training.
saver = (max_to_keep=5) #.write_graph(session.graph_def, FLAGS.model_dir, "nn_model.pbtxt", as_text=True) with () as sess: (tf.global_variables_initializer()) max_step = 2000 for i in range(max_step): batch = .next_batch(50) if i % 100 == 0: train_accuracy = (feed_dict={ x: batch[0], y_: batch[1], keep_prob: 1.0}) print('step %d, training accuracy %g' % (i, train_accuracy)) train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5}) print('test accuracy %g' % (feed_dict={ x: , y_: , keep_prob: 1.0})) # Save pb and ckpt print('save pb file and ckpt file') .write_graph(sess.graph_def, graph_location, "",as_text=False) checkpoint_path = (graph_location, "") (sess, checkpoint_path, global_step=max_step)
Way 2: convert_variables_to_constants
This is the method I actually use.
As you can tell by the name, it's about converting variables to constants and saving them so they can be happily loaded and used.
Note that you need to specify the saved output node here, mine is 'out/fc2' (I guess it will be inferred which parts are used for training and not used for inference based on the dependencies of the output node). There is a pattern about the names of the output nodes, where out is a name_scope name and fc2 is the name of the op node.
with () as sess: (tf.global_variables_initializer()) max_step = 2000 for i in range(max_step): batch = .next_batch(50) if i % 100 == 0: train_accuracy = (feed_dict={ x: batch[0], y_: batch[1], keep_prob: 1.0}) print('step %d, training accuracy %g' % (i, train_accuracy)) train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5}) print('test accuracy %g' % (feed_dict={ x: , y_: , keep_prob: 1.0})) print('save frozen file') pb_path = (graph_location, 'frozen_graph.pb') print('pb_path:{}'.format(pb_path)) # Curing models output_graph_def = convert_variables_to_constants(sess, sess.graph_def, output_node_names=['out/fc2']) with (pb_path, mode='wb') as f: (output_graph_def.SerializeToString())
The above code will save the trained computed graph and parameters to the frozen_graph.pb file after training. Subsequently, you can use this model to test the images.
Full training and saving model code for mode 2
Just look mainly at the main function. Also note the name of the last node of the deepnn function.
"""A deep MNIST classifier using convolutional layers. See extensive documentation at /get_started/mnist/pros """ # Disable linter warnings to maintain consistency with tutorial. # pylint: disable=invalid-name # pylint: disable=g-bad-import-order from __future__ import absolute_import from __future__ import division from __future__ import print_function import argparse import sys import tempfile import os from import input_data from .graph_util import convert_variables_to_constants import tensorflow as tf FLAGS = None def deepnn(x): """deepnn builds the graph for a deep net for classifying digits. Args: x: an input tensor with the dimensions (N_examples, 784), where 784 is the number of pixels in a standard MNIST image. Returns: A tuple (y, keep_prob). y is a tensor of shape (N_examples, 10), with values equal to the logits of classifying the digit into one of 10 classes (the digits 0-9). keep_prob is a scalar placeholder for the probability of dropout. """ # Reshape to use within a convolutional neural net. # Last dimension is for "features" - there is only one here, since images are # grayscale -- it would be 3 for an RGB image, 4 for RGBA, etc. with tf.name_scope('reshape'): x_image = (x, [-1, 28, 28, 1]) # First convolutional layer - maps one grayscale image to 32 feature maps. with tf.name_scope('conv1'): W_conv1 = weight_variable([5, 5, 1, 32]) b_conv1 = bias_variable([32]) h_conv1 = (conv2d(x_image, W_conv1) + b_conv1) # Pooling layer - downsamples by 2X. with tf.name_scope('pool1'): h_pool1 = max_pool_2x2(h_conv1) # Second convolutional layer -- maps 32 feature maps to 64. with tf.name_scope('conv2'): W_conv2 = weight_variable([5, 5, 32, 64]) b_conv2 = bias_variable([64]) h_conv2 = (conv2d(h_pool1, W_conv2) + b_conv2) # Second pooling layer. with tf.name_scope('pool2'): h_pool2 = max_pool_2x2(h_conv2) # Fully connected layer 1 -- after 2 round of downsampling, our 28x28 image # is down to 7x7x64 feature maps -- maps this to 1024 features. with tf.name_scope('fc1'): W_fc1 = weight_variable([7 * 7 * 64, 1024]) b_fc1 = bias_variable([1024]) h_pool2_flat = (h_pool2, [-1, 7 * 7 * 64]) h_fc1 = ((h_pool2_flat, W_fc1) + b_fc1) # Dropout - controls the complexity of the model, prevents co-adaptation of # features. with tf.name_scope('dropout'): keep_prob = (tf.float32, name='ratio') h_fc1_drop = (h_fc1, keep_prob) # Map the 1024 features to 10 classes, one for each digit with tf.name_scope('out'): W_fc2 = weight_variable([1024, 10]) b_fc2 = bias_variable([10]) y_conv = ((h_fc1_drop, W_fc2), b_fc2, name='fc2') return y_conv, keep_prob def conv2d(x, W): """conv2d returns a 2d convolution layer with full stride.""" return .conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') def max_pool_2x2(x): """max_pool_2x2 downsamples a feature map by 2X.""" return .max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') def weight_variable(shape): """weight_variable generates a weight variable of a given shape.""" initial = tf.truncated_normal(shape, stddev=0.1) return (initial) def bias_variable(shape): """bias_variable generates a bias variable of a given shape.""" initial = (0.1, shape=shape) return (initial) def main(_): # Import data mnist = input_data.read_data_sets(FLAGS.data_dir) # Create the model with tf.name_scope('input'): x = (tf.float32, [None, 784], name='x') # Define loss and optimizer y_ = (tf.int64, [None]) # Build the graph for the deep net y_conv, keep_prob = deepnn(x) with tf.name_scope('loss'): cross_entropy = .sparse_softmax_cross_entropy( labels=y_, logits=y_conv) cross_entropy = tf.reduce_mean(cross_entropy) with tf.name_scope('adam_optimizer'): train_step = (1e-4).minimize(cross_entropy) with tf.name_scope('accuracy'): correct_prediction = ((y_conv, 1), y_) correct_prediction = (correct_prediction, tf.float32) accuracy = tf.reduce_mean(correct_prediction) graph_location = './model' print('Saving graph to: %s' % graph_location) train_writer = (graph_location) train_writer.add_graph(tf.get_default_graph()) saver = (max_to_keep=5) #.write_graph(session.graph_def, FLAGS.model_dir, "nn_model.pbtxt", as_text=True) with () as sess: (tf.global_variables_initializer()) max_step = 2000 for i in range(max_step): batch = .next_batch(50) if i % 100 == 0: train_accuracy = (feed_dict={ x: batch[0], y_: batch[1], keep_prob: 1.0}) print('step %d, training accuracy %g' % (i, train_accuracy)) train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5}) print('test accuracy %g' % (feed_dict={ x: , y_: , keep_prob: 1.0})) # save pb file and ckpt file #print('save pb file and ckpt file') #.write_graph(sess.graph_def, graph_location, "", as_text=False) #checkpoint_path = (graph_location, "") #(sess, checkpoint_path, global_step=max_step) print('save frozen file') pb_path = (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']) with (pb_path, mode='wb') as f: (output_graph_def.SerializeToString()) if __name__ == '__main__': parser = () parser.add_argument('--data_dir', type=str, default='./data', help='Directory for storing input data') FLAGS, unparsed = parser.parse_known_args() (main=main, argv=[[0]] + unparsed)
Loading the model for inference
The previous section has trained and exported frozen_graph.pb.
This section gets it running.
Loading Models
The code below is used to load the model. There are a total of two placeholders in the computation graph that need to be populated with data when reasoning, one for the picture (is that nonsense?) and one for the drouout_ratio, which uses a constant as input and subsequently just the picture.
graph_location = './model' pb_path = (graph_location, 'frozen_graph.pb') print('pb_path:{}'.format(pb_path)) newInput_X = (tf.float32, [None, 784], name="X") drouout_ratio = (1., name="drouout") with open(pb_path, 'rb') as f: graph_def = () graph_def.ParseFromString(()) output = tf.import_graph_def(graph_def, input_map={'input/x:0': newInput_X, 'dropout/ratio:0':drouout_ratio}, return_elements=['out/fc2:0'])
The input_map parameter is not required. If you don't use input_map, you can use tf.get_default_graph().get_tensor_by_name to get the handle of the tensor before run. But I don't think this method is very friendly, I don't use this method here.
Note that the tensor name in input_map is related to the name_scope and op name when building the computational map, and is complemented by a ':0' (which I haven't looked into in detail).
Also note that the shape of newInput_X is [None, 784], the first dimension is the batch size, and inference should be consistent with training.
(I used mnist images, the shape of each bacth during training is [batchsize, 784],each image is 28x28)
operational model
I tested this one image at a time, individually, by changing the image to [1, 784] before running the model to match the dimension of newInput_X.
with ( ) as sess: file_list = (test_image_dir) # Traversing the document for file in file_list: full_path = (test_image_dir, file) print('full_path:{}'.format(full_path)) # As long as it's black and white and sized to (28,28) # img = (full_path, cv2.IMREAD_GRAYSCALE ) res_img = (img,(28,28),interpolation=cv2.INTER_CUBIC) # Into one-dimensional data 784 long new_img = res_img.reshape((784)) # Add a dimension to [1, 784] image_np_expanded = np.expand_dims(new_img, axis=0) image_np_expanded.astype('float32') # The type must also meet the requirements print('image_np_expanded shape:{}'.format(image_np_expanded.shape)) # Watch out, watch out, I'm gonna call the model result = (output, feed_dict={newInput_X: image_np_expanded}) # The result that comes out removes useless dimensions # result = (result) print('result:{}'.format(result)) #print('result:{}'.format((output, feed_dict={newInput_X: image_np_expanded}))) # The output result is one-dimensional data of length 10 (corresponding to 0-9), and the subscript of the maximum value is the predicted number print('result:{}'.format( ((result==(result)))[0][0] ))
Note that the output of the model is a one-dimensional array of length 10, which is the output of computing the full connection in the graph. There is no softmax here, just take the subscript of the maximum value to get the result.
Output results:
full_path:./test_images/97_7.jpg image_np_expanded shape:(1, 784) result:[-1340.37145996 -283.72436523 1305.03320312 437.6053772 -413.69961548 -1218.08166504 -1004.83807373 1953.33984375 42.00457001 -504.43829346] result:7 full_path:./test_images/98_6.jpg image_np_expanded shape:(1, 784) result:[ 567.4041748 -550.20904541 623.83496094 -1152.56884766 -217.92695618 1033.45239258 2496.44750977 -1139.23620605 -5.64091825 -615.28491211] result:6 full_path:./test_images/99_9.jpg image_np_expanded shape:(1, 784) result:[ -532.26409912 -1429.47277832 -368.58096313 505.82876587 358.42163086 -317.48199463 -1108.6829834 1198.08752441 289.12286377 3083.52539062] result:9
Full code for loading the model for inference
import sys import os import cv2 import numpy as np import tensorflow as tf test_image_dir = './test_images/' graph_location = './model' pb_path = (graph_location, 'frozen_graph.pb') print('pb_path:{}'.format(pb_path)) newInput_X = (tf.float32, [None, 784], name="X") drouout_ratio = (1., name="drouout") with open(pb_path, 'rb') as f: graph_def = () graph_def.ParseFromString(()) #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']) with ( ) as sess: file_list = (test_image_dir) # Traversing the document for file in file_list: full_path = (test_image_dir, file) print('full_path:{}'.format(full_path)) # As long as it's black and white and sized to (28,28) # img = (full_path, cv2.IMREAD_GRAYSCALE ) res_img = (img,(28,28),interpolation=cv2.INTER_CUBIC) # Into one-dimensional data 784 long new_img = res_img.reshape((784)) # Add a dimension to [1, 784] image_np_expanded = np.expand_dims(new_img, axis=0) image_np_expanded.astype('float32') # The type must also meet the requirements print('image_np_expanded shape:{}'.format(image_np_expanded.shape)) # Watch out, watch out, I'm gonna call the model result = (output, feed_dict={newInput_X: image_np_expanded}) # The result that comes out removes useless dimensions # result = (result) print('result:{}'.format(result)) #print('result:{}'.format((output, feed_dict={newInput_X: image_np_expanded}))) # The output result is one-dimensional data of length 10 (corresponding to 0-9), and the subscript of the maximum value is the predicted number print('result:{}'.format( ((result==(result)))[0][0] ))
Above this tensorflow 20:networking,Export model,The example of running the model is all that I have to share with you,I hope this gives you a reference,And I hope you'll support me more。