保存 TF 服务的模型
为了服务模型,需要先保存它们。在本节中,我们将从官方 TensorFlow 文档中演示 MNIST 示例的略微修改版本,可从以下链接获得: https://www.tensorflow.org/serving/serving_basic 。
TensorFlow 团队建议使用 SavedModel 来保存和恢复在 TensorFlow 中构建和训练的模型。根据 TensorFlow 文档:
SavedModel 是一种语言中立的,可恢复的,密集的序列化格式。SavedModel 支持更高级别的系统和工具来生成,使用和转换 TensorFlow 模型。您可以按照 Jupyter 笔记本中的代码ch-11b_Saving_TF_Models_with_SavedModel_for_TF_Serving
。我们按照以下方式继续保存模型:
- 定义模型变量:
model_name = 'mnist'
model_version = '1'
model_dir = os.path.join(models_root,model_name,model_version)
- 像我们在第 4 章中所做的那样获取 MNIST 数据 - MLP 模型:
from tensorflow.examples.tutorials.mnist import input_data
dataset_home = os.path.join('.','mnist')
mnist = input_data.read_data_sets(dataset_home, one_hot=True)
x_train = mnist.train.images
x_test = mnist.test.images
y_train = mnist.train.labels
y_test = mnist.test.labels
pixel_size = 28
num_outputs = 10 # 0-9 digits
num_inputs = 784 # total pixels
- 定义将构建并返回模型的 MLP 函数:
def mlp(x, num_inputs, num_outputs,num_layers,num_neurons):
w=[]
b=[]
for i in range(num_layers):
w.append(tf.Variable(tf.random_normal(
[num_inputs if i==0 else num_neurons[i-1],
num_neurons[i]]),name="w_{0:04d}".format(i)
)
)
b.append(tf.Variable(tf.random_normal(
[num_neurons[i]]),
name="b_{0:04d}".format(i)
)
)
w.append(tf.Variable(tf.random_normal(
[num_neurons[num_layers-1] if num_layers > 0 \
else num_inputs, num_outputs]),name="w_out"))
b.append(tf.Variable(tf.random_normal([num_outputs]),
name="b_out"))
# x is input layer
layer = x
# add hidden layers
for i in range(num_layers):
layer = tf.nn.relu(tf.matmul(layer, w[i]) + b[i])
# add output layer
layer = tf.matmul(layer, w[num_layers]) + b[num_layers]
model = layer
probs = tf.nn.softmax(model)
return model,probs
上述mlp()
函数返回模型和概率。概率是应用于模型的 softmax 激活。
- 为图像输入和目标输出定义
x_p
和y_p
占位符:
# input images
serialized_tf_example = tf.placeholder(tf.string,
name='tf_example')
feature_configs = {'x': tf.FixedLenFeature(shape=[784],
dtype=tf.float32),}
tf_example = tf.parse_example(serialized_tf_example,
feature_configs)
# use tf.identity() to assign name
x_p = tf.identity(tf_example['x'], name='x_p')
# target output
y_p = tf.placeholder(dtype=tf.float32, name="y_p",
shape=[None, num_outputs])
- 创建模型,以及损失,优化器,准确性和训练函数:
num_layers = 2
num_neurons = []
for i in range(num_layers):
num_neurons.append(256)
learning_rate = 0.01
n_epochs = 50
batch_size = 100
n_batches = mnist.train.num_examples//batch_size
model,probs = mlp(x=x_p,
num_inputs=num_inputs,
num_outputs=num_outputs,
num_layers=num_layers,
num_neurons=num_neurons)
loss_op = tf.nn.softmax_cross_entropy_with_logits
loss = tf.reduce_mean(loss_op(logits=model, labels=y_p))
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(loss)
pred_check = tf.equal(tf.argmax(probs,1), tf.argmax(y_p,1))
accuracy_op = tf.reduce_mean(tf.cast(pred_check, tf.float32))
values, indices = tf.nn.top_k(probs, 10)
table = tf.contrib.lookup.index_to_string_table_from_tensor(
tf.constant([str(i) for i in range(10)]))
prediction_classes = table.lookup(tf.to_int64(indices))
- 在 TensorFlow 会话中,像以前一样训练模型,但使用构建器对象来保存模型:
from tf.saved_model.signature_constants import \
CLASSIFY_INPUTS
from tf.saved_model.signature_constants import \
CLASSIFY_OUTPUT_CLASSES
from tf.saved_model.signature_constants import \
CLASSIFY_OUTPUT_SCORES
from tf.saved_model.signature_constants import \
CLASSIFY_METHOD_NAME
from tf.saved_model.signature_constants import \
PREDICT_METHOD_NAME
from tf.saved_model.signature_constants import \
DEFAULT_SERVING_SIGNATURE_DEF_KEY
with tf.Session() as tfs:
tfs.run(tf.global_variables_initializer())
for epoch in range(n_epochs):
epoch_loss = 0.0
for batch in range(n_batches):
x_batch, y_batch = mnist.train.next_batch(batch_size)
feed_dict = {x_p: x_batch, y_p: y_batch}
_,batch_loss = tfs.run([train_op,loss],
feed_dict=feed_dict)
epoch_loss += batch_loss
average_loss = epoch_loss / n_batches
print("epoch: {0:04d} loss = {1:0.6f}" .format(epoch,average_loss))
feed_dict={x_p: x_test, y_p: y_test}
accuracy_score = tfs.run(accuracy_op, feed_dict=feed_dict)
print("accuracy={0:.8f}".format(accuracy_score))
# save the model
# definitions for saving the models builder = tf.saved_model.builder.SavedModelBuilder(model_dir)
# build signature_def_map
bti_op = tf.saved_model.utils.build_tensor_info
bsd_op = tf.saved_model.utils.build_signature_def
classification_inputs = bti_op(serialized_tf_example)
classification_outputs_classes = bti_op(prediction_classes)
classification_outputs_scores = bti_op(values)
classification_signature = (bsd_op(
inputs={CLASSIFY_INPUTS: classification_inputs},
outputs={CLASSIFY_OUTPUT_CLASSES:
classification_outputs_classes,
CLASSIFY_OUTPUT_SCORES:
classification_outputs_scores
},
method_name=CLASSIFY_METHOD_NAME))
tensor_info_x = bti_op(x_p)
tensor_info_y = bti_op(probs)
prediction_signature = (bsd_op(
inputs={'inputs': tensor_info_x},
outputs={'outputs': tensor_info_y},
method_name=PREDICT_METHOD_NAME))
legacy_init_op = tf.group(tf.tables_initializer(),
name='legacy_init_op')
builder.add_meta_graph_and_variables(
tfs, [tf.saved_model.tag_constants.SERVING],
signature_def_map={
'predict_images':prediction_signature,
DEFAULT_SERVING_SIGNATURE_DEF_KEY:
classification_signature,
},
legacy_init_op=legacy_init_op)
builder.save()
一旦看到以下输出,就会保存模型:
accuracy=0.92979997
INFO:tensorflow:No assets to save.
INFO:tensorflow:No assets to write.
INFO:tensorflow:SavedModel written to: b'/home/armando/models/mnist/1/saved_model.pb'
接下来,我们运行 ModelServer 并提供刚刚保存的模型。