深度学习模型的服务化⾼并发部署--以Nginx+gunicorn+flask为例的dock。。。机器学习模型的服务化⾼并发部署--以Nginx+gunicorn+flask为例的docker部署⽅案
0.前⾔
机器学习模型训练完成后如何让其他⼈使⽤是⼀个⼯程化的问题,也许我们的⽤户是没有⼀点机器学习的基础,我们让他们独⾃完成模型的部署是⼗分困难的,这时候我们可以考虑为他们提供⼀种服务,他们并不需要关⼼怎么实现的,只需要简单的调⽤我们提供的服务接⼝便可以实现⾃⼰的需求,这便是模型服务化的部署过程。
机器学习模型部署是⼀个复杂的⼯程化问题,本部分为了简单化模型的部署过程,主要介绍简单的Nginx+gunicorn+flask的docker部署⽅案。
1. flask部署机器学习模型
flask介绍
Python 现阶段有三⼤主流Web框架,分别是Django、Tornado、Flask :
1. Django主要特点是⼤⽽全,集成了很多组件,例如: Models Admin Form 等等, 不管你⽤得到⽤不到,反正它全都有,属于全能型框架;
2. Torando主要特点是原⽣异步⾮阻塞,在IO密集型应⽤和多任务处理上占据绝对性的优势,属于专注型框架;
3. Flask主要特点⼩⽽轻,原⽣组件⼏乎为0, 三⽅提供的组件请参考Django ⾮常全⾯,属于短⼩精悍型框架。
在这⾥我们选⽤的是flask,这⾥主要介绍⼀下flask:
Flask 是⼀个 web 框架,也就是说 Flask 为你提供⼯具、库和技术来允许你构建⼀个 web 应⽤程序。这个 wdb 应⽤程序可以使⼀些 web 页⾯、博客、wiki、基于 web 的⽇历应⽤或商业⽹站。
Flask 属于微框架(micro-framework)这⼀类别,微架构通常是很⼩的不依赖于外部库的框架。这既有优点也有缺点,优点是框架很轻量,更新时依赖少,并且专注安全⽅⾯的 bug,缺点是你不得不⾃⼰做更多的⼯作,或通过添加插件增加⾃⼰的依赖列表,但是简单的部署服务也是可⾏的。
安装依赖
在模型flask部署的过程中,主要需要以下的python依赖包:
Flask
numpy
torch
torchvision
pillow
模型推理
这⾥以resnet模型为例进⾏介绍,可以使⽤这个训练好的模型权重(,如下式使⽤该模型进⾏推理的代码:
# -*- encoding: utf-8 -*-
import json
import torch
import numpy as np
from PIL import Image
from torchvision import transforms, models
data_trans = transforms.Compose([transforms.Resize([224,224]),                                transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],                                                    [0.229, 0.224, 0.225])])
def thresh_sort(x, thresh):
idx, = np.where(x > thresh)
return idx[np.argsort(x[idx])]
# 加载模型部分
def init_model():
resnet = snet50()
num_ftrs = resnet.fc.in_featuresnginx部署前端项目
resnet.fc = Linear(num_ftrs, 20)
resnet.load_state_dict(torch.load('model.pth',
map_location='cpu'))
for param in resnet.parameters():
resnet.eval()
return resnet
def make_prediction(path):
img = Image.open(path)
img_trans = data_trans(img).unsqueeze(0)
output = model(img_trans)
output = output[0].numpy().ravel()
labels = thresh_sort(output, 0.5)
if len(labels) == 0 :
label_array = "No Categories"
status = 0
else:
label_array = [cat_to_name[str(i)] for i in labels]
status = 1
return label_array, status
if __name__ == '__main__':
# 初始化,预加载完成模型
model = init_model()
# 类别信息
with open('class_name.json', 'r') as f:
cat_to_name = json.load(f)
path = "path/image"
label, status = make_prediction(path)
print(label, status)
在上述的代码中class_name.json的⽂件内容为:
{"0": "Aeroplane", "1": "Bicycle", "2": "Bird", "3": "Boat", "4": "Bottle", "5": "Bus", "6": "Car", "7": "Cat", "8": "Chair", "9": "Cow", "10": "Dining Table", "11": "Dog" , "12": "Horse", "13": "Motorbike", "14": "Person", "15": "Potted Plant", "16": "Sheep", "17": "Sofa", "18": "Train", "19": "TV Monitor"}
flask服务化部署模型
如上是常⽤的模型推理的代码,现将模型改为flask⽅式实现模型服务化,如下所⽰:
# -*- encoding: utf-8 -*-
'''
@File    :  deploy.py
@Time    :  2021/11/07 16:05:22
@Author  :  xx Xianqin
@Version :  1.0
@Contact :  @163
@License :  (C)Copyright 2017-2021
@Desc    :  None
'''
import json
import torch
import numpy as np
from PIL import Image
from torchvision import transforms, models
from flask import Flask, request
app = Flask(__name__)
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])])
def thresh_sort(x, thresh):
idx, = np.where(x > thresh)
return idx[np.argsort(x[idx])]
# 加载模型部分
def init_model():
resnet = snet50()
num_ftrs = resnet.fc.in_features
resnet.fc = Linear(num_ftrs, 20)
resnet.load_state_dict(torch.load('model.pth', map_location='cpu'))
for param in resnet.parameters():
resnet.eval()
return resnet
# 调⽤服务执⾏的内容
@ute('/model_predict', methods=['POST'])
def make_prediction():
hod == 'POST':
file_data = ('image')
img = Image.open(file_data)
img_trans = fig["data_trans"](img).unsqueeze(0)
output = fig["model"](img_trans)
output = output[0].numpy().ravel()
labels = thresh_sort(output, 0.5)
if len(labels) == 0 :
label_array = "No Categories"
status = 0
else:
label_array = [fig["name"][str(i)] for i in labels]
status = 1
return json.dumps({"result": label_array, "status":status})
if __name__ == '__main__':
# 初始化,预加载完成模型
# 类别信息
with open('class_name.json', 'r') as f:
# 启动模型的flask服务
app.run(host='0.0.0.0', port=10086, debug=True)
对⽐两个段代码可以看出,使⽤flask部署模型可以很简单的实现,仅需要修改较少的代码就可以,其他的模型参照类似的⽅式实现。启动flask服务
若上述项⽬的python⽂件名为model_flask.py,则启动flask服务执⾏如下命令:
python model_flask.py
在进⾏测试时,建议选⽤进⾏测试,如下图是针对本项⽬启动的flask进⾏测试的配置页⾯:
如上图,由于我们选⽤的是post⽅式,按照本图中的相关内容进⾏配置即可进⾏测试。
注意这⾥是 flask 代码启动了 app.run(), 尤其注意这是⽤ flask ⾃带的服务器启动 的app服务,后边会介绍这⼀问题。
2. gunicorn部署flask项⽬
flask直接⽣产环境部署的问题
在启动上述的flask项⽬时,会出现“WARNING: Do not use the development server in a production environment.”的警告提⽰;这是提⽰不要在⽣产环境直接部署flask服务。
Flask的web框架内部已经有了⼀个 WSGI server⽤来接受请求,但是因为其⾃带的server在处理并发等情况时不够优秀,并且存在响应慢等问题,出现这种情况也是由于flask框架的重点都放在了WSGI applicaiton的层⾯上,因为flask只是⼀个web框架,并不是⼀个web server的容器,flask⾃带的werkzeug只能⽤于开发环境,不能⽤于⽣产环境。此外如果直接通过nginx进⾏反向代理,也会经常⽆法响应请求。因此在⽣产环境下,flask ⾃带的服务器是⽆法满⾜性能要求的。
有两个可以在⽣产环境中使⽤、性能良好且⽀持Flask程序的服务器,分别是Gunicorn和uWSGI,但是这两个模块不提供对window的⽀持。因此本部分主要介绍gunicorn部署flask服务。
常见的客户请求模式下图所⽰,因此主要是介绍下图模式的部署⽅案实现:
gunicorn介绍
gunicorn是⼀个python Wsgi http server(其中WSGI为Web Server Gateway Interface,服务器⽹关接
⼝),只⽀持在Unix系统上运⾏,来源于Ruby的unicorn项⽬。Gunicorn使⽤prefork master-worker模型(在gunicorn中,master被称为arbiter),能够与各种wsgi web框架协作。
Gunicorn很容易配置,轻量级对cpu的消耗很少,且兼容性好,具有⾼性能,并⽀持了很多Worker模式,推荐的模式有以下⼏种:
同步Worker:也是默认模式Sync,也就是⼀次只处理⼀个请求。
异步Worker:通过Eventlet、Gevent实现的异步模式。
异步IO Worker:⽬前⽀持gthread和gaiohttp两种类型。
gunicorn依赖环境
gunicorn
supervisor
gunicorn部署flask
在安装好 gunicorn 后,需要⽤ gunicorn 启动 flask(不需要启动上⼀步的flask,不然会造成gunicorn
端⼝号冲突),使⽤了 gunicorn 启动flask服务,则这⼀过程中model_flask.py 就等同于⼀个库⽂件,被 gunicorn 调⽤。
启动flask(在终端输⼊如下命令)
gunicron -w 4 -k gevent -b 0.0.0.0:10086 model_flask:app

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。