飞桨领航团AI创造营:模型部署,Hub Serving部署

创建必要的目录和文件

比如在 work 目录下创建 food_predict 文件夹,并在该目录下分别创建 module.py __init__.py ,其中 module.py 作为 Module 的入口,用来实现逻辑预测功能。

tree work/
在这里插入图片描述
module.py中的代码如下:

import paddle
import numpy as np
import argparse
import os
from PIL import Image
import base64
from io import BytesIO
import json
import paddle.nn.functional as F

import paddlehub as hub
from paddlehub.module.module import runnable, moduleinfo, serving

# 读取一张本地的样例图片,转变成模型输入的格式
def load_image(img_path):

    img = Image.open(img_path)
    if img.mode != 'RGB': 
        img = img.convert('RGB') 
    img = img.resize((224, 224), Image.ANTIALIAS)
    img = np.array(img).astype("float32")
    img = img.transpose(2,0,1)
    img = np.expand_dims(img, axis=0) # 增加一个维度
    img = img / 255.0           # 将图像数据归一化

    return img

#定义模型
class My_vgg(paddle.nn.Layer):
    def __init__(self, num_classes=11):
        super().__init__()
        self.num_classes = num_classes     
        net = []
        # block 1
        net.append(paddle.nn.Conv2D(3, 64, (3, 3),padding=1,  stride=1))
        net.append(paddle.nn.ReLU())
        # net.append(paddle.nn.Conv2D(64, 64, (3, 3),padding=1,  stride=1))
        # net.append(paddle.nn.ReLU())
        net.append(paddle.nn.MaxPool2D(kernel_size=2, stride=2))
        # block 2
        net.append(paddle.nn.Conv2D(64, 128, (3, 3), stride=1, padding=1))
        net.append(paddle.nn.ReLU())
        # net.append(paddle.nn.Conv2D(128, 128, (3, 3), stride=1, padding=1))
        # net.append(paddle.nn.ReLU())
        net.append(paddle.nn.MaxPool2D(kernel_size=2, stride=2))
        # block 3
        net.append(paddle.nn.Conv2D(128, 256, (3, 3), stride=1,padding=1))
        net.append(paddle.nn.ReLU())
        net.append(paddle.nn.Conv2D(256, 256, (3, 3),  stride=1,padding=1))
        net.append(paddle.nn.ReLU())
        # net.append(paddle.nn.Conv2D(256, 256, (3, 3),  stride=1,padding=1))
        # net.append(paddle.nn.ReLU())
        net.append(paddle.nn.MaxPool2D(kernel_size=2, stride=2))
        # block 4
        net.append(paddle.nn.Conv2D(256, 512, (3, 3), stride=1, padding=1))
        net.append(paddle.nn.ReLU())
        net.append(paddle.nn.Conv2D(512,  512,  (3, 3), stride=1, padding=1))
        net.append(paddle.nn.ReLU())
        # net.append(paddle.nn.Conv2D( 512,  512,  (3, 3), stride=1, padding=1))
        # net.append(paddle.nn.ReLU())
        net.append(paddle.nn.MaxPool2D(kernel_size=2, stride=2))
        # block 5
        net.append(paddle.nn.Conv2D( 512,  512,  (3, 3), stride=1, padding=1))
        net.append(paddle.nn.ReLU())
        net.append(paddle.nn.Conv2D( 512,  512,  (3, 3), stride=1, padding=1))
        net.append(paddle.nn.ReLU())
        # net.append(paddle.nn.Conv2D( 512,  512,  (3, 3), stride=1, padding=1))
        # net.append(paddle.nn.ReLU())
        #net.append(paddle.nn.MaxPool2D(kernel_size=2, stride=2))
        net.append(paddle.nn.AdaptiveAvgPool2D(output_size=1))
        # 组网
        #顺序容器。子Layer将按构造函数参数的顺序添加到此容器中。
        self.conv = paddle.nn.Sequential(*net)
        classifier = []
        # classifier.append(paddle.nn.Linear( 512*7*7,  4096))
        # classifier.append(paddle.nn.ReLU())
        # classifier.append(paddle.nn.Dropout(p=0.5))
        # classifier.append(paddle.nn.Linear( 4096,  4096))
        # classifier.append(paddle.nn.ReLU())
        # classifier.append(paddle.nn.Dropout(p=0.5))
        # classifier.append(paddle.nn.Linear( 4096,  self.num_classes))
        classifier.append(paddle.nn.Dropout(p=0.5))
        classifier.append(paddle.nn.Linear( 512,  self.num_classes))
        # 组网
        #顺序容器。子Layer将按构造函数参数的顺序添加到此容器中。
        self.classifier = paddle.nn.Sequential(*classifier)

    def forward(self, x):
        features = self.conv(x)
        features = paddle.reshape(features, [features.shape[0], -1])
        classify_result = self.classifier(features)
        return classify_result

@moduleinfo(
    name="food_predict",
    version="1.0.0",
    summary="This is a PaddleHub Module. Just for test.",
    author="hyq",
    author_email="",
    type="cv/my_food",
)

class FoodPredict:
    def __init__(self):
        self.parser = argparse.ArgumentParser(
            description="Run the food_predict module.",
            prog='hub run food_predict',
            usage='%(prog)s',
            add_help=True)
        self.parser.add_argument(
            '--input_img', type=str, default=None, help="img to predict")
        

    def food_predict(self, img_path):
        print('forward')
        model.eval()
        tensor_img = load_image(img_path)
        paddle.disable_static()
        result = model(paddle.to_tensor(tensor_img))

        return result.numpy().astype('int32')
    
    @runnable
    def runnable(self, argvs):
        print('runnable')
        args = self.parser.parse_args(argvs)

        return self.mnist_predict(args.input_img)

    @serving
    def serving(self, img_b64):
        print('serving')
        model.eval()
        img_b = base64.b64decode(img_b64)
        tensor_img = load_image(BytesIO(img_b))
        paddle.disable_static()
        result = model(paddle.to_tensor(tensor_img))

        # 应该返回JSON格式数据
        # 从numpy读出的数据格式是 numpy.int32
        # res = { 'res': int(np.argmax(result.numpy()[0])) }
        res = int(np.argmax(result.numpy()[0]))
        return json.dumps(res)

# 代码应该放到全局
model = My_vgg()
params_file_path = 'work/My_vgg.pdparams'
param_dict = paddle.load(params_file_path)
model.load_dict(param_dict)

my_mnist = FoodPredict()

编写 module.py 的第一步就是导入依赖库。这里有一些库不太常见,比如 BytesIO、argparse 和 paddlehub.module.module 里的内容。

  • BytesIO 用于把二进制图片转换成 Image.open 可以读取的格式
  • argparse 用来解析命令行参数
  • paddlehub 中的库用于装饰器,可以轻松添加命令行预测、服务部署功能

训练好的模型保存在 work/My_vgg.pdparams 当中。接下来我们编写一个 PaddleHub Module,并定义一个 新的类 。这个类用来实现Hub的预测功能,包括Python调用、命令行调用和服务部署。

如果希望Module可以支持命令行调用,则需要提供一个经过runnable修饰的接口,接口负责解析传入数据并进行预测,将结果返回。如果不需要提供命令行预测功能,则可以不实现该接口,PaddleHub在用命令行执行时,会自动发现该Module不支持命令行方式,并给出提示。

如果希望Module可以支持PaddleHub Serving部署预测服务,则需要提供一个经过serving修饰的接口,接口负责解析传入数据并进行预测,将结果返回。如果不需要提供PaddleHub Serving部署预测服务,则可以不需要加上serving修饰。

安装模型

module.py 中编写好代码后,就可以通过 hub install xxx 的方式来安装模型了。(终端运行)

hub install work/food_predict

安装成功:
在这里插入图片描述

预测测试:

import paddlehub as hub
my_food_predector = hub.Module(name="food_predict")
my_food_predector.food_predict("work/0.jpg")

在这里插入图片描述
在终端通过服务部署的话,部署和推理都需要在终端实现,因为外网没法访问到notebook。

部署方法

  1. 终端-1 运行命令 hub serving start -m mnist_predict 。如果它出现下面的提示说明部署成功

W0723 21:44:42.436631 3845 device_context.cc:404] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1

W0723 21:44:42.441895 3845 device_context.cc:422] device: 0, cuDNN Version: 7.6.

    * Serving Flask app "paddlehub.serving.app_compat" (lazy loading)

    * Environment: production

       WARNING: This is a development server. Do not use it in a production deployment.

       Use a production WSGI server instead.

    * Debug mode: off

    * Running on http://0.0.0.0:8866/ (Press CTRL+C to quit)

在这里插入图片描述

  1. 通过POST请求实现预测
import PIL.Image as Image
import matplotlib.pyplot as plt
img = Image.open("work/0.jpg")
plt.imshow(img)
import requests
import json
import cv2
import base64

def cv2_to_base64(image):
    data = cv2.imencode('.jpg', image)[1]
    return base64.b64encode(data.tobytes()).decode('utf-8')

# 发送HTTP请求
data = {'img_b64': cv2_to_base64(cv2.imread("work/0.jpg"))}
headers = {"Content-type": "application/json"}
url = "http://0.0.0.0:8866/predict/food_predict"
r = requests.post(url=url, headers=headers, data=json.dumps(data))

# 打印预测结果
print(r)
res = r.json()
print(res)

pre_index = res['results']

# 打印预测结果
print('预测结果:'+pre_index+"  "+ food_class[int(pre_index)])

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值