TF2模型保存加载
在TF2中保存加载模型,有多种方式。下面介绍下,最主要的几种方式,以及在模型中有Custom Layer时如何保存和加载模型。
由于Google官方在有Custom Layer层 的模型 保存/加载 介绍的非常不全面。这里统一详细介绍下。
.h5 保存/加载
据Google那边的消息,好像他们准备力推TF save_model形式。
一般情况
在利用tf.keras创建的model中直接运用model.save 保存模型的结构和权重为.h5文件。加载时用tf.keras.models.load进行加载。
保存
1 | model = tf.keras.models.Sequential([...]) |
加载
1 | tf.keras.models.load_model("model.h5") |
含有custom layer情况
自定义层:
在编写自定义层时
1 | class MyDense(tf.keras.layers.Layer): |
在custom layer中的 call() 上添加 @tf.function 可以将前向传播过程中不属于Graph的部分 转化为Graph。
报错一
如果在自定义层中没有重载get_config时,使用model.save() 将会提示如下错误。
NotImplementedError: Layers with arguments in __init__
must override get_config
.
如果自定义层中没有重载get_config, 在下文中使用tf.saved_model 中可以正常使用。
因此get_config 只对model.save() 起配置作用。
在custom layer中的 call() 上添加 @tf.function 可以将前向传播过程 转化为Graph。
报错二
若在custom layer的biuld 中创建初始矩阵时,name属性没写,会导致model.save报错
报错提示名字name already exists已存在
File “h5py/_objects.pyx”, line 54, in h5py._objects.with_phil.wrapper
File “h5py/_objects.pyx”, line 55, in h5py._objects.with_phil.wrapper
File “h5py/h5o.pyx”, line 202, in h5py.h5o.link
RuntimeError: Unable to create link (name already exists)
因此正确的写法是 对每一个 矩阵 加上name属性
1 | self.w1 = self.add_weight(name="w1") |
报错提示名字name already exists已存在
File “h5py/_objects.pyx”, line 54, in h5py._objects.with_phil.wrapper
File “h5py/_objects.pyx”, line 55, in h5py._objects.with_phil.wrapper
File “h5py/h5o.pyx”, line 202, in h5py.h5o.link
RuntimeError: Unable to create link (name already exists)
保存
在含有custom layer时 保存方式和一般情况相同直接,通过model.save(‘model.h5’)即可
加载
在含有custom layer时,加载保存的。.h5 模型文件时需要声明 自定义的层和自定义的损失函数。
在tf.keras.models.load_model中通custom_objects 来指定自定义层,自定义损失函数。
1 | model = tf.keras.models.load_model("./model0.h5",custom_objects={"MyDense":MyDense}) |
TF save_model保存/加载
通过tf.saved_model 保存注意的事情没有tf.keras.models 那么多。但在加载时比较复杂。
特别是,在有自定义层时,tf.save_model 方法在保存时 加载时更加方便,不需要额外的声明自定义层。但,需要在自定义层call 加上**@tf.fuction** 进行修饰。
保存
1 | tf.saved_model.save(model, "./test_model_out") |
或者直接通过keras model.save 进行保存。 若没有 .h5 后缀,则会自动保存为TF save_model形式。若有.h5 则会保存为.h5文件
1 | model.save("./test_model_out") |
加载
1 | load = tf.save_model.load("./test_model_out") |
[‘serving_default’]
1 | infer = loaded.signatures["serving_default"] |
{‘output’: TensorSpec(shape=(None, 1), dtype=tf.float32, name=’output’)}
然后可以直接通过infer进行预测。
输入数据为Tensor变量。
1 | test_input_ids = np.load('./data/test/input_ids.npy')[:10] |
1 | pre = infer(input_mask=test_input_mask,input_type_ids=test_input_type_ids,input_word_ids=test_input_word_ids) |
{‘output’: <tf.Tensor: id=22859, shape=(10, 1), dtype=float32, numpy=
array([[0.16463354],
[0.17504019],
[0.16223168],
[0.18234646],
[0.17594947],
[0.16918331],
[0.15553711],
[0.14790532],
[0.15857093],
[0.17600629]], dtype=float32)>}
通过上面的打印可以看见 layer name = output,可以通过该索引输出。
1 | print(pre['output'].numpy()) |
[[0.16463354]
[0.17504019]
[0.16223168]
[0.18234646]
[0.17594947]
[0.16918331]
[0.15553711]
[0.14790532]
[0.15857093]
[0.17600629]]
总结
在和Google大佬的交谈中发现TF团队准备力推TF save_model 的形式。
https://github.com/tensorflow/models/issues/7643
简单总结下:
模型保存
1 | model.save('file_path') |
模型加载
infer()中的数据 需要是Tensor 形式,可以用tf.convert_to_tensor 进行转换
1 | load = tf.save_model.load('file_path') |