TensorFlow模型固化:从训练到部署的完整指南
本文详细介绍TensorFlow中模型固化的两种核心方法:使用freeze_graph工具以及通过convert_variables_to_constants将变量转换为常量。文章涵盖从生成PB和CKPT文件、构建固化命令、编写转换代码到最终测试加载模型的全流程,旨在帮助开发者解决移动端无法训练仅能推理的问题,实现参数与图结构的统一保存。
前言
TensorFlow移动端部署挑战
目前TensorFlow在移动端环境中不支持模型训练功能,仅能加载并运行预先训练好的模型。然而,常规的模型保存方式往往只单独保存参数文件或计算图结构,这导致在部署时难以同时获取完整的网络结构和权重。因此,如何将参数与计算图(Graph)整合保存为一个独立文件,成为模型部署的关键问题。
生成模型
模型固化的两种主要方法
实现模型固化主要有两种技术路径。第一种是利用freeze_graph工具,将tf.train.write_graph()生成的PB文件与tf.train.saver()生成的CKPT文件合并,重新生成一个包含完整信息的PB文件,但该方法目前官方已不推荐。第二种方法则是将训练中的变量直接转换为常量,并写入PB文件中。下文将对这两种方式,特别是较新的变量转常量方法进行详细介绍。
freeze_graph
使用freeze_graph工具固化
在使用freeze_graph方法时,首先需要分别生成PB文件和CKPT文件。具体操作代码如下:
with tf.Session() as sess:
saver = tf.train.Saver()
saver.save(session, "model.ckpt")
tf.train.write_graph(session.graph_def, '', 'graph.pb')
随后,利用TensorFlow源码中提供的freeze_graph工具执行固化操作:
首先,需要编译构建freeze_graph工具,此过程依赖bazel构建系统:
bazel build tensorflow/python/tools:freeze_graph
构建完成后,使用该工具执行固化命令(其中/path/to/需替换为实际文件路径):
bazel-bin/tensorflow/python/tools/freeze_graph --input_graph=/path/to/graph.pb --input_checkpoint=/path/to/model.ckpt --output_node_names=output/predict --output_graph=/path/to/frozen.pb convert_variables_to_constants
变量转常量保存法
在TensorFlow的传统保存模式中,模型通常保存为常量和计算图结构,而训练得到的权重实际上是变量。若将训练好的权重转换为常量后再保存为PB文件,虽然能实现权重的持久化,但过程较为繁琐,需要逐一调用eval方法获取值并赋值,再手动构建新的计算图并将W和b赋值给新图。
为了简化这一流程,Google提供了专门的函数供开发者快速转换并保存模型。
首先,需要在代码中引入该转换函数:
from tensorflow.python.framework.graph_util import convert_variables_to_constants
在需要保存模型的位置添加以下代码,将变量转换为常量:
output_graph_def = convert_variables_to_constants(sess, sess.graph_def, output_node_names=['output/predict'])
该函数的第一个参数为当前的Session对象,第二个参数为计算图定义,第三个参数为输出节点名称。例如,若我的输出层代码定义如下:
with tf.name_scope('output'):
w_out = tf.Variable(w_alpha * tf.random_normal([1024, MAX_CAPTCHA * CHAR_SET_LEN]))
tf.summary.histogram('output/weight', w_out)
b_out = tf.Variable(b_alpha * tf.random_normal([MAX_CAPTCHA * CHAR_SET_LEN]))
tf.summary.histogram('output/biases', b_out)
out = tf.add(tf.matmul(dense2, w_out), b_out)
out = tf.nn.softmax(out)
predict = tf.argmax(tf.reshape(out, [-1, 11, 36]), 2, name='predict')
由于在代码中使用了name_scope命名空间,因此在指定输出节点名称时,需要在predict前加上output/前缀。
生成文件
with tf.gfile.FastGFile('model/CTNModel.pb', mode='wb') as f: f.write(output_graph_def.SerializeToString())
上述代码中,第一个参数指定了输出文件的路径,第二个参数指定了文件操作模式,此处为以二进制写入方式保存文件。
运行上述代码后,系统会生成一个PB文件。接下来,我们需要测试该模型是否能够被正常读取并运行。
固化模型的加载与测试
测试模型
在Python环境中,首先需要加载生成的固化模型,具体代码如下:
with open('./model/rounded_graph.pb', 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
output = tf.import_graph_def(graph_def,
input_map={'inputs/X:0': newInput_X},
return_elements=['output/predict:0'])
由于原始网络的输入是一个placeholder,为了方便数据输入,我们需要先定义一个新的placeholder:
newInput_X = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT * IMAGE_WIDTH], name="X")
在调用模型时,将新的placeholder填入input_map参数中。
在调用网络进行推理时,直接使用这个新的placeholder接收数据,示例如下:
text_list = sesss.run(output, feed_dict={newInput_X: [captcha_image]})
最后,运行网络代码以验证模型是否正常工作。
以上关于TensorFlow模型固化的实现操作即为全部内容,希望能为读者提供参考,并欢迎大家支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













