Paddle Inference(模型推理)实例分析

一、Paddle推理生态

在这里插入图片描述


二、API说明

create_predictor 方法

# 根据 Config 构建预测执行器 Predictor
# 参数: config - 用于构建 Predictor 的配置信息
# 返回: Predictor - 预测执行器
paddle.inference.create_predictor(config: Config)

加载预测模型 - 非Combined模型

import paddle.inference as paddle_infer

# 创建 config
config = paddle_infer.Config("./mobilenet_v1")

# 根据 config 创建 predictor
predictor = paddle_infer.create_predictor(config)

加载预测模型 - Combined模型

# 引用 paddle inference 预测库
import paddle.inference as paddle_infer

# 创建 config
config = paddle_infer.Config("./mobilenet_v2/__model__", "./mobilenet_v2/__params__")

# 根据 config 创建 predictor
predictor = paddle_infer.create_predictor(config)

Predictor 类

Paddle Inference的预测器,由 create_predictor 根据 Config 进行创建。用户可以根据Predictor提供的接口设置输入数据、执行模型预测、获取输出等。

import numpy

# 引用 paddle inference 预测库
import paddle.inference as paddle_infer

# 创建 config
config = paddle_infer.Config("./mobilenet_v1")

# 根据 config 创建 predictor
predictor = paddle_infer.create_predictor(config)

# 获取输入 Tensor
input_names = predictor.get_input_names()
input_tensor = predictor.get_input_handle(input_names[0])

# 从 CPU 获取数据,设置到 Tensor 内部
fake_input = numpy.random.randn(1, 3, 224, 224).astype("float32")
input_tensor.copy_from_cpu(fake_input)

# 执行预测
predictor.run()

# 获取输出 Tensor
output_names = predictor.get_output_names()
output_tensor = predictor.get_output_handle(output_names[0])

# 释放中间Tensor
predictor.clear_intermediate_tensor()

# 释放内存池中的所有临时 Tensor
predictor.try_shrink_memory()

三、自建线性模型推理

1、保存模型跟参数

'''
1.1.1 动态图存储载入体系
为提升框架使用体验,飞桨框架2.0将主推动态图模式,动态图模式下的存储载入接口包括:

paddle.save  #训练调优,只保存参数
paddle.load

paddle.jit.save  # 训练部署,保存模型与参数
paddle.jit.load
'''

import numpy as np
import paddle
import paddle.nn as nn
from paddle.io import Dataset,DataLoader
import paddle.optimizer as opt

BATCH_SIZE = 4
BATCH_NUM = 4
EPOCH_NUM = 4

IMAGE_SIZE = 16
CLASS_NUM = 10

# define a random dataset
class RandomDataset(Dataset):
    def __init__(self,nums):
        super(RandomDataset,self).__init__()
        self.num_samples = nums

    def __getitem__(self, idx):
        image = np.random.random([IMAGE_SIZE]).astype('float32')
        label = np.random.randint(0,CLASS_NUM-1,(1,)).astype('int64')
        return image,label

    def __len__(self):
        return self.num_samples

class LinearNet(nn.Layer):
    def __init__(self):
        super(LinearNet,self).__init__()

        self.linear = paddle.nn.Linear(IMAGE_SIZE,700)
        self.linear1 = paddle.nn.Linear(700, CLASS_NUM)

    # @paddle.jit.to_static 保存模型跟参数的时候需要转化
    def forward(self, x):
        x = self.linear(x)
        return self.linear1(x)

# create data loader
dataset = RandomDataset(BATCH_NUM*BATCH_SIZE)

loader = DataLoader(dataset,batch_size=BATCH_SIZE)

def train(layer,loader,loss_fn,opt):
    for epoch_id in range(EPOCH_NUM):
        for batch_id,(image,label) in enumerate(loader):
            print(image.shape)
            out = layer(image)
            loss = loss_fn(out,label)
            loss.backward()
            opt.step()
            opt.clear_grad()
            print("Epoch[{}/{}] batch {}: loss = {}".format(epoch_id,EPOCH_NUM,batch_id,np.mean(loss.numpy())))

# create network
layer = LinearNet()
loss_fn = nn.CrossEntropyLoss()
adam = opt.Adam(learning_rate=0.001, parameters=layer.parameters())

# train
train(layer, loader, loss_fn, adam)

'''
动转静训练 + 模型&参数存储


class LinearNet(nn.Layer):
    def __init__(self):
        super(LinearNet, self).__init__()
        self._linear = nn.Linear(IMAGE_SIZE, CLASS_NUM)

    @paddle.jit.to_static
    def forward(self, x):
        return self._linear(x)
'''
# from paddle.static import InputSpec
# save
path = "example.model/linear"
paddle.jit.save(layer, path)

# save
path = "example.dy_model/linear"
paddle.jit.save(
    layer=layer,
    path=path,
    input_spec=[InputSpec(shape=[None, 784], dtype='float32')])

还有一种方法如下:
net = to_static(model, input_spec=[InputSpec(shape=[None, 1, 28, 28], name='x')])
paddle.jit.save(net, 'inference_model/lenet')

结果如下:
在这里插入图片描述


2、Paddle Inference

# model_inference.py
import argparse
import numpy as np

# 引用 paddle inference 预测库
import paddle.inference as paddle_infer

def main():
    args = parse_args()

    # 创建 config
    config = paddle_infer.Config(args.model_file, args.params_file)
	config.disable_gpu() # 使用cpu预测
    # 根据 config 创建 predictor
    predictor = paddle_infer.create_predictor(config)

    # 获取输入的名称
    input_names = predictor.get_input_names()
    print("input_names:",input_names)
    input_handle = predictor.get_input_handle(input_names[0])

    # 设置输入
    fake_input = np.random.randn(args.batch_size, 16).astype("float32")
    input_handle.reshape([args.batch_size, 16])
    input_handle.copy_from_cpu(fake_input)

    # 运行predictor
    predictor.run()

    # 获取输出
    output_names = predictor.get_output_names()
    output_handle = predictor.get_output_handle(output_names[0])
    output_data = output_handle.copy_to_cpu() # numpy.ndarray类型
    print("Output data size is {}".format(output_data.size))
    print("Output data shape is {}".format(output_data.shape))

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("--model_file", type=str,default='./example.model/linear.pdmodel', help="model filename")
    parser.add_argument("--params_file", type=str,default='./example.model/linear.pdiparams', help="parameter filename")
    parser.add_argument("--batch_size", type=int, default=1, help="batch size")
    return parser.parse_args()

if __name__ == "__main__":
    main()

'''
# 参数输入上面生成的linear模型
python model_inference.py --model_file ./example.model/linear.pdmodel --params_file ./example.model/linear.pdiparams --batch_size 2
'''

结果如下:
在这里插入图片描述


四、检测网络YOLOV3推理

总共需要三个文件:
1、Paddle模型和参数
2、utils.py包括图像的处理
3、infer_yolov3.py实现模型的推理

获取模型

wget https://paddle-inference-dist.bj.bcebos.com/Paddle-Inference-Demo/yolov3_r50vd_dcn_270e_coco.tgz
tar xzf yolov3_r50vd_dcn_270e_coco.tgz

# utils.py
import cv2
import numpy as np
from PIL import Image, ImageDraw


def resize(img, target_size):
    """resize to target size"""
    if not isinstance(img, np.ndarray):
        raise TypeError('image type is not numpy.')
    im_shape = img.shape
    print(im_shape)
    im_size_min = np.min(im_shape[0:2])
    im_size_max = np.max(im_shape[0:2])
    im_scale_x = float(target_size) / float(im_shape[1])
    im_scale_y = float(target_size) / float(im_shape[0])
    img = cv2.resize(img, None, None, fx=im_scale_x, fy=im_scale_y)
    return img


def normalize(img, mean, std):
    img = img / 255.0
    mean = np.array(mean)[np.newaxis, np.newaxis, :]
    std = np.array(std)[np.newaxis, np.newaxis, :]
    img -= mean
    img /= std
    return img


def preprocess(img, img_size):
    mean = [0.485, 0.456, 0.406]
    std = [0.229, 0.224, 0.225]
    img = resize(img, img_size)
    img = img[:, :, ::-1].astype('float32')  # bgr -> rgb
    img = normalize(img, mean, std)
    img = img.transpose((2, 0, 1))  # hwc -> chw
    img = img[np.newaxis, :]
    print(img.shape)
    return img

"""
def draw_bbox(img, result, threshold=0.5, save_name='res.jpg'):
    """draw bbox"""
    draw = ImageDraw.Draw(img)
    for res in result:
        cat_id, score, bbox = res[0], res[1], res[2:]
        if score < threshold:
            continue
        xmin, ymin, xmax, ymax = bbox
        draw.line([(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin),
                   (xmin, ymin)],
                  width=2,
                  fill=(255, 0, 0))
        print('category id is {}, bbox is {}'.format(cat_id, bbox))
    img.save(save_name, quality=95)
"""

def draw_box(img,result,threshold=0.5):
    for res in result:
        cat_id, score, bbox = res[0], res[1], res[2:]
        if score < threshold:
            continue
        xmin, ymin, xmax, ymax = int(bbox[0]),int(bbox[1]),int(bbox[2]),int(bbox[3])
        print('category id is {}, bbox is {}'.format(cat_id, bbox))
        cv2.rectangle(img,(xmin,ymax),(xmax,ymin),(255,0,0),2)
    cv2.namedWindow("detection",cv2.WINDOW_NORMAL)
    cv2.imshow("detection",img)
    cv2.waitKey(0)


if __name__ == '__main__':
    img = cv2.imread('kite.jpg')

    # xmin, ymin, xmax, ymax = [216, 697, 268, 848]
    # cv2.rectangle(img, (xmin, ymax), (xmax, ymin), (255, 0, 0), 2)
    cv2.namedWindow("detection1",cv2.WINDOW_GUI_NORMAL)
    cv2.imshow("detection1",img)
    cv2.waitKey(0)

# -*- coding: utf-8 -*-
"""
Created on : 2021/6/3 21:10

@author: Jeremy
"""

import numpy as np
import argparse
import cv2
from PIL import Image

from paddle.inference import Config
from paddle.inference import create_predictor

from PaddlePaddle.utils import preprocess, draw_bbox,draw_box


def init_predictor(args):
    if args.model_dir != "":
        config = Config(args.model_dir)
    else:
        config = Config(args.model_file, args.params_file)

    config.enable_memory_optim()
    if args.use_gpu:
        config.enable_use_gpu(1000, 0)
    else:
        # If not specific mkldnn, you can set the blas thread.
        # The thread num should not be greater than the number of cores in the CPU.
        config.set_cpu_math_library_num_threads(4)
        config.enable_mkldnn()

    predictor = create_predictor(config)

    return predictor


def run(predictor, img):
    # copy img data to input tensor
    input_names = predictor.get_input_names()
    # print("input_names:",input_names)
    for i, name in enumerate(input_names):
        input_tensor = predictor.get_input_handle(name)

        input_tensor.reshape(img[i].shape)
        # print("input_tensor:",img[i].shape)
        input_tensor.copy_from_cpu(img[i].copy())

    # do the inference
    predictor.run()

    results = []
    # get out data from output tensor
    output_names = predictor.get_output_names()
    for i, name in enumerate(output_names):
        output_tensor = predictor.get_output_handle(name)
        output_data = output_tensor.copy_to_cpu()
        results.append(output_data)
    return results


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--model_file",type=str,
        default="./yolov3_coco/model.pdmodel",
        help="Model filename, Specify this when your model is a combined model."
    )
    parser.add_argument(
        "--params_file",type=str,
        default="./yolov3_coco/model.pdiparams",
        help="Parameter filename, Specify this when your model is a combined model."
    )
    parser.add_argument(
        "--model_dir",type=str,
        default="",
        help="Model dir, If you load a non-combined model, specify the directory of the model."
    )
    parser.add_argument("--use_gpu",type=int,default=0,help="Whether use gpu.")
    return parser.parse_args()


if __name__ == '__main__':
    args = parse_args()
    img_name = 'kite.jpg'
    save_img_name = 'res.jpg'
    im_size = 608
    pred = init_predictor(args)
    img = cv2.imread(img_name)
    data = preprocess(img, im_size)
    scale_factor = np.array([im_size * 1. / img.shape[0], im_size * 1. / img.shape[1]]).reshape((1, 2)).astype(np.float32)
    im_shape = np.array([im_size, im_size]).reshape((1, 2)).astype(np.float32)
    result = run(pred, [im_shape, data,scale_factor])
    # img = Image.open(img_name).convert('RGB')
    # draw_bbox(img, result[0], save_name=save_img_name)
    draw_box(img,result[0])

猜你喜欢

转载自blog.csdn.net/Jeremy_lf/article/details/117529994