Tensorflow——模型保存与部署(上)

470 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情


在之前的文章中,我们学习了循环神经网络的数据padding序列式问题文本生成LSTM长短期记忆网络subword文本分类

今天我们来介绍模型保存与部署。进行Keras模型转化为,签名函数转化为SavedModelSavedModel,签名函数、SavedModel和keras模型到具体函数转换方法的介绍


  • 1.1 模型保存与部署

    • 1.1.1 模型保存
    • 文件格式

      • Checkpoint与graphdef(tf1.0)
      • keras(hdf5),SavedModel(tf2.0)
    • 保存的是什么?

      • 参数
      • 参数+网络结构
    • 1.1.2 TFLite
      • TFLite Converter
        • 模型转化
      • TFLite Interpreter
        • 模型加载
        • 支持android与iOS设备
        • 支持多种语言
    • 1.1.3 TFLite - FlatBuffer
      • Google开源的跨平台数据库序列化库,可以很方便的给模型做序列化和反序列化,非常高效
      • 优点:
        • 直接读取序列化数据
        • 高效的内存使用和速度,无需占用额外内存
        • 灵活,数据前后向兼容,灵活控制数据结构
        • 使用少量的代码即可完成功能
        • 强数据类型,易于使用
    • 1.1.4 TFLite —— 量化
      • 参数从float变成8-bit整数
        • 模型准确率会有些许损失
        • 模型大小变为原理啊四分之一
      • 量化方法
        • 真是float值 = (int值 - 归零点) * 因子
    • 实战: keras-保存参数与保存模型+参数

      keras, 签名函数到SavedModel

      keras,SavedModel,签名函数到具体函数

      keras,SavedModel,具体函数到tflite

      Tflite 量化

      Tensorflow js部署模型

      Android部署模型

  • 2.1 保存模型构建加参数与保存参数

  • 使用ModelCheckpoint中的save_weights_only = False,:True是只保存参数,默认情况(False)是保存结构加参数
  • 2.2 Keras模型转化为SavedModel

    • 这个实战主要介绍使用saved_model将keras模型保存成SavedModel模型,介绍!saved_model_cli工具,在保存的模型中有一个最重要的信息就是签名信息,在签名信息中定义了输出和输出格式是什么,还介绍如何在程序中将模型导入尽力啊
    • 使用fashion_mnist数据集训练一个模型,详细请见之前的模型归一化处理,如果想保存成SaveModel格式只需要调用一个API即可

第一个参数是搭建好的模型,第二个参数是存储的路径

tf.saved_model.save(model, "./keras_saved_graph")

可以看到,保存好的文件夹由三个,其中对我们有用的就是saved_model.pb

A@BMO$JG)`8A1CHOLYSDUBD.png

对savemodel存储好之后,我们可以通过一个工具来查看——saved_model_cli,因为这是一个命令行工具,如果想在notebook里运行命令行工具的话,需要在前面加一个“!”

!saved_model_cli show --dir ./keras_saved_graph --all

我们还可以去指定不同的tag-set和 SignatureDefs

!saved_model_cli show --dir ./keras_saved_graph \
    --tag_set serve --signature_def serving_default

运行结果:

The given SavedModel SignatureDef contains the following input(s):
  inputs['flatten_input'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 28, 28)
      name: serving_default_flatten_input:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['dense_2'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 10)
      name: StatefulPartitionedCall:0
Method name is: tensorflow/serving/predict

这样的话,我们就会只打印出来serving_default的信息了, 而我们在SignatureDef中定义的信息的作用就在于我们如何把信息传给它,以及如何把信息取出来

我们还可以通过这个工具对SaveModel进行测试,--input_exprs之后可以输出python表达式

!saved_model_cli run --dir ./keras_saved_graph --tag_set serve \
    --signature_def serving_default \
    --input_exprs 'flatten_input=np.ones((2, 28, 28))'

运行结果:

[[0.07439692 0.12902586 0.06762592 0.04435977 0.1261992  0.01800182
  0.22577088 0.04594292 0.26419848 0.00447821]
 [0.07439692 0.12902586 0.06762592 0.04435977 0.1261992  0.01800182
  0.22577088 0.04594292 0.26419848 0.00447821]]

这里可以发现,输出的是两个概率分布,这两个概率分布应该是一样的,因为我们输入的两个样本都是一样的,每个分布都有十个值,意味着在十类中的预测,通过这个工具就可以检查我们的SavedModel是不是正常可以工作的。

除了工具之外,我们还可以使用程序对它进行测试

loaded_saved_model = tf.saved_model.load('./keras_saved_graph')
print(list(loaded_saved_model.signatures.keys()))

运行结果:

['serving_default']

通过这个签名可以获得一个inference

inference = loaded_saved_model.signatures['serving_default']
print(inference)
ConcreteFunction signature_wrapper(*, flatten_input)
  Args:
    flatten_input: float32 Tensor, shape=(None, 28, 28)
  Returns:
    {'dense_2': <1>}
      <1>: float32 Tensor, shape=(None, 10)

也可以查看outputs

print(inference.structured_outputs)

运行结果:

{'dense_2': TensorSpec(shape=(None, 10), dtype=tf.float32, name='dense_2')}

通过inference可以获得一个推理,输入是测试集中一个样本


results = inference(tf.constant(x_test_scaled[0:1])) print(results['dense_2'])

运行结果:

tf.Tensor(
[[3.94980771e-06 3.30364219e-06 3.71269880e-06 2.58380169e-06
  1.66972529e-06 1.78842749e-02 1.42412055e-05 5.17248968e-03
  2.42425900e-04 9.76671398e-01]], shape=(1, 10), dtype=float32)
  • 2.3 签名函数转化为SavedModel

将Signature保存成SavedModel

# 保存成SavedModel
to_export = tf.Module()
to_export.cube = cube
tf.saved_model.save(to_export, "./signature_to_saved_model")

和2.2一样,也可以使用saved_model_cli进行查看

!saved_model_cli show --dir ./signature_to_saved_model --all

使用程序对它进行测试

imported = tf.saved_model.load('./signature_to_saved_model')
imported.cube(tf.constant([2]))

运行结果:

<tf.Tensor: shape=(1,), dtype=int32, numpy=array([8], dtype=int32)>
  • 2.4 签名函数、SavedModel和keras模型到具体函数转换

把keras model转化为concrete_function

loaded_keras_model = keras.models.load_model(
    './graph_def_and_weights/fashion_mnist_model.h5')
loaded_keras_model(np.ones((1, 28, 28)))
# 把keras function用tf.function封装一遍
run_model = tf.function(lambda x : loaded_keras_model(x))
# get_concrete_function 来获得concrete_function,参数是定义的输入格式
keras_concrete_func = run_model.get_concrete_function(
    tf.TensorSpec(loaded_keras_model.inputs[0].shape,
                  loaded_keras_model.inputs[0].dtype))

测试一下是否可以正常运行:

keras_concrete_func(tf.constant(np.ones((1, 28, 28), dtype=np.float32)))

运行结果:

<tf.Tensor: shape=(1, 10), dtype=float32, numpy=
array([[0.12054981, 0.13891368, 0.06380311, 0.02520141, 0.03194021,
        0.01083281, 0.05653547, 0.145804  , 0.37682512, 0.02959438]],
      dtype=float32)>

在2.2中keras model到SavedModel转换的过程中,用到了一个inference的具体函数,这个函数是从SavedModel中的sugnatures得到的,这个inference就是一个concrete_function

在下一篇文章中我们将来介绍tflite保存与理解与量化

9JQ4ZCQY3M({Q$KEN%9BFQX.png