使用keras_bert训练了模型,采用三种方式分别保存了模型结构、模型权重和完整模型,其中模型结构为json格式,模型权重和完整模型都是h5格式。tensorflow = 1.14,2.0以后貌似更加简单了
保存代码:
现在的需求是将h5模型转为SavedModel格式,并通过tf_serving部署。
1.1 加载h5模型
参考:
keras模型保存和加载_fu6543210的博客-CSDN博客blog.csdn.net注意:使用原生keras,tf.keras出现意想不到的错误。
1.1.1 json、load_weights方式
除了json以外,还有yaml方法。这种保存的都是模型结构,无法直接进行inference,需要加载权重。API:keras.model.model_from_config,model.load_weights()。没有使用这种方法,就不过多展开。
1.1.2 完整模型加载
API:model = keras.models.load_model(‘模型路径’)
坑1:使用上述代码直接加载模型的时候会出现:ValueError: Unknown layer: TokenEmbedding
原因:keras_bert这个包的需求
解决:
from keras_bert import get_custom_objects
model = keras.models.load_model('model.h5', custom_objects = get_custom_objects())
如果还是出现ValueError: Unknown layer: xxx,很可能是因为你用了tf.keras
1.2 转为SavedModel
1.2.1 创建bulider、回复计算图
参考:
https://zhuanlan.zhihu.com/p/81999483zhuanlan.zhihu.com上面的链接有一些api使用会出错,我的代码如下
import keras.backend as K
K.set_learning_phase(0)
export_path = '../models_pb'
builder = tf.saved_model.Builder(export_path)
signature_def_map = {
"predict": tf.saved_model.build_signature_def(
# 根据自己模型的要求
inputs = {"input0": tf.saved_model.build_tensor_info(model.input[0]),
"input1": tf.saved_model.build_tensor_info(model.input[1])},
outputs = {"output": tf.saved_model.build_tensor_info(model.output)},
method_name = tf.saved_model.signature_constants.PREDICT_METHOD_NAME
)}
builder.add_meta_graph_and_variables(keras.backend.get_session(), # 注意4
[tf.saved_model.tag_constants.SERVING],
signature_def_map=signature_def_map,
# 初始化操作,我的不需要,否则报错
# legacy_init_op=tf.group(tf.tables_initializer(), name='legacy_init_op')
)
builder.save()
一些注释及注意点(其实就是坑!!!):
补充知识(大佬请忽略)
1、查看模型输入输出,以及signature_name(后面用得到)
linux 命令:saved_model_cli 查看的话一般用show
注:红圈中的name就是tensor_name,可以使用get_tensor_by_name获取张量。这样方法就不会忘记加‘:0’,导致报错
2、回复计算图时可以使用tensorboard查看
我没用哈哈,直接copy别人的代码图把
这一段我是直接通过Docker部署,通过上一步保存的结果,我们可以得到如下模型
部署的话比较简单,也没出粗,不谈
TensorFlow与Docker服务 | TFXtensorflow.google.cn没想到在这里出现了坑,我们的post请求格式如下(一下都是一些别人的代码)
1、通过python request
2、或者通过下面的命令
举例:
import json
import numpy as np
import requests
from zh.model.utils import MNISTLoader
data_loader = MNISTLoader()
data = json.dumps({
"instances": data_loader.test_data[0:3].tolist()
})
headers = {"content-type": "application/json"}
json_response = requests.post(
'http://localhost:8501/v1/models/MLP:predict',
data=data, headers=headers)
predictions = np.array(json.loads(json_response.text)['predictions'])
print(np.argmax(predictions, axis=-1))
print(data_loader.test_label[0:10])
总则:“instances”的值是一个列表!列表!列表!,列表中每个元素是一个样本(更确切地说应该是一组完整的输入,即一个样本inputs),每个样本可能会有多个输入,比如我的模型中有input0、input1,每个样本用字典表示,每个输入是一个键值对。
坑1:json格式坑
TypeError: Object of type 'ndarray' is not JSON serializable
原因:样本需要的是list格式,我们给了ndarray
解决:np.ndarray.tolist()
坑2:post请求内容坑
{ "error": "Serving signature name: "serving_default" not found in signature def" }
原因:没有传入signature_name
解决:一般只用inference就是“predict”,也可以通过上面的linux 命令查看。
data = {
"signature_name": "predict",
"instances": [{
"input0": x1.tolist(),
"input1": x2.tolist()
}]
}
坑3:终于解决前两个坑了,然后输入格式也有坑。当然这个坑是因为自己的模型输入比较特别,是两个列表用'[]'括了起来,见总则
{ "error": "2 root error(s) found.n (0) Invalid argument: Expected multiples argument to be a vector of length 4 but got length 3nt [[{{node model_3_1/model_2/Encoder-1-MultiHeadSelfAttention/Tile_1}}]]nt [[dense_1_1/concat/_1681]]n (1) Invalid argument: Expected multiples argument to be a vector of length 4 but got length 3nt [[{{node model_3_1/model_2/Encoder-1-MultiHeadSelfAttention/Tile_1}}]]n0 successful operations.n0 derived errors ignored." }
原因:我的x1本身的shape是(2, 28),即2个样本。所以不能放在一个key中TensorFlow Serving 原因:我的x1本身的shape是(2, 28),即2个样本。所以不能放在一个key中
解决:每个样本生成一个dict
# 多个样本输入
assert len(x1) == len(x2)
inputs_dict = [{"input0": x1[i].tolist(),
"input1": x2[i].tolist()} for i in range(len(x1))]
打完收工,欢迎交流,一起踩坑!(踩了两天坑,写出来感觉也没啥,哈哈,心疼我的头发)
特别鸣谢:
载入h5模型:
Keras load_model raise ValueError: Unknown layer: TokenEmbedding问题blog.csdn.net 使用keras调用load_model时报错ValueError: Unknown Layer:LayerNameblog.csdn.net 用keras调用load_model时报错ValueError: Unknown Layer:LayerNameblog.csdn.net恢复计算图:
导出pb模型和导入pb模型_高円樹一-CSDN博客blog.csdn.net 读取pb文件恢复模型_kakak_的博客-CSDN博客blog.csdn.net 读取pb模型进行预测_macunshi的专栏-CSDN博客blog.csdn.net To load pb file : DecodeError: Error parsing messagestackoverflow.com格式转换:
https://zhuanlan.zhihu.com/p/81999483zhuanlan.zhihu.com查看模型结构:
tf_serving-模型训练、导出、部署(解析)_永远飞翔的鸟-CSDN博客blog.csdn.net 如何查看Tensorflow SavedModel格式模型的信息blog.csdn.nettensorboard查看:
查看.pb文件的结构_lishanlu136的博客-CSDN博客blog.csdn.net 【AI小疑问】如何加载PB文件并推理预测 - nowbug - 博客园www.cnblogs.com 如何查看Tensorflow SavedModel格式模型的信息blog.csdn.netpost请求:
TensorFlow Servingtf.wiki