《PaddlePaddle从入门到炼丹》十四——把预测模型部署在服务器

原文博客:Doi技术团队
链接地址:https://blog.doiduoyi.com/authors/1584446358138
初心:记录优秀的Doi技术团队学习经历

前言

如果读者使用过百度等的一些图像识别的接口,比如百度的细粒度图像识别接口,应该了解这个过程,省略其他的安全方面的考虑。这个接口大体的流程是,我们把图像上传到百度的网站上,然后服务器把这些图像转换成功矢量数据,最后就是拿这些数据传给深度学习的预测接口,比如是PaddlePaddle的预测接口,获取到预测结果,返回给客户端。这个只是简单的流程,真实的复杂性远远不止这些,但是我们只需要了解这些,然后去搭建属于我们的图像识别接口。

了解Flask

安装flask很简单,只要一条命令就可以了:

pip install flask

同时我们也使用到flask_cors,所以我们也要安装这个库

pip install flask_cors

创建一个paddle_server.py文件,然后编写一个简单的程序,了解一些如何使用这个Flask框架,首先导入所需的依赖库:

import os
import uuid
import numpy as np
import paddle.fluid as fluid
from PIL import Image
from flask import Flask, request
from flask_cors import CORS
from werkzeug.utils import secure_filename

编写一个hello_world()函数,使用@app.route('/')是指定访问的路径,该函数的返回值是一个字符串Welcome to PaddlePaddle

# 根路径,返回一个字符串
@app.route('/')
def hello_world():
    return 'Welcome to PaddlePaddle'

然后启动这个服务,如果是在Ubuntu的话,可能是需要在root下执行这个程序。

if __name__ == '__main__':
    # 启动服务,并指定端口号
    app.run(port=80)

然后浏览器访问http://127.0.0.1,返回之前写好的字符串:

Welcome to PaddlePaddle

要预测图片,上传图片是首要的,所以我们来学习如何使用Flask来上传图片。

  • secure_filename是为了能够正常获取到上传文件的文件名
  • /upload指定该函数的访问地址
  • methods=['POST']指定该路径只能使用POST方法访问
  • f = request.files['img']读取表单名称为img的文件
  • f.save(img_path)在指定路径保存该文件
# 上传文件
@app.route('/upload', methods=['POST'])
def upload_file():
    f = request.files['img']
    # 设置保存路径
    save_father_path = 'images'
    img_path = os.path.join(save_father_path, str(uuid.uuid1()) + secure_filename(f.filename).split('.')[-1])
    if not os.path.exists(save_father_path):
        os.makedirs(save_father_path)
    f.save(img_path)
    return 'success, save path: ' + img_path

然后再次启动服务

if __name__ == '__main__':
    # 启动服务,并指定端口号
    app.run(port=80)

然后再创建index.html文件,编写一个表单,指定表单提交的路径http://127.0.0.1/upload,并设置表单提交数据的格式multipart/form-data,而且支持表单提交方式是POST。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>预测图像</title>
</head>
<body>
<!--上传图片的表单-->
<form action="http://127.0.0.1/upload" enctype="multipart/form-data" method="post">
    选择上传的图像:<input type="file" name="img"><br>
    <input type="submit" value="上传">
</form>
</body>
</html>

打开我们编写的网页,选择需要上传的图片,点击上传。成功后返回类似以下的字符串,图片会保存在images目录下。

success, save path: images/65d7661a-3892-11e9-a7b7-f44d30185f58jpg

预测服务

paddle_server.py中添加一个图片文件预处理函数,这个函数的参数是根据已经上传并保存到服务器上图片的路径,根据处理对图片进行预处理,并返回处理否的图片数据:

# 预处理图片
def load_image(file):
    img = Image.open(file)
    # 统一图像大小
    img = img.resize((224, 224), Image.ANTIALIAS)
    # 转换成numpy值
    img = np.array(img).astype(np.float32)
    # 转换成CHW
    img = img.transpose((2, 0, 1))
    # 转换成BGR
    img = img[(2, 1, 0), :, :] / 255.0
    img = np.expand_dims(img, axis=0)
    return img

以下就是PaddlePaddle代码,这次我们使用《PaddlePaddle从入门到炼丹》十一——自定义图像数据集识别训练保存的预测代码。

# 创建执行器
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())

# 保存预测模型路径
save_path = 'infer_model/'
# 从模型中获取预测程序、输入数据名称列表、分类器
[infer_program, feeded_var_names, target_var] = fluid.io.load_inference_model(dirname=save_path, executor=exe)

以下就是这个后端服务项目的核心代码,该函数主要的功能是接受上传的图片,对图片进行预测,最后返回预测的结果。预测的方式和之前的图片预测的方式一样的。

@app.route('/infer', methods=['POST'])
def infer():
    f = request.files['img']

    # 保存图片
    save_father_path = 'images'
    img_path = os.path.join(save_father_path, str(uuid.uuid1()) + '.' + secure_filename(f.filename).split('.')[-1])
    if not os.path.exists(save_father_path):
        os.makedirs(save_father_path)
    f.save(img_path)

    # 开始预测图片
    img = load_image(img_path)
    result = exe.run(program=infer_program,
                     feed={feeded_var_names[0]: img},
                     fetch_list=target_var)

    # 显示图片并输出结果最大的label
    lab = np.argsort(result)[0][0][-1]

    names = ['苹果', '哈密瓜', '胡萝卜', '樱桃', '黄瓜', '西瓜']

    # 打印和返回预测结果
    r = '{"label":%d, "name":"%s", "possibility":%f}' % (lab, names[lab], result[0][0][lab])
    print(r)
    return r

启动服务

if __name__ == '__main__':
    # 启动服务,并指定端口号
    app.run(port=80)

index.html文件增加一个表单,这个是访问的地址就是上面服务中的预测函数的访问路径:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>预测图像</title>
</head>
<body>
<!--调用服务器预测接口的表单-->
<form action="http://127.0.0.1/infer" enctype="multipart/form-data" method="post">
    选择预测的图像:<input type="file" name="img"><br>
    <input type="submit" value="预测">
</form>
</body>
</html>

打开我们刚才编写的网页,选择需要预测的图片,点击预测。成功后返回类似以下的字符串,识别类别的标签,名字,还有该类别的概率。

{"label":1, "name":"哈密瓜", "possibility":0.982786}

GitHub地址:https://github.com/yeyupiaoling/LearnPaddle2/tree/master/note14


上一章:《PaddlePaddle从入门到炼丹》十三——自定义图像数生成
下一章:《PaddlePaddle从入门到炼丹》十五——把预测模型部署到Android手机上

参考资料

  1. https://blog.csdn.net/qq_33200967/article/details/79571511
  2. http://blog.csdn.net/u011054333/article/details/70151857

Google开发专家带你学 AI:入门到实战(Keras/Tensorflow)(附源码)

猜你喜欢

转载自blog.csdn.net/qq_33200967/article/details/87895601