在完成早期的模型训练管理和系统搭建之后,需要将训练的模型送上生产环境。基于app客户端的生产环境主要在于客户端上运行,因此只要客户端效率优化到位,那就Ok,但是如果说要在server端提供服务达到生产级别的性能要求,该怎么做呢?近期就碰到这个问题。因此模型服务搭建的任务就随之而来。我们选择的是google官方推出的tensorflow serving框架,这套框架是谷歌为了方便使用tf的用户,将训练的模型应用在生产环境上而开发的,实验之后的结果也确实令人满意,性能强悍!下面说一些过程中采坑实践出来的代码。

按照tf的文档,需要将我们的模型导出为固定的savedModel格式。我们是采用kares训练,导出的模型为h5格式。下面是导出的核心代码:

# start to convert
keras.backend.clear_session()
keras.backend.set_learning_phase(0)

# alpha is defined by model
model = StyleTransferNetwork.build((None, None), alpha=0.5)
model.load_weights(model_path, by_name=False)

tf.keras.backend.set_learning_phase(0)  # Ignore dropout at inference
signature = tf.saved_model.signature_def_utils.predict_signature_def(
inputs={'image': model.input}, outputs={'output_image': model.output})

builder = tf.saved_model.builder.SavedModelBuilder(output_dir)
builder.add_meta_graph_and_variables(
       sess=K.get_session(),
       tags=[tf.saved_model.tag_constants.SERVING],
       signature_def_map={
              tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
              signature
       })

builder.save()

tf serving功能很强大,支持同时加载多模型,支持版本切换,支持模型热更新。将转换后的模型保存在我们的自定义目录。配置好配置文件:

model_config_list {
  config {
    name: 'single_test_model_1'
    base_path: '/tmp/models/single_test_model_1'
    model_platform: "tensorflow" 
  }
}

通过docker 启动的同时制定上配置文件即可加载好模型:

sudo docker run --gpus all -t --rm -p 8500:8500 -p 8501:8501 -v "/tmp/models/:/tmp/models/" tensorflow/serving:latest-gpu --model_config_file=/tmp/models/models.config

这样一个基础的模型访问就搭建好了。这个基础上运行的服务其实性能已经很不错了,测试处理一张1000*1000的图片,如果用kares处理的话,耗时1.2s左右,而tf serving只需要100ms左右,而且tf这个是production级别的,训练所用的keras处理速度完全跟这个没法比。测试的环境是一台显卡为RTX2070,32G内存,CPU E3-1240 v6 @3.70GHz的机器。
虽然速度很快了,但是还能不能更快点呢?办法是有的,本人参考了两个方式:

  1. 优化savedModel
  2. 编译安装针对CPU平台优化了的tf。

方式1参考了文章Optimizing TensorFlow Models for Serving,虽然文章的作者说自己优化之后,速度提升了17%,但是本人实际测试之后发现几乎没有提升。
方式二参考了文章How we improved Tensorflow Serving performance by over 70%。在tf serving的github issues里面有很多关于这个的讨论,就是很多人都想知道这个到底能优化速度多少,讨论的结果大致是对于用cpu处理的机器来说,能有2-3倍的速度提升,但是对于使用GPU来处理的机器来说,没有提升,对于我们来说没什么意义,因此放弃。

深度学习相关的东西都很前沿,在一路爬坑的过程中很多时候连参考资料都没有,需要很大的决心去挖掘。本人的github放了一小部分在这个过程中实践的代码,有需要的可以浏览下。github 主页


补充

这两天琢磨了怎么优化速度,尝试了将模型精度降低,由之前的fp32降低到fp16。研究一番之后确实成功降低精度了,模型文件大小减少了45%左右。可是模型预测服务并没有提速,甚至出现了50%的降速,找了一番发现不是个例,在tensorflow官方库的issue里面看到别人发出的问题:FP16 slower than FP32。其中官方人员的回复,tf默认使用fp32运算,使用fp16会导致tf进行一次额外的转换操作,因此速度降低, 暂时没什么好的解决办法,o(╥﹏╥)o