基于Paddle Serving的手写数字图像识别模型服务化部署

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文章主要讲述Windows系统下的paddle模型服务化部署,目前Win系统只支持用web service的方式搭建local predictor预测服务,linux系统的RPC服务部署请参考https://aistudio.baidu.com/aistudio/projectdetail/545527

一、可部署模型准备

安装百度飞桨框架:

python -m pip install paddlepaddle==2.3.0 -i https://mirror.baidu.com/pypi/simple

安装服务端与客户端:

pip install paddle-serving-client -i https://mirror.baidu.com/pypi/simple
pip install paddle-serving-server -i https://mirror.baidu.com/pypi/simple
pip install paddle-serving-app -i https://mirror.baidu.com/pypi/simple

请参考上述连接文章训练好模型并将模型文件转化为可部署的server端与client端文件:
在这里插入图片描述
注意其中的conf.prototxt文件中feed与fetch分别为模型的输入与输出,需要打开查看,与下文服务端代码中的feed与fetch对应填上:
在这里插入图片描述

二、服务端框架

服务端基于paddle serving的web框架,具体设计原理可查阅官方文档:
https://github.com/PaddlePaddle/Serving/blob/develop/doc/Windows_Tutorial_CN.md
服务端代码如下(示例):

from PIL import Image
from paddle_serving_client import Client
from paddle_serving_app.reader import OCRReader
import cv2
import sys
import numpy as np
# import os
# from paddle_serving_client import Client
# from paddle_serving_app.reader import Sequential, URL2Image, ResizeByFactor
# from paddle_serving_app.reader import Div, Normalize, Transpose
# from paddle_serving_app.reader import DBPostProcess, FilterBoxes, GetRotateCropImage, SortedBoxes
# from paddle_serving_client.pipeline.channel import ChannelData
if sys.argv[1] == 'gpu':
    from paddle_serving_server.web_service import WebService
elif sys.argv[1] == 'cpu':
    print(3)
    from paddle_serving_server.web_service import WebService
    print(1)
from paddle_serving_app.local_predict import LocalPredictor
import time
import re
import base64


class NUMPICweb(WebService):
    def init_det_debugger(self, det_model_config):
        self.det_client = LocalPredictor()
        if sys.argv[1] == 'gpu':
            self.det_client.load_model_config(
                det_model_config, use_gpu=True, gpu_id=1)
        elif sys.argv[1] == 'cpu':
            self.det_client.load_model_config(det_model_config)
    def preprocess(self, feed=[],fetch=[]):
        data = base64.b64decode(feed[0]['image'].encode('utf8'))
        data = np.fromstring(data, np.uint8)
        im = cv2.imdecode(data, cv2.IMREAD_COLOR)
        cv2.imwrite('test.png',im)
        file = r"test.png"
        im = cv2.imread(file)
        im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)#转为灰度图
        im = 255-im#对图片反色处理
        im = im / 255.0 * 2.0 - 1.0#(255-im)/255.0
        #im = Image.open(file).convert('L')
        cv2.imshow('a',im)
        cv2.waitKey()
        im = cv2.resize(im,(28,28))  # resize image with high-quality 图像大小为28*28
        im = np.array(im).reshape(1, 1, 28, 28).astype(np.float32)  # 返回新形状的数组,把它变成一个 numpy 数组以匹配数据馈送格式。
        print(im)
        #im = (255-im)/255.0#im / 255.0 * 2.0 - 1.0
        feed = {"image":im}
        fetch = ['fc_2.tmp_2']
        #print(feed)
        fetch_map = self.det_client.predict(feed={"image":im}, fetch=['fc_2.tmp_2'])
        lab = fetch_map['fc_2.tmp_2']
        print(lab)
        print(np.argmax(lab[0]))
        return feed,fetch,False


    def postprocess(self, feed={}, fetch=[],fetch_map=None):
        res = {"res": [f"{np.argmax(fetch_map['fc_2.tmp_2'])}"]}
        return res

# class PICService(WebService):
#     def get_pipeline_response(self, read_op):
#         image_op = NUMPICOp(name="pic", input_ops=[read_op])
#         return image_op

pic_service = NUMPICweb(name="pic")
pic_service.load_model_config("serving_server_dir")#你模型的服务端路径
pic_service.prepare_server(workdir="workdir", port=9292)
pic_service.init_det_debugger(det_model_config="serving_server_dir")
if sys.argv[1] == 'gpu':
    pic_service.set_gpus("0")
    pic_service.run_debugger_service(gpu=True)
elif sys.argv[1] == 'cpu':
    pic_service.run_debugger_service()
pic_service.run_web_service()

其中preprocess为图片预处理,即对传入的base64数据进行解码,保存图片,转灰度以及反色等,因为这里的测试集图像是我自己画的白底黑字数字,训练用的图像都是黑底白字所以要保证预测的输入一致。postprocess为返回客户端的json数据,类似于python的字典格式,这俩个核心函数具体原理请参考上述Web Service设计官方文档。

三、客户端实现

代码如下(示例):

import requests
import json
import cv2
import base64
import os, sys
import time


def cv2_to_base64(image):
    #data = cv2.imencode('.jpg', image)[1]
    return base64.b64encode(image).decode(
        'utf8')  #data.tostring()).decode('utf8')


headers = {"Content-type": "application/json"}
url = "http://127.0.0.1:9292/pic/prediction"
test_img_dir = "D:/Mypy_pro/1/deep_learning/num_pic"#你的测试集数字图像路径
for img_file in os.listdir(test_img_dir):
    with open(os.path.join(test_img_dir, img_file), 'rb') as file:
        image_data1 = file.read()
    image = cv2_to_base64(image_data1)
    data = {"feed": [{"image":image}], "fetch": ['fc_2.tmp_2']}
    r = requests.post(url=url, headers=headers, data=json.dumps(data))
    print(r)

实验示例

手画的数字图片:
在这里插入图片描述
建议使用原始MNIST数据集的数字图片预测,自己手写的数字后面789基本识别不出来!
在工程目录下开启服务命令:python pic_web_server.py cpu
在这里插入图片描述
打开一个新的终端作为客户端:python pic-pipeline_http_client.py
在这里插入图片描述
博主也是新手小白,刚入手才不到俩三个星期,后续会持续更新并尝试pipeline serving服务部署,各位可参考大佬的文章https://blog.csdn.net/qianbin3200896/article/details/124330556,22年4月底写的,非常适合新手学习,有问题欢迎随时在评论区交流一起学习!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
PaddlePaddle可以用来训练数字识别模型。一个常用的数字识别数据集是MNIST,包含了大量手写数字的图片。你可以使用PaddlePaddle的API来加载MNIST数据集,构建卷积神经网络模型,并进行训练和测试。 以下是一个简单的例子,使用PaddlePaddle训练一个数字识别模型: ```python import paddle import paddle.fluid as fluid import numpy as np # 定义网络结构 def convolutional_neural_network(input_layer): conv1 = fluid.layers.conv2d(input_layer, num_filters=32, filter_size=5, stride=1, padding=2, act='relu') pool1 = fluid.layers.pool2d(conv1, pool_size=2, pool_type='max', pool_stride=2) conv2 = fluid.layers.conv2d(pool1, num_filters=64, filter_size=5, stride=1, padding=2, act='relu') pool2 = fluid.layers.pool2d(conv2, pool_size=2, pool_type='max', pool_stride=2) fc1 = fluid.layers.fc(pool2, size=512, act='relu') drop1 = fluid.layers.dropout(fc1, dropout_prob=0.5) fc2 = fluid.layers.fc(drop1, size=10, act='softmax') return fc2 # 定义输入数据形状 image = fluid.layers.data(name='image', shape=[1, 28, 28], dtype='float32') label = fluid.layers.data(name='label', shape=[1], dtype='int64') # 定义前向计算图 predict = convolutional_neural_network(image) # 定义损失函数和优化器 cost = fluid.layers.cross_entropy(input=predict, label=label) avg_cost = fluid.layers.mean(cost) optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.001) opts = optimizer.minimize(avg_cost) # 定义训练和测试程序 place = fluid.CUDAPlace(0) exe = fluid.Executor(place) exe.run(fluid.default_startup_program()) # 加载数据集 train_reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.mnist.train(), buf_size=500), batch_size=128) test_reader = paddle.batch(paddle.dataset.mnist.test(), batch_size=128) # 定义训练过程 for epoch in range(10): for batch_id, data in enumerate(train_reader()): train_cost, train_acc = exe.run(program=fluid.default_main_program(), feed={'image': np.array([x[0].reshape(1, 28, 28) for x in data], dtype='float32'), 'label': np.array([x[1] for x in data], dtype='int64')}, fetch_list=[avg_cost, predict.accuracy]) if batch_id % 100 == 0: print('Epoch {}, Batch {}, Cost {}, Accuracy {}'.format(epoch, batch_id, train_cost[0], train_acc[0])) # 测试模型 test_accs = [] test_costs = [] for batch_id, data in enumerate(test_reader()): test_cost, test_acc = exe.run(program=fluid.default_main_program(), feed={'image': np.array([x[0].reshape(1, 28, 28) for x in data], dtype='float32'), 'label': np.array([x[1] for x in data], dtype='int64')}, fetch_list=[avg_cost, predict.accuracy]) test_accs.append(test_acc[0]) test_costs.append(test_cost[0]) test_cost = sum(test_costs) / len(test_costs) test_acc = sum(test_accs) / len(test_accs) print('Test Epoch {}, Cost {}, Accuracy {}'.format(epoch, test_cost, test_acc)) # 保存模型 fluid.io.save_inference_model(dirname='./model', feeded_var_names=['image'], target_vars=[predict], executor=exe) ``` 在训练完成后,你可以使用保存的模型来进行数字识别。以下是一个简单的例子,加载训练好的模型,输入一张手写数字的图片,输出识别结果: ```python import cv2 # 加载模型 infer_exe = fluid.Executor(place) inference_scope = fluid.core.Scope() with fluid.scope_guard(inference_scope): [inference_program, feed_target_names, fetch_targets] = fluid.io.load_inference_model(dirname='./model', executor=infer_exe) # 读取手写数字的图片 img = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE) img = cv2.resize(img, (28, 28), interpolation=cv2.INTER_AREA) img = img.astype(np.float32) / 255.0 img = np.reshape(img, [1, 1, 28, 28]) # 进行数字识别 results = infer_exe.run(program=inference_program, feed={feed_target_names[0]: img}, fetch_list=fetch_targets) print('The digit is classified as:', np.argmax(results[0])) ``` 注意:在使用以上代码时,需要先安装PaddlePaddle和MNIST数据集。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值