本文介绍tensorflow Serving的原理和代码实现, 并提供简要的代码阅读指导.
如何serve一个模型
具体的步骤可以参考官方文档. 主要包括两个部分:
1. 导出模型
1. 启动服务
需要说明的是导出模型部分. 如果要把我们训练的模型拿来提供服务, 除了模型本身外, 还需要一些额外的信息, 比如模型的名称, 输入、输出对应的tensor信息, 方法名, 这些东西可以让TFS进行请求数据的格式检查以及目标模型查找. 这就是模型导出的作用. 直接拿一个checkpoint文件之类的是不能用的. TF使用SavedModel格式导出模型, 并提供了相关的工具(tf.saved_model.builder.SavedModelBuilder).
TFS的功能
- 支持多种模型服务策略,比如用最新版本/所有版本/指定版本, 以及动态策略更新、模型的增删等
- 自动加载/卸载模型
- Batching
- 多种平台支持(非TF平台)
TFS的架构
本节简要介绍各模块的主要功能, 后续章节介绍他们相互之间是如何协作的.
Servable
Servable是对模型的抽象, 但是任何能够提供算法或者数据查询服务的实体都可以是Servable, 不一定是机器学习模型.
在我们常用的场景下, Servable就是模型. 所以本文有时会混用模型和Servable.
ServerCore
整个服务系统的创建维护, 建立http rest server、grpc server和模型管理部分(AspiredVersionManager)之间的关系等.
AspiredVersionManager
模型管理的上层控制部分. 负责执行Source发出的模型管理指令. 一部分功能通过回调的方式由Source调用, 一部分由独立线程执行.
BasicManager
负责Servable的管理, 包括加载、卸载、状态查询、资源跟踪等, 对外提供如下接口操作Servable
- ManageServable
- LoadServable
- UnloadServable
- StopManagerServable
另外提供接口查询servableHandle(GetUntypedServableHandle), 也就是加载好的模型,供http rest或者grpc server调用进行推理.
所有受管理的servable都放在ManagedMap里面, 已经正常加载的servable同时也放在ServingMap里进行管理, 提供查询接口.
LoaderHarness
LoaderHarness对Loader提供状态跟踪, ServingMap和ManagedMap里面保存的都是LoaderHarness对象,只有通过LoaderHarness才能访问Loader的接口.
Loader
Loader对Servable的生命周期进行控制, 包括load/unload接口,资源预估接口等. 加载之后的Servable也存在Loader里面.
Adapter
Adapter是为了将Source(比如文件系统)转换成Loader而引入的抽象, 这样server core的实现和具体的平台解耦.
SourceRouter
Adapter是平台相关的, 每个平台一个Adapter, 但是Source是和Servable相关的, 这样在Adapter和Source之间存在一对多的关系, Router负责维护这些对应关系.
Source
Source是对Servable的来源(Source)的抽象, 比如模型文件是某个模型的Source. Source监控外部的资源(如文件系统), 发现新的模型版本, 并通知Target.
Target
Target是和Source对应的抽象概念, AspiredVersionManager、Router都是Target.
启动过程
TFS启动的全部参数可以参考main.c. 主要的参数包括服务端口(gprc和http rest端口)和模型配置. 其中模型配置可以直接指定(名称(model_name)、路径(model_base_path)等), 也可以使用文件指定(model_config_file,格式参考model_server_config.proto). 如果只启动单个模型的服务可以使用参数指定, 如果是多个模型必须使用文件. 其他的参数可以使用默认值.
启动过程主要是创建ServerCore对象, 并启动grpc server和http server.
ServerCore对象可以认为是系统中枢, 模型的维护, 服务请求的处理都是由他完成. ServerCore通过BasicManager管理所有的