如何⽤flask部署pytorch模型
随着深度学习越来越⽕,各种框架也层出不穷,如何训练⼀个深度学习模型变得越来越简单。然⽽在实际的⼯业场景中,我们往往更加关注如何部署⼀个已经训练好的模型。
在这⼀点上,tensorflow做得⾮常好,提供了来帮助我们⾮常⽅便地部署到⼯业场景下。众所周知,PyTorch的⼀个⾮常⼤的劣势就是没有办法很⽅便地部署模型,facebook和Microsoft⼀起搞了⼀个神经交换机,ONNX,可以将pytorch model转换到Caffe2 model,这样⼀是⿇烦,⼆是Caffe2⽬前还在测试,⼀堆bug,⽤的⼈也不多,三是还要多学⼀个框架Caffe2。所以这并不是⼀个⾮常好的选择。
⽬前的最新消息,Caffe2的源码已经并到pytorch中了,或许这是Facebook准备对付TensorFlow的⼤招,我们拭⽬以待。
本⽂受到keras的⼀篇的启发,会教⼤家如何使⽤flask来部署训练好的pytorch模型。⾸先声明⼀下,flask我也不太会⽤,因为看到了keras的⽂章,希望分享这种思路和想法,使⽤⼀种web框架实现深度学习模型的部署。
环境配置
eval是做什么的⾸先确保安装了pytorch,因为需要使⽤flask这个web框架,所以当然需要安装flask,⾮常简单,使⽤下
⾯的命令进⾏安装。
pip install flask
配置REST API
我们知道每次启动模型,load参数是⼀件⾮常费时间的事情,⽽每次做前向传播的时候模型其实都是⼀样的,所以我们最好的办法就是load ⼀次模型,然后做完前向传播之后仍然保留这个load好的模型,下⼀次有新的数据进来,我们就可以不⽤重新load模型,可以直接做前向传播得到结果,这样⽆疑节约了很多load模型的时间。所以我们需要建⽴⼀个类似于服务器的机制,将模型在服务器上load好,⽅便我们不断去调⽤模型做前向传播,那么怎么能够达到这个⽬的呢?我们可以使⽤flask来建⽴⼀个REST API来达到这⼀⽬的。
REST API 是什么呢?REST 是Representational State Transfer的缩写,这是⼀种架构风格,这⾥就不再过多描述,感兴趣的同学可以⾃⼰去google⼀下。
那么如何⽤flask启动这个服务呢?
载⼊模型
app = flask.Flask(__name__)
model = None
use_gpu = True
def load_model():
"""Load the pre-trained model, you can use your model just as easily.
"""
global model
model = resnet50(pretrained=True)
model.eval()
if use_gpu:
model.cuda()
⾸先我们需要使⽤上⾯的代码来载⼊模型,前⾯三句话的⾮常简单,第⼀句话表⽰调⽤flask初始化⼀个app,接着定义⼀个变量model来表⽰模型,use_gpu表⽰是否使⽤gpu。
接着定义 load_model 这个函数,在函数中将模型的参数load到前⾯定义的model中,这⾥使⽤了resnet50,记得使⽤ .eval将model转换成eval模式,如果要使⽤GPU,则加上 .cuda()
数据预处理
def prepare_image(image, target_size):
"""Do image preprocessing before prediction on any data.
:param image:      original image
:param target_size: target image size
:return:
preprocessed image
"""
de != 'RGB':
image = vert("RGB")
# Resize the input image nad preprocess it.
image = T.Resize(target_size)(image)
image = T.ToTensor()(image)
# Convert to Torch.Tensor and normalize.
image = T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])(image)
# Add batch_size axis.
image = image[None]
if use_gpu:
image = image.cuda()
return torch.autograd.Variable(image, volatile=True)
这⾥就是 pytorch 中标准的预处理流程,⾸先将图⽚resize到固定的⼤⼩,然后转换成 tensor,接着做标准化。启动REST API
定义好了模型和数据预处理,接下来我们就需要开始启动 flask 服务了。
@ute("/predict", methods=["POST"])
def predict():
# Initialize the data dictionary that will be returned from the view.
data = {"success": False}
# Ensure an image was properly uploaded to our endpoint.
hod == 'POST':
("image"):
# Read the image in PIL format
image = quest.files["image"].read()
image = Image.open(io.BytesIO(image))
# Preprocess the image and prepare it for classification.
image = prepare_image(image, target_size=(224, 224))
# Classify the input image and then initialize the list of predictions to return to the client.
preds = F.softmax(model(image), dim=1)
results = pk(preds.cpu().data, k=3, dim=1)
data['predictions'] = list()
# Loop over the results and add them to the list of returned predictions
for prob, label in zip(results[0][0], results[1][0]):
label_name = idx2label[label]
r = {"label": label_name, "probability": float(prob)}
data['predictions'].append(r)
# Indicate that the request was a success.
data["success"] = True
# Return the data dictionary as a JSON response.
return flask.jsonify(data)
⾸先定义请求⽅式为 POST,表⽰向服务器传输数据,接着定义⼀个 predict 函数来进⾏模型的前向传播。
在 prediect 中,⾸先建⽴⼀个字典 data 来存储请求状态,初始化为 false。接着通过 hod 来判断是否是 POST 请求,如果是的话,我们就通过 ("image") 来判断是否能够得到从远端传过来的数据,如果确实有数据传过来,我们就可以通过 quest.files["image"].read() 来得到从远⽅ POST 上来的数据。
为了传输的速度考虑,⼀般都会传⼆进制的⽂件,所以通过 io.BytesIO(image) 将⼆进制的⽂件读取出来,再通过 PIL.Image.open 来读取这个图⽚,这样我们就解码了⼀张从远端传过来的图⽚了。
然后下⾯的操作就很简单了,⾸先通过 prepare_image 将图⽚做预处理,接着传⼊到⽹络当中,这⾥
需要注意我们会使⽤ F.softmax 将模型的输出得分转换成⼀个概率分布,因为我们想要输出 top3 的结果和置信概率。最后我们就是将结果存到 data 中,返回成 json 的⽂件。
最后我们在 main 函数中调⽤
load_model()
app.run()
就可以启动 flask 服务了。通过上⾯的代码,我们知道了如何处理传过来的图⽚并输出预测的结果,那么我们如何传图⽚呢?这就是下⾯会讲的如何发起数据请求。
发送数据请求
发送数据请求并不难,⾸先我们需要知道上⾯定义好的 flask server 的地址,因为这就是我们在本地定义的,所以地址是
PyTorch_REST_API_URL = '127.0.0.1:5000/predict'
上⾯的 /predict 是因为我们前⾯使⽤了 @ute("/predict", methods=["POST"])。
接着我们定义⼀个函数来发送数据请求
def predict_result(image_path):
# Initialize image path
image = open(image_path, 'rb').read()
payload = {'image': image}
# Submit the request.
r = requests.post(PyTorch_REST_API_URL, files=payload).json()
# Ensure the request was successful.
if r['success']:
# Loop over the predictions and display them.
for (i, result) in enumerate(r['predictions']):
print('{}. {}: {:.4f}'.format(i + 1, result['label'],
result['probability']))
# Otherwise, the request failed.
else:
print('Request failed')
传⼊的参数 image_path 是图⽚路径,然后使⽤ requests.post(PyTorch_REST_API_URL, files=payload).json() 向服务器传⼊数据,同时得到服务器计算的结果,最后将结果 print 出来就可以了。
实验结果
我们使⽤ ResNet50 作为预训练的模型,传⼊下⾯这张图⽚作为测试
⾸先在⼀个终端中运⾏
python run_pytorch_server.py
来启动 flask server,等待⼀会⼉,可以得到下⾯的结果
然后我们重新打开⼀个新的终端,运⾏下⾯的代码
python simple_request.py --file='./dog.jpg'
这⾥的 dog.jpg 可以改成你⾃⼰的⽂件路径,然后我们可以得到下⾯的结果
讨论
最后我们实现了⼀个简单的深度学习服务器,当然这个模型是在本地建⽴的,我们当然可以将模型建⽴到远端的服务器上,本地向远端发送请求。当然这只是⼀个 toy model,我们可以基于这种思想设计更加复杂的结构。
本⽂内容参考⾃
本⽂的完整
欢迎关注原作者的知乎专栏
欢迎访问原作者的

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