一、参考资料
简单粗暴 TensorFlow 2
简单粗暴 TensorFlow 2 | A Concise Handbook of TensorFlow 2
TensorFlow 中文文档
TensorFlow 英文文档
tensorflow2.0的函数签名与图结构
Tensorflow - AI研习社
二、相关介绍
1. tensorflow命名空间
scope 命名方法
tensorflow中的scope命名方法:name_scope, variavle_scope
2. tag标签
tag 是用来区别不同的 MetaGraphDef
,这是在加载模型所需要的参数。其默认值是 tag_constants.SERVING (“serve”)
。
from tensorflow.python.saved_model import tag_constants
tag_train = tag_constants.TRAINING
tag_serve = tag_constants.SERVING
tag_gpu = tag_constants.GPU
tag_tpu = tag_constants.TPU
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
tag_train = tf.saved_model.tag_constants.TRAINING
tag_serve = tf.saved_model.tag_constants.SERVING
tag_gpu = tf.saved_model.tag_constants.GPU
tag_tpu = tf.saved_model.tag_constants.TPU
3. Eager模式
Eager模式在TensorFlow v1.5首次引入,它是一种交互模式(命令行模式),每进行一步输入就可以得出一步结果,而无需构建计算图。
引入的Eager Execution模式后, TensorFlow就拥有了类似于Pytorch一样动态图模型能力, 我们可以不必再等到see.run(*)才能看到执行结果,可以方便在IDE随时调试代码,查看OPs执行结果。Eager模式极大的方便TensorFlow的使用和模型调试,增加了网络调试的灵活程度和TensorFlow对于初学者友好性。
TensorFlow 1.X 版本可以通过 tf.enable_eager_execution()
方法来启用动态图机制,TensorFlow 2.X默认启用Eager模式。
开启Eager模式
import tensorflow as tf
tf.enable_eager_execution
查看是否启用Eager模式
import tensorflow as tf
tf.executing_eagerly()
三、TensorFlow各种模型格式
tensorflow 模型导出总结
Tensorflow模型保存方式大汇总
辨析tensorflow模型存储形式:checkpoint、graphdef、savedmodel、frezzemodel
tensorflow模型保存(三)——tensorflow1.x版本的savedmodel格式的模型保存与加载
Tensorflow笔记:模型保存、加载和Fine-tune
0. 简介
针对不同场景,tensorflow 1.x 以及2.x 提供了多种不同的模型导出格式,例如有 checkpoint
,SavedModel
,Frozen GraphDef
,Keras model(HDF5)
以及用于移动端、嵌入式的 TFLite
。
Checkpoint
: 用于保存模型的权重,主要用于模型训练过程中参数的备份和模型训练热启动。GraphDef
:用于保存模型的Graph,不包含模型权重,加上checkpoint后就有模型上线的全部信息。SavedModel
:使用saved_model接口导出的模型文件,包含模型Graph和权限可直接用于上线,TensorFlow和Keras模型推荐使用这种模型格式。FrozenGraph
:使用freeze_graph.py
对checkpoint和GraphDef进行整合和优化,可以直接部署到Android、iOS等移动设备上。TFLite
:基于flatbuf对模型进行优化,可以直接部署到Android、iOS等移动设备上,使用接口和FrozenGraph有些差异。
模型导出主要包含了:参数以及网络结构的导出,不同的导出格式可能是分别导出,或者是整合成一个独立的文件。
- 权重参数和网络结构分开保存:checkpoint, SavedModel;
- 只保存权重:HDF5(可选);
- 权重参数和网络结构保存为一个文件:Frozen GraphDef,HDF5(可选)。
TensorFlow 1.x
在TensorFlow 1.x中,可以见下图,主要有三种主要的API,Keras
,Estimator
,以及 Legacy
即最初的session模型,其中 tf.Keras
主要保存为 HDF5
,Estimator
保存为SavedModel
,而 Lagacy
主要保存为 Checkpoint
,并且可以通过 freeze_graph
,将模型变量冻结,得到 Frozen GradhDef
文件。这三种格式的模型,都可以通过 TFLite Converter
导出为 .tflite
的模型文件,用于安卓/ios/嵌入式设备的serving。
TensorFlow 2.x
在TensorFlow 2.x中,推荐使用 SavedModel
进行模型的保存,所以keras默认导出格式是 SavedModel
,也可以通过显性使用 .h5
后缀,使得保存的模型格式为HDF5 。 此外其他low level API,都支持导出为SavedModel
格式,以及 Concrete Functions
。Concrete Function
是一个签名函数,有固定格式的输入和输出。
1. Frozen GraphDef
格式(pb格式)
请参考另一篇博客:TensorFlow之pb模型保存和加载
2. SavedModel格式
请参考另一篇博客:TensorFlow之SavedModel模型保存和加载
3. checkpoint格式
checkpint 的导出是网络结构和权重参数分开保存的。一个checkpoint 由两个部分以及三个文件组成,其中网络结构部分(meta文件),以及权重参数部分(参数名:index,参数值:data)。
checkpoint文件如下所示:
checkpoint # 列出该目录下,保存的所有的checkpoint列表,下面有具体的例子
events.out.tfevents.1583930869.prod-cloudserver-gpu169 # tensorboad可视化所需文件,可以直观展示模型的结构
# model.ckpt-13000表示前缀,代表第13000 global steps时的保存结果,当加载指定checkpoint时,只需要说明前缀即可
model.ckpt-13000.index # 表示参数名
model.ckpt-13000.data-00000-of-00001 # 表示参数值
model.ckpt-13000.meta # 表示网络结构
3.1 保存checkpoint模型
-
TensorFlow 1.x
# in tensorflow 1.x saver = tf.train.Saver() saver.save(sess=session, save_path=args.save_path)
-
estimator
# estimator """ 通过 RunConfig 配置多少时间或者多少个steps 保存一次模型,默认600s 保存一次。 具体参考 https://zhuanlan.zhihu.com/p/112062303 """ run_config = tf.estimator.RunConfig( model_dir=FLAGS.output_dir, # 模型保存路径 session_config=config, save_checkpoints_steps=FLAGS.save_checkpoints_steps, # 多少steps保存一次ckpt keep_checkpoint_max=1) estimator = tf.estimator.Estimator( model_fn=model_fn, config=run_config, params=None )
3.2 加载checkpoint模型
-
TensorFlow 1.x
# tf1.0 session = tf.Session() session.run(tf.global_variables_initializer()) saver = tf.train.Saver() saver.restore(sess=session, save_path=args.save_path) # 读取保存的模型
对于estimator 会自动
load output_dir
中的最新的ckpt,通常用model_file = tf.train.latest_checkpoint(FLAGS.output_dir)
获取最新的ckpt。 -
TensorFlow 2.x
import os import tensorflow.compat.v1 as tf tf.disable_v2_behavior() def restore_model_ckpt(ckpt_file_path="./ckpt"): sess = tf.Session() saver = tf.train.import_meta_graph(os.path.join(ckpt_file_path, "model.ckpt.meta")) saver.restore(sess, tf.train.latest_checkpoint(ckpt_file_path)) # 直接获取保存的变量 print(sess.run('b:0')) # 获取placeholder变量 input_x = sess.graph.get_tensor_by_name('x_input:0') input_y = sess.graph.get_tensor_by_name('y_input:0') # 获取需要进行计算的operator op = sess.graph.get_tensor_by_name('output:0') # 加入新的操作 add_on_op = tf.multiply(op, 2) ret = sess.run(add_on_op, feed_dict={input_x: 10, input_y: 3}) print(ret)
4. HDF5格式
4.1 保存/导出HDF5模型
-
导出整个模型
"""TensorFlow 1.x 默认是HDF5,但是2.0中,默认是SavedModel,所以需要显性地指定`.h5`后缀""" model.save('my_model.h5') # 或者 model.save('my_model.h5', save_format="h5")
-
导出模型weights
"""keras 1.0""" model.save_weights('my_model_weights.h5')
4.2 加载/导入HDF5模型
-
加载整个模型(无自定义部分)
"""keras 1.0""" from keras.models import load_model model = load_model(model_path)
"""keras 2.0""" new_model = tf.keras.models.load_model('my_model.h5')
-
加载整个模型(含自定义部分)
对于有自定义layers的或者实现的模型加载,需要增加dependencies 的映射字典,示例如下:dependencies = {'MyLayer': MyLayer(), 'auc': auc, 'log_loss': log_loss} model = load_model(model_path, custom_objects=dependencies, compile=False)
4.3 自定义Keras模型
使用继承 tf.keras.Model
类建立的 Keras 模型同样可以用 tf.saved_model.save(model, "xxx")
的方法导出,唯须注意 call 方法需要以 @tf.funtion 修饰,以转化为 SavedModel 支持的计算图。
5. TFLite格式
Frozen GraphDef
转 TFLite
tflite_convert --graph_def_file ./models/frozen_graph.pb \
--input_arrays 'x_input,y_input' \
--output_arrays 'output'\
--input_shapes 1:1 \
--output_file frozen_graph.tflite \
--enable_v1_converter \
--experimental_new_converter
参数解释
input_arrays
:输入节点的名称,多个用逗号隔开;output_arrays
:输出节点的名称,多个用逗号隔开;input_shapes
:输入节点的尺寸,多个用冒号隔开;
SavedModel 转 TFLite
//TODO
“Only support at least one signature key.” when trying converting a tensorflow model to tensorflow lite model
Tflite converter signature error
四、常用TensorFlow库
1. TensorBoard
使用 tensorboard --logdir PATH_TO_CHECKPOINT
: tensorboard 会调用 events.out.tfevents.*
文件,并生成tensorboard,如下图所示:
1.1 生成log日志
def print_pb_info_v1(pb_path):
"""
打印pb模型可视化结构
:param pb_path: pb模型文件的路径
:return:
"""
tf.reset_default_graph() # 重置计算图
output_graph_path = pb_path
with tf.Session() as sess:
tf.global_variables_initializer().run()
output_graph_def = tf.GraphDef()
# 获得默认的图
graph = tf.get_default_graph()
with open(output_graph_path, "rb") as f:
output_graph_def.ParseFromString(f.read())
_ = tf.import_graph_def(output_graph_def, name="")
# 在log_graph文件夹下生产日志文件,可以在tensorboard中可视化模型
_ = tf.summary.FileWriter('log_pb/', graph)
1.2 生成 TensorBoard
tensorboard --logdir="/PATH/TO/log_pb"
1.3 查看 TensorBoard
http://localhost:6006/
2. TensorFlow Serving
tf.saved_model.save模型导出、TensorFlowServing模型部署。。。
2.1 引言
当我们将模型训练完毕后,往往需要将模型在生产环境中部署。最常见的方式,是在服务器上提供一个 API,即客户机向服务器的某个 API 发送特定格式的请求,服务器收到请求数据后通过模型进行计算,并返回结果。如果仅仅是做一个 Demo,不考虑高并发和性能问题,其实配合 Flask 等 Python 下的 Web 框架就能非常轻松地实现服务器 API。
如果是在真的实际生产环境中部署,这样的方式就显得力不从心了。这时,TensorFlow 为我们提供了 TensorFlow Serving 这一组件,能够帮助我们在实际生产环境中灵活且高性能地部署机器学习模型。
2.2 简介
TensorFlow Serving是一种灵活的高性能服务系统,适用于机器学习模型,专为生产环境而设计。TensorFlow Serving可以进行算法和实验,同事保持相同的服务器架构和API。TensorFlow Serving提供与TensorFlow模型的开箱即用集成,可以轻松部署其他类型的模型和数据。
2.3 特点
TensorFlow Serving支持热更新模型,其典型的模型文件结构如下:
Saved_Model_files
├── 1 # 版本号为1的模型文件
│ ├── assets
│ ├── variables
│ ├── saved_model.pb
...
├── N # 版本号为N的模型文件
│ ├── assets
│ ├── variables
│ ├── saved_model.pb
从上面结构中,1-N的子文件夹代表不同版本号的模型。当指定 --model_base_path
时,只需要指定根目录的绝对路径(不是相对路径),例如 /PATH/TO/Saved_Model_files
,TensorFlow Serving会自动选择版本号最大的模型进行载入。
五、常用API
input_signature
@tf.function
可以给普通的python函数签名,再给它加上 input_signature
, 可以让这个python函数变成一个可以保存的tensorflow 图结构(SavedModel)。
input_signature
可以限定函数的输入类型,以防止调用函数时调错。比如,定义函数的输入类型为 tf.int32
,调用时的输入类型为 float32
,导致函数调用失败。
@tf.function(input_signature=[tf.TensorSpec([None], tf.int32, name='x')])
def cube(z): #实现输入的立方
return tf.pow(z, 3)
try:
print(cube(tf.constant([1., 2., 3.])))
except ValueError as ex:
print(ex)
# 输出
Python inputs incompatible with input_signature:
inputs: (
tf.Tensor([1. 2. 3.], shape=(3,), dtype=float32))
input_signature: (
TensorSpec(shape=(None,), dtype=tf.int32, name='x'))
正确调用方式:
print(cube(tf.constant([1, 2, 3])))
# 输出
tf.Tensor([ 1 8 27], shape=(3,), dtype=int32)
get_concrete_function()
调用 get_concrete_function
函数后,输出的是一个 ConcreteFunction
对象。
# @tf.function py func -> tf graph
# get_concrete_function -> add input signature -> SavedModel
cube_func_int32 = cube.get_concrete_function(
tf.TensorSpec([None], tf.int32)) #tensorflow的类型
print(cube_func_int32)
# 输出
ConcreteFunction cube(z)
Args:
z: int32 Tensor, shape=(None,)
Returns:
int32 Tensor, shape=(None,)