RKNN模型部署(3)—— 模型转换与测试

这篇具有很好参考价值的文章主要介绍了RKNN模型部署(3)—— 模型转换与测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


1 常用 API 介绍

1.1 rknn初始化及释放

初始化函数:

rknn = RKNN(verbose,verbose_file)

初始化RKNN对象时,可以设置verbose和verbose_file参数,以打印详细的日志信息。

参数 解析
verbose 指定是否要在屏幕上打印详细日志信息
verbose_file 如果verbose参数为True,日志信息将写到该参数指定的文件中,一般将verbose设置为True,verbose_file不设置,将日志显示到终端上。

1.2 rknn模型配置

转化模型之前需要先配置RKNN-Toolkit。使用到的API是config,使用示例如下:

ret = rknn.config(
        reorder_channel='2 1 0',
        mean_values=[123.675, 116.28, 103.53],
         std_values=[58.395, 57.12, 57.375], 
        optimization_level=3,
        target_platform='rk1808,
        quantize_input_node=False
        output_optimize=1,
        force_builtin_perm=False,
)
参数 解析
reorder_channel 对输入图像RGB通道的调整,’ 0 1 2 ’ 表示不做调整,此处若设 ‘2 1 0’,那么在前处理时就不用调整通道,否则就重复调整了
mean_values 输入的均值,参数是一个列表。表示输入图像的三个通道值分别减去[123.675, 116.28, 103.53]
std_values 输入的归一化值,参数是一个列表。表示输入图像的三个通道值分别减去[123.675, 116.28, 103.53]再分别除以[58.395, 57.12, 57.375]
optimization_level 设置代码的优化等级,0:不优化;1:Fast;2:Faster; 3:Fastest
target_platform 运行平台,这里用到的是rk1808
quantize_input_node ***
output_optimize ***
force_builtin_perm ***

1.3 PT模型加载

将Pytorch进行处理,API是load_pytorch,示例:

ret = rknn.load_pytorch(model=pt_model, inputs=['Preprocessor/sub'], outputs=['concat_1', 'concat_2'],  input_size_list=[[3,416, 416]])
参数 解析
pt_model 是yolox算法(Pytorch开发)模型的路径
inputs 模型的输入节点(操作数名),按照官方例子写[‘Preprocessor/sub’]
outputs 模型的输出节点(操作数名),按照官方例子写[‘concat’, ‘concat_1’]
input_size_list 每个输入节点对应的图片的尺寸和通道数

1.4 rknn模型转化

   将Pytorch模型转化为rknn模型,需要使用的API是build,示例:

ret = rknn.build(do_quantization, dataset, pre_compile)

这个就是将Pytorch模型转化成rknn。

参数 解析
do_quantization 是否对模型进行量化,值为True 或False
dataset 量化校正数据的数据集。可以理解为用来进行测试的图像路径名的集合。每一个图像路径放一行。我这里就用一个图像进行测试。所以dataset.txt内如为 road.bmp
pre_compile 预编译开关,如果设置成 True,可以减小模型大小,及模型在硬件设备上的首次启动速度。但是打开这个开关后,构建出来的模型就只能在硬件平台上运行,无法通过模拟器进行推理或性能评估。如果硬件有更新,则对应的模型要重新构建

1.5 模型导出

   模型的导出需要使用export_rknn函数,参数为导出模型所在的路径,后缀名为‘.rknn’。

ret = rknn.export_rknn('./rknn_model.rknn')

1.6 rknn运行环境初始化

ret = rknn.init_runtime(target='rk1808', device_id=DEVICE_ID, perf_debug=True,eval_mem=True)
参数 解析
target 目标平台,这里是rk1808
device_id 设备的ID号
perf_debug 评估模型使用时间,默认为False
eval_mem 评估模型使用的内存,这两个配置为True后,才可以使用模型评估相关的API

1.7rknn模型推理

outputs = rknn.inference(inputs=[img],data_type,data_format,inputs_pass_through)
参数 解析
img: cv2读取、处理好的图像
inputs 待推理的输入,如经过 cv2 处理的图片。格式是 ndarray list
data_type 输入数据的类型,可填以下值: ’float32’, ‘float16’, ‘int8’, ‘uint8’, ‘int16’。默认值为’uint8’
data_format 数据模式,可以填以下值: “nchw”, “nhwc”。默认值为’nhwc’。这两个的不同之处在于 channel 放置的位置
inputs_pass_through 将输入透传给 NPU 驱动。非透传模式下,在将输入传给 NPU 驱动之前,工具会对输入进行减均值、除方差等操作;而透传模式下,不会做这些操作。这个参数的值是一个数组,比如要透传 input0,不透彻 input1,则这个参数的值为[1,0]。默认值为 None,即对所有输入都不透传

1.8 rknn性能评估

ret = rknn.eval_perf(inputs=[img], is_print=True)
memory_detail = rknn.eval_memory()

2 pth2pt

   Pytorch训练的模型转换成RKNN,只能通过 .pt 转成 .rknn ,且需通过torch.jit.trace()函数保存的 .pt

目前只支持 torch.jit.trace 导出的模型。torch.save 接口仅保存权重参数字典,缺乏网络结构信息,故无法被正常导入并转成 RKNN 模型。

import torch
import torchvision
from nets.yolo2rknn import YoloBody

model_path  = 'model_data/7150_nano.pth'   # 训练后保存的模型文件
num_classes = 3                                            # 检测类别数
phi         = 'nano'                                            # 模型类型

model = YoloBody(num_classes, phi)             #导入模型
#device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#model.load_state_dict(torch.load(model_path, map_location=device)) #初始化权重
model.load_state_dict(torch.load(model_path))
model.eval()

example = torch.rand(1, 3, 416, 416)
traced_script_module = torch.jit.trace(model, example)
traced_script_module.save("model_data/MySelf_Nano.pt")

3 pt2rknn

3.1 界面转换

   在终端中输入:python3 -m rknn.bin.visualization ,然后出现如下界面:

   根据自己原始模型格式选择,这里的原始模型是onnx模型,所以选择onnx,进去后各个选项的意思自己翻译过来对照一下不难懂(rknn toolkit 1.7.1版本界面好像是中文),需要注意的是预编译选项(Whether To Enable Pre-Compile),预编译 RKNN 模型可以减少模型初始化时间,但是无法通过模拟器进行推理或性能评估。

3.2 代码转换

模型转换时API调用流程如下:
RKNN模型部署(3)—— 模型转换与测试
   在Ubuntu的虚拟环境RKNN中进行转换,其中特别需要注意的是rknn.config()中参数的设置,转换代码如下:

import os
import numpy as np
from rknn.api import RKNN

pt_model        = '/home/liu/RKNN/model/myself_nano.pt'
rknn_model      = '/home/liu/RKNN/model/myself_nano.rknn'
DATASET         = '/home/liu/RKNN/model/JPEGImages.txt'
QUANTIZE_ON     = False        # 是否对模型进行量化

if __name__ == '__main__':
    # Create RKNN object
    rknn = RKNN(verbose=False)

    if not os.path.exists(pt_model):
        print('model not exist')
        exit(-1)
    _force_builtin_perm = False
    # pre-process config
    print('--> Config model')
    rknn.config(
                reorder_channel='2 1 0',
                mean_values=[[123.675, 116.28, 103.53]],
                std_values=[[58.395, 57.12, 57.375]],
                optimization_level=3,
                target_platform = 'rk1808',
                # target_platform='rv1109',
                quantize_input_node= QUANTIZE_ON,
                batch_size = 200,
                output_optimize=1,
                force_builtin_perm=_force_builtin_perm
               )

    print('done')

    # Load PT model
    print('--> Loading model')
    ret = rknn.load_pytorch(model=pt_model, input_size_list=[[3,416, 416]])
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')

    # Build model
    print('--> Building model')
    ret = rknn.build(do_quantization=QUANTIZE_ON, dataset=DATASET, pre_compile=False)
    if ret != 0:
        print('Build model failed!')
        exit(ret)
    print('done')

    # Export RKNN model
    print('--> Export RKNN model')
    ret = rknn.export_rknn(rknn_model)
    if ret != 0:
        print('Export rknn failed!')
        exit(ret)
    print('done')

    exit(0)

    #rknn.release()

转换后得到MySelf_Nano.rknn模型。

4 测试

4.1 模型推理

模型推理时API调用流程如下:
RKNN模型部署(3)—— 模型转换与测试
   RKNN-Toolkit 通过 PC 的 USB 连接到开发板硬件,将构建或导入的 RKNN 模型传到 RK1808 上运行,并从 RK1808 上获取推理结果、性能信息。使用 RKNN 模型时请先将设备的 NPU 驱动更新至最新的 release 版本。

请执行以下步骤:

1、确保开发板的 USB OTG 连接到 PC,并且 ADB 能够正确识别到设备,即在 PC 上执行adb devices -l命令能看到目标设备。
2、调用init_runtime 接口初始化运行环境时需要指定 target 参数和 device_id 参数。其中 target 参数表明硬件类型, 选值为 rk1808, 当 PC 连接多个设备时,还需要指定 device_id 参数,即设备编号,可以通过adb devics命令查看,举例如下:

$ adb devices
List of devices attached 
0123456789ABCDEF        device

即可以改为:

ret = rknn.init_runtime(target='rk1808', device_id='0123456789ABCDEF')

3、运行测试代码

   该测试代码包括前处理、后处理,前处理与后处理都与训练时的处理尽量保持一致,需要注意的是,torch中有些函数与numpy的函数略有不同,若检测的Bbox存在不准确的情况,可能是其中一些函数造成的。

例如:

  • torch.stack((grid_x, grid_y), 2) 改成 np.transpose(np.stack((grid_x, grid_y), 2), (1, 0, 2))
  • prediction.new(prediction.shape) 改成 np.copy(prediction)
  • class_conf, class_pred = torch.max(image_pred[:, 5:5 + num_classes], 1, keepdim=True) 改成
    class_conf = np.max(image_pred[:, 5:5 + num_classes], axis=1, keepdims=True)
    class_pred = np.expand_dims(np.argmax(image_pred[:, 5:5 + num_classes], axis=1), axis=1)
  • boxes.batched_nms() 改成 nms_boxes()
import os
from re import T
import numpy as np
import cv2
import time
from rknn.api import RKNN
mode            = 'image'     # 模式:image、video,分别为用图片测试和用摄像头测试
#pt_model        = '/home/liu/RKNN/model/myself_nano.pt'
rknn_model      = '/home/liu/RKNN/model/myself_nano.rknn'
img_path        = '/home/liu/RKNN/model/JPEGImages/04245.jpg'
#DATASET         = '/home/liu/RKNN/model/JPEGImages.txt'
#QUANTIZE_ON     = False        # 是否对模型进行量化
box_thresh      = 0.7           # 置信度 阈值
nms_thresh      = 0.3           # nms 阈值
input_shape     = [416, 416]
letterbox_image = True          # resize是否保持原长宽比例

num_classes     = 3
class_names     = ("iris", "pipul", "shut-eye")
#===================================================================
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
def nms_boxes(boxes, scores):
    x = boxes[:, 0]
    y = boxes[:, 1]
    w = boxes[:, 2] - boxes[:, 0]
    h = boxes[:, 3] - boxes[:, 1]
    areas = w * h
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        xx1 = np.maximum(x[i], x[order[1:]])
        yy1 = np.maximum(y[i], y[order[1:]])
        xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])
        yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])
        w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)
        h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)
        inter = w1 * h1
        ovr = inter / (areas[i] + areas[order[1:]] - inter)
        inds = np.where(ovr <= nms_thresh)[0]
        order = order[inds + 1]
    keep = np.array(keep)
    return keep
def yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape, letterbox_image):
    box_yx = box_xy[..., ::-1]
    box_hw = box_wh[..., ::-1]
    input_shape = np.array(input_shape)
    image_shape = np.array(image_shape)
    if letterbox_image:
        new_shape = np.round(image_shape * np.min(input_shape/image_shape))
        offset  = (input_shape - new_shape)/2./input_shape
        scale   = input_shape/new_shape
        box_yx  = (box_yx - offset) * scale
        box_hw *= scale
    box_mins    = box_yx - (box_hw / 2.)
    box_maxes   = box_yx + (box_hw / 2.)
    boxes  = np.concatenate([box_mins[..., 0:1], box_mins[..., 1:2], box_maxes[..., 0:1], box_maxes[..., 1:2]], axis=-1)
    boxes *= np.concatenate([image_shape, image_shape], axis=-1)
    return boxes
def decode_outputs(outputs, input_shape):
    # [1, 8, 52, 52]
    # [1, 8, 26, 26]
    # [1, 8, 13, 13]
    grids   = []
    strides  = []
    hw      = [x.shape[-2:] for x in outputs]  # [[52,52] ,[26,26], [13,13]]
    outputs = np.concatenate([x.reshape(1, 8,-1) for x in outputs],axis=2)
    outputs = np.transpose(outputs,(0,2,1))
    outputs[:, :, 4:] = sigmoid(outputs[:, :, 4:])
    for h, w in hw: 
        # [[52,52] ,[26,26], [13,13]]
        grid_y, grid_x  = np.meshgrid([np.arange(0, h, 1.)], [np.arange(0, w, 1.)])
        grid            = np.transpose(np.stack((grid_x, grid_y), 2), (1, 0, 2)).reshape(1, -1, 2)
        shape           = grid.shape[:2]
        grids.append(grid)
        strides.append(np.full((shape[0], shape[1], 1), input_shape[0] / h))
    grids               = np.concatenate(grids, axis=1)
    strides             = np.concatenate(strides, axis=1)
    outputs[..., :2]    = (outputs[..., :2] + grids) * strides
    outputs[..., 2:4]   = np.exp(outputs[..., 2:4]) * strides
    outputs[..., [0,2]] = outputs[..., [0,2]] / input_shape[1]
    outputs[..., [1,3]] = outputs[..., [1,3]] / input_shape[0]
    return outputs
def non_max_suppression(prediction, num_classes, input_shape, image_shape, letterbox_image, conf_thres=0.5, nms_thres=0.4):
    #box_corner          = prediction.copy()
    box_corner          = np.copy(prediction)   # [xc,yc,w,h]
    box_corner[:, :, 0] = prediction[:, :, 0] - prediction[:, :, 2] / 2   
    box_corner[:, :, 1] = prediction[:, :, 1] - prediction[:, :, 3] / 2
    box_corner[:, :, 2] = prediction[:, :, 0] + prediction[:, :, 2] / 2
    box_corner[:, :, 3] = prediction[:, :, 1] + prediction[:, :, 3] / 2
    prediction[:, :, :4] = box_corner[:, :, :4]   # [left,top,right,botton]
    output = [None for _ in range(len(prediction))]
    for i, image_pred in enumerate(prediction):
        class_conf = np.max(image_pred[:, 5:5 + num_classes], axis=1, keepdims=True)
        class_pred = np.expand_dims(np.argmax(image_pred[:, 5:5 + num_classes], axis=1), axis=1)
        conf_mask = (image_pred[:, 4] * class_conf[:, 0] >= conf_thres).squeeze()
        if not image_pred.shape[0]:
            continue
        detections = np.concatenate((image_pred[:, :5], class_conf, class_pred), axis=1)
        detections = detections[conf_mask]
        
        nms_out_index = nms_boxes(detections[:, :4], detections[:, 4] * detections[:, 5])

        if not nms_out_index.shape[0]:
            continue

        output[i]   = detections[nms_out_index]
      
        if output[i] is not None:   # [left,top,right,botton]
            box_xy, box_wh      = (output[i][:, 0:2] + output[i][:, 2:4])/2, output[i][:, 2:4] - output[i][:, 0:2]
            output[i][:, :4]    = yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape, letterbox_image)
    return output

def detect(inputs, image_shape):
    # input: [1, 3 * h*w, 8]
    outputs = decode_outputs(inputs, input_shape)
    results = non_max_suppression(outputs, num_classes, input_shape, 
                image_shape, letterbox_image, conf_thres = box_thresh, nms_thres = nms_thresh)

    if results[0] is None:
        return None, None, None
    label   = np.array(results[0][:, 6], dtype = 'int32')
    conf    = results[0][:, 4] * results[0][:, 5]
    boxes   = np.array(results[0][:, :4], dtype = 'int32')
    return label, conf, boxes

def draw(image, image_shape, label, conf, boxes):
    for i, c in list(enumerate(label)):
        predicted_class = class_names[int(c)]
        box             = boxes[i]
        score           = conf[i]
        top, left, bottom, right = box
        top     = max(0, np.floor(top).astype('int32'))
        left    = max(0, np.floor(left).astype('int32'))
        bottom  = min(image_shape[1], np.floor(bottom).astype('int32'))
        right   = min(image_shape[0], np.floor(right).astype('int32'))
        label = '{} {:.2f}'.format(predicted_class, score)
        for box, score, cl in zip(boxes, scores, classes):
            top, left, bottom, right = box
            top = int(top)
            left = int(left)
            right = int(right)
            bottom = int(bottom)

            center_coordinates = ((right+left)//2, (bottom+top)//2) # 椭圆中心
            axesLength = ((right-left)//2, (bottom-top)//2)                   #(长轴长度,短轴长度)
            cv2.ellipse(image,center_coordinates, axesLength, 0, 0, 360, (0,0,255), 2)
            #cv2.rectangle(image, (left, top), (right, bottom), (255, 0, 0), 2)
            cv2.putText(image, '{0} {1:.2f}'.format(class_names[cl], score),
                        (left, top - 6),
                        cv2.FONT_HERSHEY_SIMPLEX,
                        0.6, (255, 0, 0), 2)

def resize_image(image, letterbox_image, size = input_shape):
    ih, iw  = image.shape[0:2]    # 实际尺寸
    w, h    = size                # [416, 416]
    if letterbox_image:
        scale   = min(w/iw, h/ih)
        nw      = int(iw * scale)   # resize后的尺寸
        nh      = int(ih * scale)

        image   = cv2.resize(image,(nw,nh), interpolation=cv2.INTER_LINEAR)
        top, bottom = (h-nh)//2 , (h-nh)//2
        left, right = (w-nw)//2 , (w-nw)//2
        new_image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(128,128,128))
    else:
        new_image = cv2.resize(image,(w,h), interpolation=cv2.INTER_LINEAR)
    return new_image

if __name__ == '__main__':
    # Create RKNN object
    rknn = RKNN(verbose=False)
    _force_builtin_perm = False
    ret = rknn.load_rknn(path=rknn_model)
    if ret!=0:
        print('Load RKNN model failed !')
        exit(ret)
    # init runtime environment
    print('--> Init runtime environment')
    ret = rknn.init_runtime()
    # ret = rknn.init_runtime('rv1109', device_id='1109')
    # ret = rknn.init_runtime('rk1808', device_id='1808')
    if ret != 0:
        print('Init runtime environmentfailed')
        exit(ret)
    print('done')

    if mode == 'video':
        # input video
        capture = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
        fps = 0.0
        while(True):
            t1 = time.time()
            # 读取某一帧
            ref,frame=capture.read()
            image_shape = np.array(np.shape(frame)[0:2])
            # 格式转变,BGRtoRGB
            #frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)

            # Inference
            print('--> Running model')
            outputs = rknn.inference(inputs=[frame], inputs_pass_through=[0 if not _force_builtin_perm else 1])
            classes, scores, boxes = detect(outputs, image_shape)

            #frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            if boxes is not None:
                draw(frame, image_shape, classes, scores, boxes)
            
            fps  = ( fps + (1./(time.time()-t1)) ) / 2
            print("fps= %.2f"%(fps))
            frame = cv2.putText(frame, "fps= %.2f"%(fps), (0, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
            
            cv2.imshow("video",frame)
            c= cv2.waitKey(1) & 0xff 
            if c==27:
                capture.release()
                break
        capture.release()
        cv2.destroyAllWindows()

    elif mode == 'image':

        # input images
        img         = cv2.imread(img_path)
        image_shape = np.array(np.shape(img)[0:2])
        img_1 = img
        #img         = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img_data    = resize_image(img, letterbox_image, input_shape)
        
        # Inference
        print('--> Running model')
        outputs = rknn.inference(inputs=[img_data], inputs_pass_through=[0 if not _force_builtin_perm else 1])
        # type : ndarray
        # print('outputs[0]:', outputs[0])   
        # [1, 8, 52, 52]
        # [1, 8, 26, 26]
        # [1, 8, 13, 13]

        classes, scores, boxes = detect(outputs, image_shape)
        print('classes:', classes)
        print('scores:' , scores)
        print('boxes:'  , boxes)
        
        #img_1 = cv2.cvtColor(img,cv2.COLOR_RGB2BGR)
        if boxes is not None:
            draw(img_1, image_shape, classes, scores, boxes)
        cv2.imshow("post process result", img_1)
        cv2.waitKeyEx(0)

    exit(0)
    #rknn.release()

4.2 量化后检测不出目标或精度大幅下降

4.2.1 模型训练注意事项

1、卷积核设置
   推荐在设计的时候尽量使用 3x3 的卷积核,这样可以实现最高的乘加运算单元(MAC)利用率,使得 NPU 的性能最佳。
NPU 也可以支持大尺寸的卷积核。支持的最小卷积核为[1],最大值为[11 * stride - 1]。同时 NPU 也支持非对称卷积核,不过会增加一些额外的计算开销。

2、结构融合设计
   NPU 会对卷积后面的 ReLU 和 MAX Pooling 进行融合的优化操作,能在运行中减少计算和带宽开销。所以在搭建网络时,能针对这一特性,进行设计。
RKNN模型部署(3)—— 模型转换与测试
   模型量化后,卷积算子与下一层的 ReLU 算子可以被合并。另外为了确保 Max Pooling算子也能被合并加速,请在设计网络时参考以下几点:

  • pool size 必须是 2x2 或者 3x3,而步长 stride=2;
  • 2x2 池化的输入图片尺寸必须是偶数,而且不能有填充;
  • 3x3 池化的输入图片尺寸必须是非 1 的奇数,而且不能有填充;
  • 如果是 3x3 的池化,则水平输入大小必须小于 64(8-bit 模型)或 32(16-bit 模型)。

3、2D卷积和Depthwise卷积
   NPU 支持常规 2D 卷积和 Depthwise 卷积加速。由于 Depthiwise 卷积特定的结构,使得它对于量化(int8)模型不太友好,而 2D 卷积的优化效果更好。所以设计网络时建议尽量使用2D 卷积。如果必须使用 Depthwise 卷积,建议按照下面的规则进行修改,能提高量化后模型的精度:
RKNN模型部署(3)—— 模型转换与测试

  • 如果网络中的激活函数使用的是 Silu,建议将其都改为 ReLU;
  • 在 Depthwise 卷积层的 BN 层和激活层,建议去除;
  • 在训练时,针对 Depthwise 卷积层,对它的权重进行 L2 正则化。

4.2.2 RKNN量化过程使用的Dataset

   RKNN Toolkit 量化过程中,需要根据数据的最大值、最小值,找到合适的量化参数。
此时需要使用 dataset 里的输入进行推理,获取每一层的输入、输出数据,再根据这些数据计算每一层输入、输出的量化参数。
   基于这个原因,校准数据集里的数据最好是从训练集或验证集中取一个有代表性的子集,建议数量在 100~500 张之间。

4.2.3 RKNN量化过程的参数设置

1、使用 RKNN Toolkit 导入量化后的模型时使 rknn.build(do_quantization=False);
2、设置 mean_values/std_values 参数,确保其和训练模型时使用的参数相同;
3、务必确保测试时输入图像通道顺序为 R,G,B(不论训练时使用的图像通道顺序如何,使用 RKNN 做测试时都按 R,G,B 输入);
4、在rknn.config 函数里面设置 reorder_channel 参数,’0 1 2’代表 RGB, ’2 1 0’代表 BGR,务必和训练时候图像通道顺序一致;
5、使用多张图进行量化校准,确保量化精度稳定;
6、在 rknn.config 中设置 batch_size 参数 (建议设置 batch_size = 200) 并且在 dataset.txt 中给出大于 200 张图像路径用于量化;如果内存不够,可以设置 batch_size =10, epochs=20 代替 batch_size = 200 进行量化。文章来源地址https://www.toymoban.com/news/detail-421282.html

到了这里,关于RKNN模型部署(3)—— 模型转换与测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • yolov5-6.0项目部署+自用Pytorch模型转换rknn模型并在RK3568 linux(Debian)平台上使用qt部署使用NPU推理加速摄像头目标识别详细新手教程

    1 我们打开yolov的官网,Tags选择6.0版本 2. 下载该压缩包并解压到工程目录下 3. 我们这里使用pycharm,专门针对python的IDE,用起来非常方便,下载方式就是官网直接下载,用的是社区版 4. 我们需要安装环境,这里我推荐安装Anaconda在电脑上,这是一个非常方便的包管理工具,可

    2024年02月05日
    浏览(65)
  • yolov8n 瑞芯微RKNN和地平线Horizon芯片仿真测试部署,部署工程难度小、模型推理速度快

      特别说明:参考官方开源的yolov8代码、瑞芯微官方文档、地平线的官方文档,如有侵权告知删,谢谢。   模型和完整仿真测试代码,放在github上参考链接 模型和代码。   因为之前写了几篇yolov8模型部署的博文,存在两个问题:部署难度大、模型推理速度慢。该篇解

    2024年02月01日
    浏览(49)
  • 【运维知识高级篇】一篇文章带你搞懂Git!(Git安装+全局配置+Git初始化代码仓库+Git四大区域+Git四种状态+Git常用命令+Git分支+Git测试代码回滚)

    版本流程控制系统(version control system)是一种记录一个或若干个文件内容变化,以便将来查阅特定版本内容情况的系统,它会记录文件的所有历史变化,我们可以随时恢复到任何一个历史状态,同时支持多人协作开发。 目录 常见的版本管理工具 Git安装与全局配置 Git初始化

    2024年02月02日
    浏览(62)
  • NumPy(1)-常用的初始化方法

    NumPy是Python中科学计算的基础包,它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种API,有包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。 功能强

    2024年02月16日
    浏览(40)
  • 【随机种子初始化】一个神经网络模型初始化的大坑

    半年前写了一个模型,取得了不错的效果(简称项目文件1),于是整理了一番代码,保存为了一个新的项目(简称项目文件2)。半年后的今天,我重新训练这个整理过的模型,即项目文件2,没有修改任何的超参数,并且保持完全一致的随机种子,但是始终无法完全复现出半

    2024年02月09日
    浏览(66)
  • 模型部署——rknn-toolkit-lite2部署RKNN模型到开发板上(python版)

    欢迎学习RKNN系列相关文章,从模型转换、精度分析,评估到部署,推荐好资源: 一、Ubuntu系统上安装rknn-toolkit 二、使用rknn-toolkit将Pytorch模型转为RKNN模型 三、RKNN模型的评估和推理测试 四、RKNN模型量化精度分析及混合量化提高精度 五、RKNN模型性能评估和内存评估 六、rkn

    2024年04月11日
    浏览(46)
  • 初始化交换机的密码的方法介绍

    1、断开交换机的电源并重新给交换机加电,在给交换机加电的同时按住交换机前面板上的“模式(Mode)”按钮几秒钟,仔细观察超级终端程序中显示的交换机启动信息。 2、待出现交换机提示符switch:后,输入flash_init命令。 3、待上述命令执行完成后,输入load_helper命令。 4、待

    2024年02月05日
    浏览(41)
  • 【nginx实践连载-1】安装部署配置初始化

    要在Ubuntu上安装、部署和配置Nginx,可以按照以下步骤进行操作: 步骤1:安装Nginx 打开终端(Terminal)。 运行以下命令更新软件包索引: 安装Nginx: 步骤2:启动Nginx服务 安装完成后,Nginx服务将会自动启动。您可以使用以下命令检查Nginx服务状态: 如果Nginx未启动,您可以使

    2024年02月20日
    浏览(38)
  • rv1109/1126 rknn 模型部署过程

    rv1109/1126是瑞芯微出的嵌入式AI芯片,带有npu, 可以用于嵌入式人工智能应用。算法工程师训练出的算法要部署到芯片上,需要经过模型转换和量化,下面记录一下整个过程。 模型量化需要安装rk的工具包: rockchip-linux/rknn-toolkit (github.com) 版本要根据开发板的固件支持程度来,

    2024年02月14日
    浏览(38)
  • 深入理解 Flink(八)Flink Task 部署初始化和启动详解

    核心入口: 部署 Task 链条:JobMaster -- DefaultScheduler -- SchedulingStrategy -- ExecutionVertex -- Execution -- RPC请求 -- TaskExecutor JobMaster 向 TaskExecutor 发送 submitTask() 的 RPC 请求,用来部署 StreamTask 运行。TaskExecutor 接收到 JobMaster 的部署 Task 运行的 RPC 请求的时候,就封装了一个 Task 抽象,然

    2024年01月17日
    浏览(77)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包