手把手教你如何将DeepCTR中的模型用TF Serving部署在线服务。
【注意】
首先要将训练好的模型导出为SavedModel格式的模型。 deepctr 开源包用的是 tensorflow 框架,而实际用的是 keras。具体的导出的代码如下:
import tensorflow as tf
model_name = "DeepFM"
version = 1
tf.saved_model.save(
obj=model,
export_dir='./export_model/{}/{}'.format(model_name, version),
signatures=None)
【说明】
保存好的 SavedModel 格式的 Keras模型 的输出目录如下:
|--export_model
| |-- DeepFM
| |--1
| |--saved_model.pb
| |--variables
| |--variables.data-00000-of-00001
| |--variables.index
如果在指定目录下面生成一个pb文件,以及一个variables文件夹,就说明Keras模型导出成功了。
如果想要模型训练代码,可以参考github项目:https://github.com/MachineCYL/CTR
接下来是演示 DeepFM 模型部署到TF Serving的流程,具体如下:
Google官方已经做好了很多tf.Serving镜像,我们可以直接下载合适的版本。官方所有的Tensorflow Docker都在这个Docker Hub代码库中,下载时需要根据这个标记和变体来确定我们要下载哪一个版本的镜像。标记有四种
这里我选择tensorflow 2.0.0版本的镜像,指令如下:
docker pull tensorflow/serving:2.0.0
再看看拉取镜像是否成功:
# 查看现有镜像命令
docker images
# 输出
REPOSITORY TAG IMAGE ID CREATED SIZE
tensorflow/serving 2.0.0 048f8669e211 2 years ago 214MB
如果有出现上面的输出日志,就说明我们已经成功下载了一个tf.serving的Docker镜像。
如果只需要部署一个模型,会比较简单,可以用如下指令启动:
docker run -d \
-p 8500:8500 \
-p 8501:8501 \
--name "tf_serving" \
-v "/data/MachineCYL/CTR/export_model/DeepFM/:/models/model/" \
tensorflow/serving:2.0.0
【注意】
可以通过以下指令查看docker是否启动正常:
# 查看容器是否启动
docker ps
# 输出
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f1266508696e tensorflow/serving:2.0.0 "/usr/bin/tf_serving…" 6 days ago Up 2 days 0.0.0.0:8500-8501->8500-8501/tcp tf_serving
# 查看tf_serving服务的输出日志
docker logs -f tf_serving
# 如果没有报错,就说明模型部署成功了
另外,可以通过下面的指令,看docker中的端口是否有映射出来:
telnet 127.0.0.1 8500
# 输出
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
telnet 127.0.0.1 8501
# 输出
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
如果出现上面的输出内容,就说明8500和8501端口都有成功映射出来。
如果有多个模型需要同时部署,可以用配置文件来同时部署多个模型。相关的TF Serving的参数为model_config_file。
假设我有两个模型以及配置文件的路径如下:
|--export_model
| |-- config
| |-- models.config
| |-- test-DeepFM
| |--1
| |--saved_model.pb
| |--variables
| |-- all-DeepFM
| |--1
| |--saved_model.pb
| |--variables
这里的配置文件的存放路径如:./export_model/config/models.config
配置文件的内容如下:
model_config_list {
config {
name: 'test'
base_path: '/models/test-DeepFM/'
model_platform: 'tensorflow'
}
config {
name: 'all'
base_path: '/models/all-DeepFM/'
model_platform: 'tensorflow'
}
}
docker 启动指令如下:
docker run -d \
-p 8500:8500 \
-p 8501:8501 \
-v "/data/MachineCYL/CTR/export_model/:/models/" \
--name "tf_serving" \
tensorflow/serving:2.0.0 \
--model_config_file="/models/config/models.config"
【注意】
查看metadata的数据结构。可以通过这个输出的元数据的格式,我们可以构造请求字段与内容:
curl -X GET http://127.0.0.1:8501/v1/models/model/metadata
输出结果如下,可以看到请求的字段会比较多,如releaseYear、movieAvgRating等(不过为了方便展示,我这边就贴出一部分内容):
{
"model_spec":{
"name": "model",
"signature_name": "",
"version": "1"
}
,
"metadata": {"signature_def": {
"signature_def": {
"__saved_model_init_op": {
"inputs": {},
"outputs": {
"__saved_model_init_op": {
"dtype": "DT_INVALID",
"tensor_shape": {
"dim": [],
"unknown_rank": true
},
"name": "NoOp"
}
},
"method_name": ""
},
"serving_default": {
"inputs": {
"releaseYear": {
"dtype": "DT_INT32",
"tensor_shape": {
"dim": [
{
"size": "-1",
"name": ""
},
{
"size": "1",
"name": ""
}
],
"unknown_rank": false
},
"name": "serving_default_releaseYear:0"
},
"movieAvgRating": {
"dtype": "DT_FLOAT",
"tensor_shape": {
"dim": [
{
"size": "-1",
"name": ""
},
{
"size": "1",
"name": ""
}
],
"unknown_rank": false
},
"name": "serving_default_movieAvgRating:0"
},
... 下面内容省略 ...
根据metadata的内容,构造DeepFM模型的请求指令如下:
curl -d '{"inputs": {
"userId": [[1]],
"movieId": [[1]],
"releaseYear": [[1]],
"userAvgRating": [[1]],
"movieAvgRating": [[1]],
"userRatingCount": [[1]],
"userAvgReleaseYear": [[1]],
"userReleaseYearStddev": [[1]],
"userRatingStddev": [[1]],
"userRatedMovie1": [[1]],
"userRatedMovie2": [[1]],
"userRatedMovie3": [[1]],
"userRatedMovie4": [[1]],
"userRatedMovie5": [[1]],
"userGenre1": [[1]],
"userGenre2": [[1]],
"userGenre3": [[1]],
"userGenre4": [[1]],
"userGenre5": [[1]],
"movieGenre1": [[1]],
"movieGenre2": [[1]],
"movieGenre3": [[1]],
"movieRatingCount": [[1]],
"movieRatingStddev": [[1]]
}
}' -X POST http://127.0.0.1:8501/v1/models/model:predict
请求返回的结果如下:
{
"outputs": [
[
0.936053038
]
]
}
到此,整个模型部署到TF Serving的流程就全部完成了。如果有说得不对的地方或者遇到其他问题,欢迎在评论区讨论。