课程全程将在[SOPHGO(算能)云平台上进行。

本次课程将介绍:

(1)SOPHGO(算能)云平台环境搭建

(2)LPRNet算法

(3)通过BMNNSDK 2.7.0进行LPRNet模型转换和量化

(4)实现算法的移植

(5)部署和测试

(6)相关链接

(1) SOPHGO(算能)云平台环境搭建

a. 开通云平台账号

参考: https://cloud.sophgo.com/tpu.pdf

b. 开发环境初始化

1) 进入命令行模式,进去默认在/home/sophgo目录

2) 切换成 root 权限

sudo -i

3) 安装驱动

cd /home/sophgo/bmnnsdk2-bm1684_v2.7.0/scripts

./install_driver_pcie.sh

ls /dev/bm*

如果可以看到以下设备节点,表示驱动安装成功:

4) 加载Docker,并初始化环境

cd /home/sophgo/
apt install unzip
unzip bmnnsdk2-bm1684-ubuntu-docker-py37.zip
cd bmnnsdk2-bm1684-ubuntu-docker-py37/
docker load -i bmnnsdk2-bm1684-ubuntu.docker

5) 通过脚本创建Docker容器

cd /home/sophgo/bmnnsdk2-bm1684_v2.7.0/
# 执行脚本创建Docker容器
./docker_run_bmnnsdk.sh

# 自动进入Docker容器
# 进行环境初始化
cd scripts/

# 更新 pip
/usr/local/bin/python3 -m pip install --upgrade pip

# 安装 nntc
./install_lib.sh nntc

# 执行脚本 envsetup_pcie.sh 设置环境变量
source ./envsetup_pcie.sh

# 安装sophon包
pip3 install /workspace/lib/sail/python3/pcie/py37/sophon-2.7.0-py3-none-any.whl

 6) Docker 常用命令

# 启动 Docker容器
docker start <CONTAINER ID>

# 查看正在运行的 Docker容器
docker ps

# 进入 Docker 容器 docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
docker exec -it <CONTAINER ID> bash

 7) 通过云空间文件系统拷贝代码到Docker容器中

打开云空间文件系统:

上传文件:文件会被存储在服务器的 /tmp 目录下**

拷贝文件到Docker容器中:
Docker容器的workspace目录被映射到 /home/sophgo/bmnnsdk2-bm1684_v2.7.0/

cp /tmp/<待拷贝文件> /home/sophgo/bmnnsdk2-bm1684_v2.7.0/

(2)LPRNet简介

论文链接:[https://arxiv.org/abs/1806.10447v1](https://arxiv.org/abs/1806.10447v1)

代码仓库链接:[https://github.com/sirius-ai/LPRNet_Pytorch]

LPRNet 全称为 License Plate Recognition via Deep Neural Networks,是由Intel于2018年发表的一种轻量级卷积神经网络,可实现端到端的车牌识别。其优点主要包括以下三点:

1. LPRNet不需要字符预先分割,能够端到端进行模型训练和推理,支持可变长字符车牌识别,车牌识别的准确率高、算法实时性强。
2. LPRNet是第一个没有使用RNN的实时轻量级OCR算法,能够在各种设备上运行,包括嵌入式设备。
3. LPRNet的鲁棒性强,在视角和摄像畸变、光照条件恶劣、视角变化等复杂的情况下,仍表现出较好的识别效果。

(3) 模型转换与量化

 a. 准备模型与数据

1) 从Github上获取SOPHON示例项目:git clone -b 2.7.0 https://github.com/sophon-ai-algo/examples.git

LPRNet 示例项目路径:/examples/simple/lprnet**

附:也可通过本地直接拷贝该项目到云平台(参考 (1).b.7) ) 通过云空间文件系统拷贝代码到Docker容器中)**

2) 下载相关数据集和模型

当前路径为: /examples/simple/lprnet

打开script文件夹
cd script
运行 download.sh 脚本文件下载数据,数据模型文件被保存在/examples/simple/lprnet/data下
./download.sh

3) 训练好的Pytorch模型转换为JIT模型

由于 BMNNSDK2 中的PyTorch模型编译工具BMNETP只接受PyTorch的JIT模型(TorchScript模型),需要用户自行将训练好的Pytorch模型进行转换。

在SOPHON示例项目/examples/simple/lprnet/data/models文件夹中有已经转换好的 LPRNet_model.torchscript 模型

示例:将训练好的 Final_LPRNet_model.pth 转换为 LPRNet_model.torchscript

从Github上获取LPRNet源码:git clone https://github.com/sirius-ai/LPRNet_Pytorch.git

import torch

from model.LPRNet import LPRNet

lpr_max_len=8
phase=False
class_num=68
dropout_rate=0

PATH_TO_PT_MODEL = 'Final_LPRNet_model.pth'
PATH_TO_JIT_MODEL = 'LPRNet_model.torchscript'

LPRNet 为官方源码 https://github.com/sirius-ai/LPRNet_Pytorch/blob/master/model/LPRNet.py
lprnet = LPRNet(lpr_max_len, phase, class_num, dropout_rate)

在CPU上加载网络模型
lprnet.eval().load_state_dict(torch.load(PATH_TO_PT_MODEL, map_location=torch.device('cpu')))
jit.trace
model = torch.jit.trace(lprnet.forward, torch.rand(1, 3, 24, 94))
保存JIT模型
torch.jit.save(model, PATH_TO_JIT_MODEL)

得到 LPRNet_model.torchscript 后,需要通过 BMNNSDK2 中的PyTorch模型编译工具BMNETP和量化工具生成:FP32 BModel 和 INT8 BModel

4) 生成FP32 BModel

BMNETP是针对pytorch的模型编译器,可以把pytorch模型直接编译成BMRuntime所需的执行指令。https://doc.sophgo.com/docs/docs_latest_release/nntc/html/usage/bmnetp.html#pytorch

将 LPRNet_model.torchscript 转换为 FP32 BModel的命令:

python3 -m bmnetp --net_name=lprnet \
--target=BM1684 \
--opt=1 \
--cmp=true \
--shapes=[1,3,24,94] \
--model=<LPRNet_model.torchscript的路径> \
--outdir=<输出文件夹的路径> \
--dyn=false

附:可通过运行scripts/gen_fp32bmodel.sh脚本文件(注意修改脚本文件中的模型所在路径),在data/models/fp32bmodel/下生成lprnet_fp32_1b4b.bmodel。

# 运行scripts/gen_fp32bmodel.sh脚本文件
./gen_fp32bmodel.sh

*选做5) 生成INT8 BModel(注意: LPRNet模型量化需在20220317之后版本的BMNNSDK2 SDK中进行!)

参考文档:https://doc.sophgo.com/docs/2.7.0/docs_latest_release/calibration-tools/html/module/chapter4.html#int8umodel

具体步骤:

方法一:一键量化 (注意模型所在的路径)

python3 -m ufw.cali.cali_model --net_name lprnet \
--model ../data/models/LPRNet_model.pt \
--cali_image_path ../data/images/test_md5 \
--cali_image_preprocess 'resize_h=24,resize_w=94;mean_value=127.5:127.5:127.5,scale=0.0078125,bgr2rgb=True' \
--input_shapes '[1,3,24,94]' \
--cali_iterations=450  \
--postprocess_and_calc_score_class=feature_similarity

方法二:分步量化 (注意模型所在的路径)

分步量化步骤:

1. 生成量化数据集lmdb

2. 原模型转 FP32 UModel

3. 量化 Int8 UModel

4. bmnetu 编译 Int8 BModel

可以通过 运行scripts文件夹中的gen_int8bmodel.sh脚本文件(注意修改脚本文件中的模型所在路径)

 6) 查看得到的BModel的信息

# 以lprnet_fp32_1b4b.bmodel为例

# bm_model.bin --info xxxx.bmodel
bm_model.bin --info lprnet_fp32_1b4b.bmodel

# 将得到模型信息:
bmodel version: B.2.2
chip: BM1684
create time: Fri Apr 15 09:25:42 2022

==========================================
net 0: [lprnet]  static
------------
stage 0:
input: x.1, [1, 3, 24, 94], float32, scale: 1
output: 237, [1, 68, 18], float32, scale: 1
------------
stage 1:
input: x.1, [4, 3, 24, 94], float32, scale: 1
output: 237, [4, 68, 18], float32, scale: 1

device mem size: 5246160 (coeff: 1941776, instruct: 188928, runtime: 3115456)
host mem size: 0 (coeff: 0, runtime: 0)

# bmrt_test --bmodel xxxx.bmodel
bmrt_test --bmodel lprnet_fp32_1b4b.bmodel

# 将得到模型信息:
[BMRT][deal_with_options:1398] INFO:Loop num: 1
bmcpu init: skip cpu_user_defined
open usercpu.so, init user_cpu_init 
[BMRT][load_bmodel:1018] INFO:Loading bmodel from [lprnet_fp32_1b4b.bmodel]. Thanks for your patience...
[BMRT][load_bmodel:982] INFO:pre net num: 0, load net num: 1
[BMRT][bmrt_test:758] INFO:==> running network #0, name: lprnet, loop: 0
[BMRT][bmrt_test:1001] INFO:net[lprnet] stage[0], launch total time is 1697 us (npu 1579 us, cpu 118 us)
[BMRT][bmrt_test:1004] INFO:+++ The network[lprnet] stage[0] output_data +++
[BMRT][print_array:700] INFO:output data #0 shape: [1 68 18 ] < -145.928 -94.5729 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 ... > len=1224
[BMRT][bmrt_test:1049] INFO:load input time(s): 0.000073
[BMRT][bmrt_test:1050] INFO:calculate  time(s): 0.001713
[BMRT][bmrt_test:1051] INFO:get output time(s): 0.000106
[BMRT][bmrt_test:1052] INFO:compare    time(s): 0.000211
[BMRT][bmrt_test:1001] INFO:net[lprnet] stage[1], launch total time is 3485 us (npu 3399 us, cpu 86 us)
[BMRT][bmrt_test:1004] INFO:+++ The network[lprnet] stage[1] output_data +++
[BMRT][print_array:700] INFO:output data #0 shape: [4 68 18 ] < -145.928 -94.573 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 -119.698 ... > len=4896
[BMRT][bmrt_test:1049] INFO:load input time(s): 0.000155
[BMRT][bmrt_test:1050] INFO:calculate  time(s): 0.003489
[BMRT][bmrt_test:1051] INFO:get output time(s): 0.000069
[BMRT][bmrt_test:1052] INFO:compare    time(s): 0.000085

(4)算法移植

 a. Python示例程序: 

文件位置:/examples/simple/lprnet/python

由于python例程需要用到sail库,需要安装Sophon Inference:

pip3 install /workspace/lib/sail/python3/pcie/py37/sophon-x.x.x-py3-none-any.whl

lprnet_cv_cv_sail.py 代码

# -*- coding: utf-8 -*- 
import os
import time
import cv2
import numpy as np
import argparse
#from pyrsistent import T
import sophon.sail as sail
import logging
logging.basicConfig(level=logging.DEBUG)

CHARS = ['京', '沪', '津', '渝', '冀', '晋', '蒙', '辽', '吉', '黑',
         '苏', '浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '粤',
         '桂', '琼', '川', '贵', '云', '藏', '陕', '甘', '青', '宁',
         '新',
         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
         'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
         'W', 'X', 'Y', 'Z', 'I', 'O', '-'
         ]

CHARS_DICT = {i:char for i, char in enumerate(CHARS)}

# input: x.1, [1, 3, 24, 96], float32, scale: 1
class LPRNet(object):
    def __init__(self, opt, img_size = [94, 24]):
        self.batch_size = opt.batch_size
        
        # load bmodel
        model_path = opt.bmodel
        print("using model {}".format(model_path))
        self.net = sail.Engine(model_path, opt.tpu_id, sail.IOMode.SYSIO)
        self.graph_name = self.net.get_graph_names()[0]
        self.input_name = self.net.get_input_names(self.graph_name)[0]
        #self.scale = self.net.get_input_scale(self.graph_name, self.input_name)
        #self.scale *= 0.0078125
        print("load bmodel success!")
        self.img_size = img_size
        self.dt = 0.0
    
    # 图片预处理
    def preprocess(self, img):
        h, w, _ = img.shape
        if h != self.img_size[1] or w != self.img_size[0]:
            img = cv2.resize(img, self.img_size)
        img = img.astype('float32')
        img -= 127.5
        img *= 0.0078125
        img = np.transpose(img, (2, 0, 1))

# CHW to NCHW format
        #img = np.expand_dims(img, axis=0)
        # Convert the img to row-major order, also known as "C order":
        #img = np.ascontiguousarray(img)
        return img
    
    def predict(self, tensor):
        input_data = {self.input_name: np.array(tensor, dtype=np.float32)}
        t0 = time.time()
        # 使用sail.engine.process进行推理
        outputs = self.net.process(self.graph_name, input_data)
        self.dt += time.time() - t0
        return list(outputs.values())[0]
    
    # 后处理
    def postprocess(self, outputs):
        res = list()
        #outputs = list(outputs.values())[0]
        outputs = np.argmax(outputs, axis = 1)
        for output in outputs:
            no_repeat_blank_label = list()
            pre_c = output[0]
            if pre_c != len(CHARS) - 1:
                no_repeat_blank_label.append(CHARS_DICT[pre_c])
            for c in output:
                if (pre_c == c) or (c == len(CHARS) - 1):
                    if c == len(CHARS) - 1:
                        pre_c = c
                    continue
                no_repeat_blank_label.append(CHARS_DICT[c])
                pre_c = c
            res.append(''.join(no_repeat_blank_label))

return res

def __call__(self, img_list):
        res_list = []
        img_num = len(img_list)
        img_input_list = []
        for img in img_list:
            img = self.preprocess(img)
            img_input_list.append(img)

for beg_img_no in range(0, img_num, self.batch_size):
            end_img_no = min(img_num, beg_img_no + self.batch_size)
            if beg_img_no + self.batch_size > img_num:
                for ino in range(beg_img_no, end_img_no):
                    img_input = np.expand_dims(img_input_list[ino], axis=0)
                    outputs = self.predict(img_input)
                    res = self.postprocess(outputs)
                    res_list.extend(res)
            else:
                img_input = np.stack(img_input_list[beg_img_no:end_img_no])
                #print("=================")
                #print(img_input)
                outputs = self.predict(img_input)
                #print(outputs)
                res = self.postprocess(outputs)
                res_list.extend(res)

return res_list

def get_time(self):
        return self.dt

def main(opt):
    lprnet = LPRNet(opt)
    if os.path.isfile(opt.img_path):
        # 图片解码
        src_img = cv2.imdecode(np.fromfile(opt.img_path, dtype=np.uint8), -1)
        #src_img = cv2.imread(opt.img_path)
        #print(src_img[0])
        #print(cv2.getBuildInformation())
        res = lprnet([src_img])
        logging.info("img:{}, res:{}".format(opt.img_path, res[0]))
    else:
        img_list = []
        t1 = time.time()
        for img_name in os.listdir(opt.img_path):
            img_file = os.path.join(opt.img_path, img_name)
            # 图片解码
            src_img = cv2.imdecode(np.fromfile(img_file, dtype=np.uint8), -1)
            img_list.append(src_img)

res_list = lprnet(img_list)

t2 = time.time()
        
        Tp = 0
        for i, img_name in enumerate(os.listdir(opt.img_path)):
            logging.info("img:{}, res:{}".format(img_name, res_list[i]))
            if opt.mode == 'val':
                label = img_name.split('.')[0]
                if res_list[i] == label:
                    Tp += 1
                else:
                    logging.info("***wrong***")
                    #logging.info("img:{}, res:{}".format(img_name, res_list[i]))
                    
        if opt.mode == 'val':
            cn = len(os.listdir(opt.img_path))
            logging.info("ACC = %.4f" % (Tp / cn))
        
        
        logging.info("------------------ Inference Time Info ----------------------")
        inference_time = lprnet.get_time() / len(img_list)
        logging.info("inference_time(ms): {:.2f}".format(inference_time * 1000))
        total_time = t2 - t1
        logging.info("total_time(ms): {:.2f}, img_num: {}".format(total_time * 1000, len(img_list)))
        average_latency = total_time / len(img_list)
        qps = 1 / average_latency
        logging.info("average latency time(ms): {:.2f}, QPS: {:2f}".format(average_latency * 1000, qps))

def parse_opt():
    parser = argparse.ArgumentParser(prog=__file__)
    parser.add_argument('--mode', type=str, default='val')
    parser.add_argument('--img_path', type=str, default='data/images/test', help='input image path')
    parser.add_argument('--bmodel', type=str, default='scripts/fp32bmodel/lprnet_fp32.bmodel', help='input model path')
    parser.add_argument("--batch_size", type=int, default=4)
    parser.add_argument('--tpu_id', type=int, default=0, help='tpu id')
    opt = parser.parse_args()
    return opt

if __name__ == '__main__':
    opt = parse_opt()
    main(opt)

lprnet_sail_bmcv_sail.py 代码

# -*- coding: utf-8 -*- 
import time
import os
import cv2
import numpy as np
import argparse
import sophon.sail as sail
import logging
logging.basicConfig(level=logging.DEBUG)

CHARS = ['京', '沪', '津', '渝', '冀', '晋', '蒙', '辽', '吉', '黑',
         '苏', '浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '粤',
         '桂', '琼', '川', '贵', '云', '藏', '陕', '甘', '青', '宁',
         '新',
         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
         'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
         'W', 'X', 'Y', 'Z', 'I', 'O', '-'
         ]

CHARS_DICT = {i:char for i, char in enumerate(CHARS)}

# input: x.1, [1, 3, 24, 96], float32, scale: 1
class LPRNet(object):
    def __init__(self, opt):
        self.batch_size = opt.batch_size
        # load bmodel
        model_path = opt.bmodel
        print("using model {}".format(model_path))
        self.net = sail.Engine(model_path, opt.tpu_id, sail.IOMode.SYSIO)
        print("load bmodel success!")
        self.graph_name = self.net.get_graph_names()[0]
        self.input_name = self.net.get_input_names(self.graph_name)[0]
        self.output_name = self.net.get_output_names(self.graph_name)[0]

self.input_shape = [self.batch_size, 3, 24, 94]
        self.input_shapes = {self.input_name: self.input_shape}
        self.output_shape = [self.batch_size, 68, 18]
        self.input_dtype= self.net.get_input_dtype(self.graph_name, self.input_name)
        self.output_dtype = self.net.get_output_dtype(self.graph_name, self.output_name)

# get handle to create input and output tensors  
        self.handle = self.net.get_handle()
        self.input = sail.Tensor(self.handle, self.input_shape,  self.input_dtype,  False, False)
        self.output = sail.Tensor(self.handle, self.output_shape, self.output_dtype, True,  True)
        self.input_tensors = {self.input_name: self.input}
        self.output_tensors = {self.output_name: self.output}
        # set io_mode
        # self.net.set_io_mode(self.graph_name, sail.IOMode.SYSO)
        # init bmcv for preprocess
        self.bmcv = sail.Bmcv(self.handle)
        self.img_dtype = self.bmcv.get_bm_image_data_format(self.input_dtype)

self.scale = self.net.get_input_scale(self.graph_name, self.input_name)
        self.ab = [x * self.scale * 0.0078125  for x in [1, -127.5, 1, -127.5, 1, -127.5]]

self.dt = 0.0

# 图片解码
    def decode_bmcv(self, img_file):
        decoder = sail.Decoder(img_file)
        img = decoder.read(self.handle)
        return img
    
    # 预处理
    def preprocess_bmcv(self, input, output):
        tmp = self.bmcv.vpp_resize(input, 94, 24)
        
        self.bmcv.convert_to(tmp, output, ((self.ab[0], self.ab[1]), \
                                       (self.ab[2], self.ab[3]), \
                                       (self.ab[4], self.ab[5])))
        self.bmcv.bm_image_to_tensor(output, self.input)

def predict(self):
        t0 = time.time()
         # 使用sail.engine.process进行推理
        self.net.process(self.graph_name, self.input_tensors, self.input_shapes, self.output_tensors)
        self.dt += time.time() - t0
        real_output_shape = self.net.get_output_shape(self.graph_name, self.output_name)
        outputs = self.output.asnumpy(real_output_shape)
        return outputs
    
    # 后处理
    def postprocess(self, outputs):
        res = list()
        #outputs = list(outputs.values())[0]
        outputs = np.argmax(outputs, axis = 1)
        for output in outputs:
            no_repeat_blank_label = list()
            pre_c = output[0]
            if pre_c != len(CHARS) - 1:
                no_repeat_blank_label.append(CHARS_DICT[pre_c])
            for c in output:
                if (pre_c == c) or (c == len(CHARS) - 1):
                    if c == len(CHARS) - 1:
                        pre_c = c
                    continue
                no_repeat_blank_label.append(CHARS_DICT[c])
                pre_c = c
            res.append(''.join(no_repeat_blank_label))

return res

def __call__(self, img_file_list):
        img_num = len(img_file_list)
        res_list = []
        for beg_img_no in range(0, img_num, self.batch_size):
            end_img_no = min(img_num, beg_img_no + self.batch_size)
            if (beg_img_no + self.batch_size > img_num) or (self.batch_size != 4):
                for ino in range(beg_img_no, end_img_no):
                    img0 = sail.BMImage()
                    img1 = sail.BMImage(self.handle, self.input_shape[2], self.input_shape[3], \
                        sail.Format.FORMAT_BGR_PLANAR, self.img_dtype)
                    # 图片解码
                    decoder = sail.Decoder(img_file_list[ino])
                    ret = decoder.read(self.handle, img0)
                    self.preprocess_bmcv(img0, img1)
                    outputs = self.predict()
                    res = self.postprocess(outputs)
                    res_list.extend(res)
            else:
                imgs_0 = sail.BMImageArray4D()
                imgs_1 = sail.BMImageArray4D(self.handle, self.input_shape[2], self.input_shape[3], \
                                 sail.Format.FORMAT_BGR_PLANAR, self.img_dtype)
                for j in range(4):
                    # 图片解码
                    decoder = sail.Decoder(img_file_list[beg_img_no + j])
                    ret = decoder.read_(self.handle, imgs_0[j])
                self.preprocess_bmcv(imgs_0, imgs_1)
                outputs = self.predict()
                res = self.postprocess(outputs)
                res_list.extend(res)

return res_list

def get_time(self):
        return self.dt

def main(opt):
    lprnet = LPRNet(opt)
    if os.path.isfile(opt.img_path):
        res_list = lprnet([opt.img_path])
        logging.info("img:{}, res:{}".format(opt.img_path, res_list[0]))
    else:
        Tp = 0
        img_file_list = [os.path.join(opt.img_path, img_name) for img_name in os.listdir(opt.img_path)]
        
        t1 = time.time()
        res_list = lprnet(img_file_list)
        t2 = time.time()

for i, img_name in enumerate(os.listdir(opt.img_path)):
            logging.info("img:{}, res:{}".format(img_name, res_list[i]))
            if opt.mode == 'val':
                label = img_name.split('.')[0]
                if res_list[i] == label:
                    Tp += 1
            
        if opt.mode == 'val':
            cn = len(os.listdir(opt.img_path))
            logging.info("ACC = %.4f" % (Tp / cn))
        
        logging.info("------------------ Inference Time Info ----------------------")
        inference_time = lprnet.get_time() / len(img_file_list)
        logging.info("inference_time(ms): {:.2f}".format(inference_time * 1000))
        total_time = t2 - t1
        logging.info("total_time(ms): {:.2f}, img_num: {}".format(total_time * 1000, len(img_file_list)))
        average_latency = total_time / len(img_file_list)
        qps = 1 / average_latency
        logging.info("average latency time(ms): {:.2f}, QPS: {:2f}".format(average_latency * 1000, qps))

def parse_opt():
    parser = argparse.ArgumentParser(prog=__file__)
    #parser.add_argument('--img-size', type=int, default=[94, 24], help='inference size (pixels)')
    parser.add_argument('--mode', type=str, default='val')
    parser.add_argument('--img_path', type=str, default='/workspace/projects/LPRNet/data/images/test', help='input image path')
    parser.add_argument('--bmodel', type=str, default='/workspace/bmnnsdk2-bm1684_v2.7.0_0317/examples/LPRNet/scripts/int8bmodel/lprnet_int8.bmodel', help='input model path')
    parser.add_argument("--batch_size", type=int, default=1)
    parser.add_argument('--tpu_id', type=int, default=0, help='tpu id')
    #parser.add_argument('--format', type=str, default="fp32", help='model format fp32 or fix8b')
    opt = parser.parse_args()
    return opt

if __name__ == '__main__':
    opt = parse_opt()
    main(opt)
```

b. C++示例程序: 

文件位置:/examples/simple/lprnet/cpp

(5)部署测试

a. Python示例程序运行(以lprnet_cv_cv_sail.py使用FP32 BModel为例)

注意:以下命令均在路径 examples/simple/lprnet/ 下运行, 使用不同示例程序仅需更换名称即可**

1) 测试单张图片

# 运行命令
python3 python/lprnet_cv_cv_sail.py --mode test --img_path data/images/test.jpg --bmodel data/models/fp32bmodel/lprnet_fp32_1b4b.bmodel --batch_size 1 --tpu_id 0

# 程序将输出:
...
using model data/models/fp32bmodel/lprnet_fp32_1b4b.bmodel
bmcpu init: skip cpu_user_defined
open usercpu.so, init user_cpu_init 
[BMRT][load_bmodel:1018] INFO:Loading bmodel from [data/models/fp32bmodel/lprnet_fp32_1b4b.bmodel]. Thanks for your patience...
[BMRT][load_bmodel:982] INFO:pre net num: 0, load net num: 1
load bmodel success!
INFO:root:img:data/images/test.jpg, res:皖A22B20
...

2) 测试整个文件夹

# 运行命令
python3 python/lprnet_cv_cv_sail.py --mode test --img_path data/images/test --bmodel data/models/fp32bmodel/lprnet_fp32_1b4b.bmodel --batch_size 4 --tpu_id 0

# 程序将输出整个文件夹的测试结果:
using model data/models/fp32bmodel/lprnet_fp32_1b4b.bmodel
bmcpu init: skip cpu_user_defined
open usercpu.so, init user_cpu_init 
[BMRT][load_bmodel:1018] INFO:Loading bmodel from [data/models/fp32bmodel/lprnet_fp32_1b4b.bmodel]. Thanks for your patience...
[BMRT][load_bmodel:982] INFO:pre net num: 0, load net num: 1
load bmodel success!
INFO:root:img:皖A225J1.jpg, res:皖A225J1
INFO:root:img:皖AMZ210.jpg, res:皖AMZ210
INFO:root:img:皖AAS656.jpg, res:皖AAS656
INFO:root:img:皖AC9165.jpg, res:皖AC9165
INFO:root:img:苏AP48A8.jpg, res:苏AP48A8
...
INFO:root:------------------ Inference Time Info ----------------------
INFO:root:inference_time(ms): 1.92
INFO:root:total_time(ms): 2147.03, img_num: 1000
INFO:root:average latency time(ms): 2.15, QPS: 465.759859

3) 测试整个文件夹,并计算准确率

# 运行命令
python3 python/lprnet_cv_cv_sail.py --mode val --img_path data/images/test --bmodel data/models/fp32bmodel/lprnet_fp32_1b4b.bmodel --batch_size 4 --tpu_id 0

# 程序将输出整个文件夹的测试结果:
...
INFO:root:img:皖NXT689.jpg, res:皖NXT689
INFO:root:img:皖AJ0J22.jpg, res:皖5M9B
INFO:root:***wrong***
INFO:root:img:皖AGX988.jpg, res:皖AGX988
INFO:root:img:皖AL8Y77.jpg, res:皖AL8Y77
INFO:root:img:皖AL136E.jpg, res:皖AL1365
INFO:root:***wrong***
INFO:root:img:皖A160R9.jpg, res:皖A160R9
INFO:root:ACC = 0.9000
INFO:root:------------------ Inference Time Info ----------------------
INFO:root:inference_time(ms): 1.89
INFO:root:total_time(ms): 2101.56, img_num: 1000
INFO:root:average latency time(ms): 2.10, QPS: 475.837511
...

b. C++示例程序运行(以lprnet_cv_cv_bmrt使用FP32 BModel为例)

文件位置:/examples/simple/lprnet/cpp/lprnet_cv_cv_bmrt

注意:以下命令均在路径 examples/simple/lprnet/cpp/lprnet_cv_cv_bmrt 下运行, 使用不同示例程序需更换至对应文件夹

第一步:编译

make -f Makefile.pcie

第二步:运行

1) 测试单张图片

# 运行命令
./lprnet_cv_cv_bmrt.pcie test ../../data/images/test.jpg ../../data/models/fp32bmodel/lprnet_fp32_1b.bmodel 0

# 程序将输出:
set device id:0
bmcpu init: skip cpu_user_defined
open usercpu.so, init user_cpu_init 
[BMRT][load_bmodel:1018] INFO:Loading bmodel from [../../data/models/fp32bmodel/lprnet_fp32_1b.bmodel]. Thanks for your patience...
[BMRT][load_bmodel:982] INFO:pre net num: 0, load net num: 1
> Load model lprnet successfully
input scale:1.000000
output scale:1.000000
fp32 input
fp32 output
input count:6768
Open /dev/bm-sophon0 successfully, device index = 0, jpu fd = 13, vpp fd = 13
../../data/images/test.jpg pred: 皖A22B20

2) 测试整个文件夹  

# 运行命令
./lprnet_cv_cv_bmrt.pcie test ../../data/images/test/ ../../data/models/fp32bmodel/lprnet_fp32_4b.bmodel 0

# 程序将输出整个文件夹的测试结果:
set device id:0
bmcpu init: skip cpu_user_defined
open usercpu.so, init user_cpu_init 
[BMRT][load_bmodel:1018] INFO:Loading bmodel from [../../data/models/fp32bmodel/lprnet_fp32_4b.bmodel]. Thanks for your patience...
[BMRT][load_bmodel:982] INFO:pre net num: 0, load net num: 1
> Load model lprnet successfully
input scale:1.000000
output scale:1.000000
fp32 input
fp32 output
input count:27072
Open /dev/bm-sophon0 successfully, device index = 0, jpu fd = 14, vpp fd = 14
皖A225J1.jpg pred:皖A225J1
皖AMZ210.jpg pred:皖AMZ210
皖AAS656.jpg pred:皖AAS656
皖AC9165.jpg pred:皖AC9165
苏AP48A8.jpg pred:苏AP48A8
...

3) 测试整个文件夹,并计算准确率  

# 运行命令
./lprnet_cv_cv_bmrt.pcie val ../../data/images/test/ ../../data/models/fp32bmodel/lprnet_fp32_4b.bmodel 0

# 程序将输出整个文件夹的测试结果:

set device id:0
bmcpu init: skip cpu_user_defined
open usercpu.so, init user_cpu_init 
[BMRT][load_bmodel:1018] INFO:Loading bmodel from [../../data/models/fp32bmodel/lprnet_fp32_4b.bmodel]. Thanks for your patience...
[BMRT][load_bmodel:982] INFO:pre net num: 0, load net num: 1
> Load model lprnet successfully
input scale:1.000000
output scale:1.000000
fp32 input
fp32 output
input count:27072
Open /dev/bm-sophon0 successfully, device index = 0, jpu fd = 14, vpp fd = 14
皖A225J1.jpg pred:皖A225J1
皖AMZ210.jpg pred:皖AMZ210
...
皖AL8Y77.jpg pred:皖AL8Y77
皖AL136E.jpg pred:皖AL1365
皖A160R9.jpg pred:皖A160R9
===========================
Acc = 895/1000=0.895000

(6)相关链接

样例开源仓库:https://github.com/sophon-ai-algo/examples

BM1684 BMNNSDK2入门文档:https://sophgo-doc.gitbook.io/bmnnsdk2-bm1684/

编译工具用户开发手册: https://doc.sophgo.com/docs/2.7.0/docs_latest_release/nntc/html/index.html

量化工具用户开发手册: https://doc.sophgo.com/docs/2.7.0/docs_latest_release/calibration-tools/html/index.html

算能量化工具介绍及使用说明:https://www.bilibili.com/video/BV1DA4y1S75p?spm_id_from=333.999.0.0

官网视频教程:https://developer.sophgo.com/site/index/course/all/all.html

官网文档中心:https://developer.sophgo.com/site/index/document/all/all.html

官网下载中心:https://developer.sophgo.com/site/index/material/all/all.html

官网论坛:https://developer.sophgo.com/forum/view/43.html

基于LPRNet的车牌识别算法移植与测试相关推荐

  1. 基于PP-OCR的文字识别算法移植与测试

    课程全程将在SOPHGO(算能)云平台上进行. 本次课程将介绍: 1. SOPHGO(算能)云平台环境搭建 2. PP-OCR的文字识别算法 3. 通过BMNNSDK进行PP-OCR模型转换和量化 4 ...

  2. SE5_基于YOLO3D的目标检测算法移植与测试

    本文档适用于SOPHGO(算能)BM1684-SE5及对应通用云开发空间,主要内容: 注意:由于SOPHGO SE5微服务器的CPU是基于ARM架构,部分步骤将在基于x86架构CPU的开发环境中完成 ...

  3. PCIE_基于YOLO3D的目标检测算法移植与测试

    本文档适用于SOPHGO(算能)BM1684-PCIE及对应通用云开发空间,主要内容: SOPHGO(算能)云平台环境搭建 YOLO3D目标检测算法 Demo文件准备 部署和测试 相关链接 1. SO ...

  4. 基于MiDas的深度估计算法移植与测试

    课程全程将在SOPHGO(算能)云平台上进行. 本次课程将介绍: SOPHGO(算能)PCIE 云平台环境搭建 MiDas的深度估计算法 通过BMNNSDK进行MiDas模型转换 实现算法的移植 部署 ...

  5. 快准狠!Intel论文揭示自家车牌识别算法:LPRNet

    (关注52CV--有价值有深度的公众号~) 来自工业界的最佳实践. 车牌识别是一个老生常谈的话题,在工业界已经得到广泛应用.当深度学习在各种视觉识别任务上刷新更高精度的时候,却常常被认为计算量远大于传 ...

  6. 基于模板匹配的车牌识别算法,输出数字和英文字母

    目录 一.理论基础 二.核心程序 三.仿真结论 一.理论基础 车牌识别是计算机视觉领域中的一个重要问题,其目的是从图像中自动识别出车辆的车牌信息.基于模板匹配的车牌识别算法是一种常见的方法,其基本思想 ...

  7. 智能驾驶 车牌检测和识别(三)《CRNN和LPRNet实现车牌识别(含车牌识别数据集和训练代码)》

    智能驾驶 车牌检测和识别(三)<CRNN和LPRNet实现车牌识别(含车牌识别数据集和训练代码)> 目录 智能驾驶 车牌检测和识别(三)<CRNN和LPRNet实现车牌识别(含车牌识 ...

  8. 基于MATLAB的人脸识别算法的研究

    基于MATLAB的人脸识别算法的研究 作者:lee神 现如今机器视觉越来越盛行,从智能交通系统的车辆识别,车牌识别到交通标牌的识别:从智能手机的人脸识别的性别识别:如今无人驾驶汽车更是应用了大量的机器 ...

  9. 寻找连通域算法_【车牌识别算法】

    车牌识别技术要求能够将运动中的汽车牌照从复杂背景中提取并识别出来,通过车牌提取.图像预处理.特征提取.车牌字符识别等技术,识别车辆牌号.颜色等信息. 目前车牌识别技术主要分为端到端识别与车牌分割识别两 ...

最新文章

  1. 【Spring实战】—— 14 传统的JDBC实现的DAO插入和读取
  2. mysql max_allowed_packet查询和修改
  3. osgi框架和spring区别_BATJ面试必会之 Spring 篇(二)
  4. react学习(68)--ant design inputNumber
  5. MySQL 优化 —— SQL优化概述(优化专题开篇词)
  6. 父类对象由子类实例化【转载】
  7. 解决Eclipse Pydev中import时报错:Unresolved import
  8. clover写入efi_Clover EFI bootloader for Mac(四叶草启动引导工具)
  9. 使用python将视频中的音频分离出来
  10. FMEA软件知识库(FMEAHunter)
  11. 通达OA2019版本全功能
  12. java ad freeradius_freeradius集合mariadb+深信服的AC做实名认证
  13. 离开百度的50余位AI大牛,假如组一个这样的公司……
  14. 平安京因服务器升级维护什么意思,阴阳师4月27日维护更新公告 堀江由衣猫掌柜降临平安京...
  15. java餐厅点餐系统免费_基于jsp的餐厅点餐系统-JavaEE实现餐厅点餐系统 - java项目源码...
  16. 让老公“寒心”的对话 (转)
  17. 平生事,此时凝睇,谁会凭栏意!(2)
  18. 条形码录入测试软件,条码管理:商品条码录入
  19. 有钱人和你想的不一样
  20. 从COMPUTEX 2017看工业4.0与企业数码化

热门文章

  1. 数据挖掘之关联规则分析
  2. Python_静态方法
  3. SpringBoot 整合Activiti(二)——流程审批完整示例
  4. 燕山大学校园网自动登录问题解决方案
  5. 通过Java生成.pfx(.p12)证书文件
  6. AspectJ的Execution表达式
  7. 集群、分布式、负载均衡区别(转)
  8. 转换 wav,ape,flac 音乐为 mp3,m4a(mp4) 格式
  9. C语言基础之32个关键字
  10. RTL8370N 8口千兆交换机 PCB图纸方案资料 和芯片的datasheet