13 | 模型服务:怎样把你的离线模型部署到线上?
在实验室的环境下,我们经常使用 Spark MLlib、TensorFlow、PyTorch 这些流行的机器学习库来训练模型,因为不用直接服务用户,所以往往得到一些离线的训练结果就觉得大功告成了。但在业界的生产环境中,模型需要在线上运行,实时地根据用户请求生成模型的预估值。这个把模型部署在线上环境,并实时进行模型推断(Inference)的过程就是模型服务。
业界的主流模型服务方法
由于各个公司技术栈的特殊性,采用不同的机器学习平台,模型服务的方法会截然不同,不仅如此,使用不同的模型结构和模型存储方式,也会让模型服务的方法产生区别。总的来说,那业界主流的模型服务方法有 4 种,分别是预存推荐结果或 Embedding 结果、预训练 Embedding+ 轻量级线上模型、PMML 模型以及 TensorFlow Serving。接下来,我们就详细讲讲这些方法的实现原理,通过对比它们的优缺点,相信你会找到最合适自己业务场景的方法。
预训练 Embedding+ 轻量级线上模型
事实上,直接预存 Embedding 的方法让模型表达能力受限这个问题的产生,主要是因为我们仅仅采用了“相似度计算”这样非常简单的方式去得到最终的推荐分数。既然如此,那我们能不能在线上实现一个比较复杂的操作,甚至是用神经网络来生成最终的预估值呢?当然是可行的,这就是业界很多公司采用的“预训练 Embedding+ 轻量级线上模型”的模型服务方式。详细一点来说,这样的服务方式指的是“用复杂深度学习网络离线训练生成 Embedding,存入内存数据库,再在线上实现逻辑回归或浅层神经网络等轻量级模型来拟合优化目标”。
利用 PMML 转换和部署模型
虽然 Embedding+ 轻量级模型的方法既实用又高效,但它还是把模型进行了割裂,让模型不完全是 End2End(端到端)训练 +End2End 部署这种最“完美”的方式。那有没有能够在离线训练完模型之后什么都不用做,直接部署模型的方式呢?当然是有的,也就是我接下来要讲的脱离于平台的通用模型部署方式,PMML。PMML 的全称是“预测模型标记语言”(Predictive Model Markup Language, PMML),它是一种通用的以 XML 的形式表示不同模型结构参数的标记语言。在模型上线的过程中,PMML 经常作为中间媒介连接离线训练平台和线上预测平台。这么说可能还比较抽象。接下来,我就以 Spark MLlib 模型的训练和上线过程为例,来和你详细解释一下,PMML 在整个机器学习模型训练及上线流程中扮演的角色。
事实上,JPMML 和 MLeap 也具备 Scikit-learn、TensorFlow 等简单模型的转换和上线能力。我把[JPMML](Java PMML API (github.com))和[MLeap](combust/mleap: MLeap: Deploy ML Pipelines to Production (github.com))的项目地址放在这里,感兴趣的同学可以进一步学习和实践。
实战搭建 TensorFlow Serving 模型服务
总的来说,搭建一个 TensorFlow Serving 的服务主要有 3 步,分别是安装 Docker,建立 TensorFlow Serving 服务,以及请求 TensorFlow Serving 获得预估结果。为了提高咱们的效率,我希望你能打开电脑跟着我的讲解和文稿里的指令代码,一块儿来安装。
1. 安装 Docker
TensorFlow Serving 最普遍、最便捷的服务方式就是使用 Docker 建立模型服务 API。为了方便你后面的学习,我再简单说说 Docker。Docker 是一个开源的应用容器引擎,你可以把它当作一个轻量级的虚拟机。它可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的操作系统,比如 Linux/Windows/Mac 的机器上。Docker 容器相互之间不会有任何接口,而且容器本身的开销极低,这就让 Docker 成为了非常灵活、安全、伸缩性极强的计算资源平台。因为 TensorFlow Serving 对外提供的是模型服务接口,所以使用 Docker 作为容器的好处主要有两点,一是可以非常方便的安装,二是在模型服务的压力变化时,可以灵活地增加或减少 Docker 容器的数量,做到弹性计算,弹性资源分配。Docker 的安装也非常简单,我们参考官网的教程,像安装一个普通软件一样下载安装就好。安装完 [Docker](Get Started | Docker) 后,你不仅可以通过图形界面打开并运行 Docker,而且可以通过命令行来进行 Docker 相关的操作。那怎么验证你是否安装成功了呢?只要你打开命令行输入 docker --version 命令,它能显示出类似“Docker version 19.03.13, build 4484c46d9d”这样的版本号,就说明你的 Docker 环境已经准备好了。
2. 建立 TensorFlow Serving 服务
首先,我们要利用 Docker 命令拉取 TensorFlow Serving 的镜像:
# 从docker仓库中下载tensorflow/serving镜像
docker pull tensorflow/serving
然后,我们再从 TenSorflow 的官方 GitHub 地址下载 TensorFlow Serving 相关的测试模型文件:
# 把tensorflow/serving的测试代码clone到本地
git clone https://github.com/tensorflow/serving
# 指定测试数据的地址
TESTDATA="$(pwd)/serving/tensorflow_serving/servables/tensorflow/testdata"
最后,我们在 Docker 中启动一个包含 TensorFlow Serving 的模型服务容器,并载入我们刚才下载的测试模型文件 half_plus_two:
# 启动TensorFlow Serving容器,在8501端口运行模型服务API
docker run -t --rm -p 8501:8501 \
-v "$TESTDATA/saved_model_half_plus_two_cpu:/models/half_plus_two" \
-e MODEL_NAME=half_plus_two \
tensorflow/serving &
3. 请求 TensorFlow Serving 获得预估结果
最后,我们再来验证一下是否能够通过 HTTP 请求从 TensorFlow Serving API 中获得模型的预估结果。我们可以通过 curl 命令来发送 HTTP POST 请求到 TensorFlow Serving 的地址,或者利用 Postman 等软件来组装 POST 请求进行验证。
# 请求模型服务API
curl -d '{"instances": [1.0, 2.0, 5.0]}' \
-X POST http://localhost:8501/v1/models/half_plus_two:predict
# 返回模型推断结果如下
# Returns => { "predictions": [2.5, 3.0, 4.5] }
如果对这整个过程还有疑问的话,你也可以参考 TensorFlow Serving 的官方教程。
小结
业界主流的模型服务方法有 4 种,分别是预存推荐结果或 Embeding 结果、预训练 Embeding+ 轻量级线上模型、利用 PMML 转换和部署模型以及 TensorFlow Serving。它们各有优缺点,为了方便你对比,我把它们的优缺点都列在了表格中,你可以看看。