一些经验
我们在产品中已经使用TensorFlow Serving大概半年的时间,我们的使用体验是相当平稳。它具有良好的预测时间延迟。以下是我们的TensorFlow Serving实例一周内的预测时间(以秒为单位)的第95百分位数的图(约20毫秒)。
然而,在生产中使用TensorFlow Serving的过程中,我们也有一些经验教训可以跟大家分享。
1. 模型版本化
到目前为止,我们已经在产品中使用了几个不同版本的TensorFlow模型,每一个版本都有不同的特性,比如网络结构、训练数据等。正确处理模型的不同版本已经是一个重要的任务。这是因为传递到TensorFlow Serving的输入请求通常涉及到多个预处理步骤。这些预处理步骤在不同TensorFlow模型版本下是不同的。预处理步骤和模型版本的不匹配可能导致错误的预测。
a.明确说明你想要的版本
我们发现了一个简单但有用的防止错误预测的方法,也就是使用在model.proto定义中指定的版本属性,它是可选的(可以编译为model_pb2.py)。这样可以始终保证你的请求有效负载与预期的版本号匹配。
当你请求某个版本(比如从客户端请求版本5),如果TensorFlow Serving服务器不支持该特定版本,它将返回一个错误消息,提示找不到模型。
b.服务多个模型版本
TensorFlow Serving默认的是加载和提供模型的最新版本。
当我们在2016年9月首次应用TensorFlow Serving时,它不支持同时提供多个模型。这意味着在指定时间内它只有一个版本的模型。这对于我们的用例是不够的,因为我们希望服务多个版本的模型以支持不同神经网络架构的A / B测试。其中一个选择是在不同的主机或端口上运行多个TensorFlow Serving进程,以使每个进程提供不同的模型版本。这样的话就需要:
• 用户应用程序(gRPC客户端)包含切换逻辑,并且需要知道对于给定的版本需要调用哪个TensorFlow Serving实例。这增加了客户端的复杂度,所以不是首选。
• 一个可以将版本号映射到TensorFlow Serving不同实例的注册表。
更理想的解决方案是TensorFlow Serving可以支持多个版本的模型。
所以我决定使用一个“lab day”的时间来扩展TensorFlow Serving,使其可以服务多个版本的时间。在Zendesk,“lab day”就是我们可以每两周有一天的时间来研究我们感兴趣的东西,让它成为能够提高我们日常生产力的工具,或者一种我们希望学习的新技术。我已经有8年多没有使用C++代码了。但是,我对TensorFlow Serving代码库的可读性和整洁性印象深刻,这使其易于扩展。支持多个版本的增强功能已经提交,并且已经合并到主代码库中。TensorFlow Serving维护人员对补丁和功能增强的反馈非常迅速。从最新的主分支,你可以启动TensorFlow Serving,用model_version_policy中附加的flag来服务多个模型版本:
/work/serving/bazel-bin/tensorflow_serving/model_servers/ tensorflow_model_server — port=8999 — model_base_path=/work/awesome_model_directory — model_version_policy=ALL_VERSIONS
值得注意的要点是,服务多个模型版本,需要权衡的是更高的内存占用。所以上述的flag运行时,记住删除模型基本路径中的过时模型版本。
2. 活用压缩
当你部署一个新的模型版本的时候,建议在复制到model_base_path之前,首先将导出的TensorFlow模型文件压缩成单个的压缩文件。Tensorflow Serving教程中包含了导出训练好的Tensorflow模型的步骤。导出的检查点TensorFlow模型目录通常具有以下文件夹结构:
包含版本号(比如0000001)和以下文件的父目录:
• saved_model.pb:序列化模型,包括模型的图形定义,以及模型的元数据(比如签名)。
• variables:保存图形的序列化变量的文件。
压缩导出的模型:
tar -cvzf modelv1.tar.gz 0000001
为什么需要压缩?
• 压缩后转移和复制更快。
• 如果你将导出的模型文件夹直接复制到model_base_path中,复制过程可能需要一段时间,这可能导致导出的模型文件已复制,但相应的元文件尚未复制。如果TensorFlow Serving开始加载你的模型,并且无法检测到源文件,那么服务器将无法加载模型,并且会停止尝试再次加载该特定版本。
3. 模型大小很重要
我们使用的TensorFlow模型相当大,在300Mb到1.2Gb之间。我们注意到,在模型大小超过64Mb时,尝试提供模型时将出现错误。这是由于protobuf消息大小的硬编码64Mb限制,如这个TensorFlow Serving在Github上的问题所述。
最后,我们采用Github问题中描述的补丁来更改硬编码的常量值。(这对我们来说还是一个问题。如果你可以找到在不改变硬编码的情况下,允许服务大于64Mb的模型的替代方案,请联系我们。)
4. 避免将源移动到你自己的分支下
从实现时开始,我们一直从主分支构建TensorFlow Serving源,最新的版本分支(v0.4)在功能和错误修复方面落后于主分支。因此,如果你只通过检查主分支来创建源,一旦新的更改被合并到主分支,你的源也可能改变。为了确保人工制品的可重复构建,我们发现检查特定的提交修订很重要:
• TensorFlow Serving
• TensorFlow(TensorFlow Serving里的Git子模块)