利用gunicorn+flask将MXNet深度学习模型服务化
2020-04-17 本文已影响0人
zbharper
利用mxnet完成深度学习模型的训练后,需要考虑如何将推理模型应用到实际工程中。比较常见的方式是将模型部署为RESTful服务,有几个好处:
1)模型服务与业务解耦。模型服务的更改或升级不影响业务代码。
2)接口标准统一,客户端可跨平台调用,不需要依赖额外的库或环境,只需要支持http协议通信即可。
3)利用反向代理与负载均衡,模型服务可以方便的横向扩展,提高处理能力。
下面将一个图像分类器,采用flask、flask_restful模块编写服务代码,并使用gunicorn启动服务。并将服务纳入supervisor管理。
代码目录结构:
wdpredictor
|----__init__.py
|---- model/ # 模型文件目录
|---- wdplib/ # 预测模型代码
|---- __init__.py
|---- predictor.py # 分类器对象
|---- flask_resource.py # flask服务对象
|---- server.py # 服务启动入口
|---- run.sh
已知通过predictor.InitImagePredictor()可以构建一个图像分类器,resource.py 中编写flask服务对象,并编写server.py 程序入口
flask服务对象
flask_resource.py:
import sys
import logging
import traceback
import time
import json
import os
import base64
from flask import request
from flask_restful import Resource
class ImagePrediction(Resource):
def __init__(self, predictor):
self.predict_type = "image" # 模型类型:图像推理
self.predictor = predictor # 模型实例需要在资源外初始化,避免每次服务重新实例化浪费时间
def post(self):
logging.info("get post requests! from %s" %(request.url))
if not request.json:
logging.error("Invalid format of received body!")
return {}
else:
req = self.decode(request.json)
score, category = self.predictor.process(req.get("data")) #调用模型推理,得到预测结果
response = {
"id": request.json.get('id'),
"results": {
"score": score, # 评分
"category": category, # 类型
},
}
return response
def decode(self, meta):
meta['data'] = base64.b64decode(meta['data'])
return meta
服务入口
server.py
import sys
import logging
import traceback
import os
from flask import Flask
from flask_restful import Api
from wdpredictor import wdplib
from wdpredictor import flask_resource
app = Flask(__name__)
api = Api(app)
image_predictor = wdplib.InitImagePredictor() #初始化,加载mxnet,绑定模型
api.add_resource(flask_resource.ImageRemotePrediction, '/image', resource_class_args=(image_predictor, ))
if __name__ == '__main__':
print ("run from local")
app.run('0.0.0.0', debug=True)
启动gunicorn
编写run.sh,将环境配置与启动命令脚本化
#!/bin/bash
proj_base_path=$(cd $(dirname $BASH_SOURCE);pwd)
export WDPREDICTOR_BASE="$proj_base_path"
export PYTHONPATH="$proj_base_path:$PYTHONPATH"
export MXNET_CUDNN_AUTOTUNE_DEFAULT=0
gunicorn -w 2 -b 0.0.0.0:9000 wdpredictor.server:app
bash run.sh
supervisor管理
编写image_server.supervisor.conf
[program:image_server]
directory = /app/wdpredictor ; 程序的启动目录
command = bash run.sh ; 启动命令
autostart = true ; 在 supervisord 启动的时候也自动启动
startsecs = 5 ; 启动 5 秒后没有异常退出,就当作已经正常启动了
autorestart = true ; 程序异常退出后自动重启
startretries = 3 ; 启动失败自动重试次数,默认是 3
user = deepctrl
redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 50MB ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 20 ; stdout 日志文件备份数
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile = /tmp/image_server.log
killasgroup = true
stopasgroup = true
将image_server.supervisor.conf 拷贝到/etc/supervisor/conf.d目录中,重启supervisor服务
sudo supervisorctl reread
sudo supervisorctl reload