国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

RKNN模型部署(3)—— 模型轉(zhuǎn)換與測試

這篇具有很好參考價值的文章主要介紹了RKNN模型部署(3)—— 模型轉(zhuǎn)換與測試。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。


1 常用 API 介紹

1.1 rknn初始化及釋放

初始化函數(shù):

rknn = RKNN(verbose,verbose_file)

初始化RKNN對象時,可以設(shè)置verbose和verbose_file參數(shù),以打印詳細(xì)的日志信息。

參數(shù) 解析
verbose 指定是否要在屏幕上打印詳細(xì)日志信息
verbose_file 如果verbose參數(shù)為True,日志信息將寫到該參數(shù)指定的文件中,一般將verbose設(shè)置為True,verbose_file不設(shè)置,將日志顯示到終端上。

1.2 rknn模型配置

轉(zhuǎn)化模型之前需要先配置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,
)
參數(shù) 解析
reorder_channel 對輸入圖像RGB通道的調(diào)整,’ 0 1 2 ’ 表示不做調(diào)整,此處若設(shè) ‘2 1 0’,那么在前處理時就不用調(diào)整通道,否則就重復(fù)調(diào)整了
mean_values 輸入的均值,參數(shù)是一個列表。表示輸入圖像的三個通道值分別減去[123.675, 116.28, 103.53]
std_values 輸入的歸一化值,參數(shù)是一個列表。表示輸入圖像的三個通道值分別減去[123.675, 116.28, 103.53]再分別除以[58.395, 57.12, 57.375]
optimization_level 設(shè)置代碼的優(yōu)化等級,0:不優(yōu)化;1:Fast;2:Faster; 3:Fastest
target_platform 運行平臺,這里用到的是rk1808
quantize_input_node ***
output_optimize ***
force_builtin_perm ***

1.3 PT模型加載

將Pytorch進(jìn)行處理,API是load_pytorch,示例:

ret = rknn.load_pytorch(model=pt_model, inputs=['Preprocessor/sub'], outputs=['concat_1', 'concat_2'],  input_size_list=[[3,416, 416]])
參數(shù) 解析
pt_model 是yolox算法(Pytorch開發(fā))模型的路徑
inputs 模型的輸入節(jié)點(操作數(shù)名),按照官方例子寫[‘Preprocessor/sub’]
outputs 模型的輸出節(jié)點(操作數(shù)名),按照官方例子寫[‘concat’, ‘concat_1’]
input_size_list 每個輸入節(jié)點對應(yīng)的圖片的尺寸和通道數(shù)

1.4 rknn模型轉(zhuǎn)化

?? 將Pytorch模型轉(zhuǎn)化為rknn模型,需要使用的API是build,示例:

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

這個就是將Pytorch模型轉(zhuǎn)化成rknn。

參數(shù) 解析
do_quantization 是否對模型進(jìn)行量化,值為True 或False
dataset 量化校正數(shù)據(jù)的數(shù)據(jù)集??梢岳斫鉃橛脕磉M(jìn)行測試的圖像路徑名的集合。每一個圖像路徑放一行。我這里就用一個圖像進(jìn)行測試。所以dataset.txt內(nèi)如為 road.bmp
pre_compile 預(yù)編譯開關(guān),如果設(shè)置成 True,可以減小模型大小,及模型在硬件設(shè)備上的首次啟動速度。但是打開這個開關(guān)后,構(gòu)建出來的模型就只能在硬件平臺上運行,無法通過模擬器進(jìn)行推理或性能評估。如果硬件有更新,則對應(yīng)的模型要重新構(gòu)建

1.5 模型導(dǎo)出

?? 模型的導(dǎo)出需要使用export_rknn函數(shù),參數(shù)為導(dǎo)出模型所在的路徑,后綴名為‘.rknn’。

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

1.6 rknn運行環(huán)境初始化

ret = rknn.init_runtime(target='rk1808', device_id=DEVICE_ID, perf_debug=True,eval_mem=True)
參數(shù) 解析
target 目標(biāo)平臺,這里是rk1808
device_id 設(shè)備的ID號
perf_debug 評估模型使用時間,默認(rèn)為False
eval_mem 評估模型使用的內(nèi)存,這兩個配置為True后,才可以使用模型評估相關(guān)的API

1.7rknn模型推理

outputs = rknn.inference(inputs=[img],data_type,data_format,inputs_pass_through)
參數(shù) 解析
img: cv2讀取、處理好的圖像
inputs 待推理的輸入,如經(jīng)過 cv2 處理的圖片。格式是 ndarray list
data_type 輸入數(shù)據(jù)的類型,可填以下值: ’float32’, ‘float16’, ‘int8’, ‘uint8’, ‘int16’。默認(rèn)值為’uint8’
data_format 數(shù)據(jù)模式,可以填以下值: “nchw”, “nhwc”。默認(rèn)值為’nhwc’。這兩個的不同之處在于 channel 放置的位置
inputs_pass_through 將輸入透傳給 NPU 驅(qū)動。非透傳模式下,在將輸入傳給 NPU 驅(qū)動之前,工具會對輸入進(jìn)行減均值、除方差等操作;而透傳模式下,不會做這些操作。這個參數(shù)的值是一個數(shù)組,比如要透傳 input0,不透徹 input1,則這個參數(shù)的值為[1,0]。默認(rèn)值為 None,即對所有輸入都不透傳

1.8 rknn性能評估

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

2 pth2pt

?? Pytorch訓(xùn)練的模型轉(zhuǎn)換成RKNN,只能通過 .pt 轉(zhuǎn)成 .rknn ,且需通過torch.jit.trace()函數(shù)保存的 .pt 。

目前只支持 torch.jit.trace 導(dǎo)出的模型。torch.save 接口僅保存權(quán)重參數(shù)字典,缺乏網(wǎng)絡(luò)結(jié)構(gòu)信息,故無法被正常導(dǎo)入并轉(zhuǎn)成 RKNN 模型。

import torch
import torchvision
from nets.yolo2rknn import YoloBody

model_path  = 'model_data/7150_nano.pth'   # 訓(xùn)練后保存的模型文件
num_classes = 3                                            # 檢測類別數(shù)
phi         = 'nano'                                            # 模型類型

model = YoloBody(num_classes, phi)             #導(dǎo)入模型
#device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#model.load_state_dict(torch.load(model_path, map_location=device)) #初始化權(quán)重
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 界面轉(zhuǎn)換

?? 在終端中輸入:python3 -m rknn.bin.visualization ,然后出現(xiàn)如下界面:

?? 根據(jù)自己原始模型格式選擇,這里的原始模型是onnx模型,所以選擇onnx,進(jìn)去后各個選項的意思自己翻譯過來對照一下不難懂(rknn toolkit 1.7.1版本界面好像是中文),需要注意的是預(yù)編譯選項(Whether To Enable Pre-Compile),預(yù)編譯 RKNN 模型可以減少模型初始化時間,但是無法通過模擬器進(jìn)行推理或性能評估。

3.2 代碼轉(zhuǎn)換

模型轉(zhuǎn)換時API調(diào)用流程如下:
RKNN模型部署(3)—— 模型轉(zhuǎn)換與測試
?? 在Ubuntu的虛擬環(huán)境RKNN中進(jìn)行轉(zhuǎn)換,其中特別需要注意的是rknn.config()中參數(shù)的設(shè)置,轉(zhuǎn)換代碼如下:

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        # 是否對模型進(jìn)行量化

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()

轉(zhuǎn)換后得到MySelf_Nano.rknn模型。

4 測試

4.1 模型推理

模型推理時API調(diào)用流程如下:
RKNN模型部署(3)—— 模型轉(zhuǎn)換與測試
?? RKNN-Toolkit 通過 PC 的 USB 連接到開發(fā)板硬件,將構(gòu)建或?qū)氲?RKNN 模型傳到 RK1808 上運行,并從 RK1808 上獲取推理結(jié)果、性能信息。使用 RKNN 模型時請先將設(shè)備的 NPU 驅(qū)動更新至最新的 release 版本。

請執(zhí)行以下步驟:

1、確保開發(fā)板的 USB OTG 連接到 PC,并且 ADB 能夠正確識別到設(shè)備,即在 PC 上執(zhí)行adb devices -l命令能看到目標(biāo)設(shè)備。
2、調(diào)用init_runtime 接口初始化運行環(huán)境時需要指定 target 參數(shù)和 device_id 參數(shù)。其中 target 參數(shù)表明硬件類型, 選值為 rk1808, 當(dāng) PC 連接多個設(shè)備時,還需要指定 device_id 參數(shù),即設(shè)備編號,可以通過adb devics命令查看,舉例如下:

$ adb devices
List of devices attached 
0123456789ABCDEF        device

即可以改為:

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

3、運行測試代碼

?? 該測試代碼包括前處理、后處理,前處理與后處理都與訓(xùn)練時的處理盡量保持一致,需要注意的是,torch中有些函數(shù)與numpy的函數(shù)略有不同,若檢測的Bbox存在不準(zhǔn)確的情況,可能是其中一些函數(shù)造成的。

例如:

  • 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        # 是否對模型進(jìn)行量化
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])
            # 格式轉(zhuǎn)變,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 量化后檢測不出目標(biāo)或精度大幅下降

4.2.1 模型訓(xùn)練注意事項

1、卷積核設(shè)置
?? 推薦在設(shè)計的時候盡量使用 3x3 的卷積核,這樣可以實現(xiàn)最高的乘加運算單元(MAC)利用率,使得 NPU 的性能最佳。
NPU 也可以支持大尺寸的卷積核。支持的最小卷積核為[1],最大值為[11 * stride - 1]。同時 NPU 也支持非對稱卷積核,不過會增加一些額外的計算開銷。

2、結(jié)構(gòu)融合設(shè)計
?? NPU 會對卷積后面的 ReLU 和 MAX Pooling 進(jìn)行融合的優(yōu)化操作,能在運行中減少計算和帶寬開銷。所以在搭建網(wǎng)絡(luò)時,能針對這一特性,進(jìn)行設(shè)計。
RKNN模型部署(3)—— 模型轉(zhuǎn)換與測試
?? 模型量化后,卷積算子與下一層的 ReLU 算子可以被合并。另外為了確保 Max Pooling算子也能被合并加速,請在設(shè)計網(wǎng)絡(luò)時參考以下幾點:

  • pool size 必須是 2x2 或者 3x3,而步長 stride=2;
  • 2x2 池化的輸入圖片尺寸必須是偶數(shù),而且不能有填充;
  • 3x3 池化的輸入圖片尺寸必須是非 1 的奇數(shù),而且不能有填充;
  • 如果是 3x3 的池化,則水平輸入大小必須小于 64(8-bit 模型)或 32(16-bit 模型)。

3、2D卷積和Depthwise卷積
?? NPU 支持常規(guī) 2D 卷積和 Depthwise 卷積加速。由于 Depthiwise 卷積特定的結(jié)構(gòu),使得它對于量化(int8)模型不太友好,而 2D 卷積的優(yōu)化效果更好。所以設(shè)計網(wǎng)絡(luò)時建議盡量使用2D 卷積。如果必須使用 Depthwise 卷積,建議按照下面的規(guī)則進(jìn)行修改,能提高量化后模型的精度:
RKNN模型部署(3)—— 模型轉(zhuǎn)換與測試

  • 如果網(wǎng)絡(luò)中的激活函數(shù)使用的是 Silu,建議將其都改為 ReLU;
  • 在 Depthwise 卷積層的 BN 層和激活層,建議去除;
  • 在訓(xùn)練時,針對 Depthwise 卷積層,對它的權(quán)重進(jìn)行 L2 正則化。

4.2.2 RKNN量化過程使用的Dataset

?? RKNN Toolkit 量化過程中,需要根據(jù)數(shù)據(jù)的最大值、最小值,找到合適的量化參數(shù)。
此時需要使用 dataset 里的輸入進(jìn)行推理,獲取每一層的輸入、輸出數(shù)據(jù),再根據(jù)這些數(shù)據(jù)計算每一層輸入、輸出的量化參數(shù)。
?? 基于這個原因,校準(zhǔn)數(shù)據(jù)集里的數(shù)據(jù)最好是從訓(xùn)練集或驗證集中取一個有代表性的子集,建議數(shù)量在 100~500 張之間。

4.2.3 RKNN量化過程的參數(shù)設(shè)置

1、使用 RKNN Toolkit 導(dǎo)入量化后的模型時使 rknn.build(do_quantization=False);
2、設(shè)置 mean_values/std_values 參數(shù),確保其和訓(xùn)練模型時使用的參數(shù)相同;
3、務(wù)必確保測試時輸入圖像通道順序為 R,G,B(不論訓(xùn)練時使用的圖像通道順序如何,使用 RKNN 做測試時都按 R,G,B 輸入);
4、在rknn.config 函數(shù)里面設(shè)置 reorder_channel 參數(shù),’0 1 2’代表 RGB, ’2 1 0’代表 BGR,務(wù)必和訓(xùn)練時候圖像通道順序一致;
5、使用多張圖進(jìn)行量化校準(zhǔn),確保量化精度穩(wěn)定;
6、在 rknn.config 中設(shè)置 batch_size 參數(shù) (建議設(shè)置 batch_size = 200) 并且在 dataset.txt 中給出大于 200 張圖像路徑用于量化;如果內(nèi)存不夠,可以設(shè)置 batch_size =10, epochs=20 代替 batch_size = 200 進(jìn)行量化。文章來源地址http://www.zghlxwxcb.cn/news/detail-421282.html

到了這里,關(guān)于RKNN模型部署(3)—— 模型轉(zhuǎn)換與測試的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • yolov5-6.0項目部署+自用Pytorch模型轉(zhuǎn)換rknn模型并在RK3568 linux(Debian)平臺上使用qt部署使用NPU推理加速攝像頭目標(biāo)識別詳細(xì)新手教程

    yolov5-6.0項目部署+自用Pytorch模型轉(zhuǎn)換rknn模型并在RK3568 linux(Debian)平臺上使用qt部署使用NPU推理加速攝像頭目標(biāo)識別詳細(xì)新手教程

    1 我們打開yolov的官網(wǎng),Tags選擇6.0版本 2. 下載該壓縮包并解壓到工程目錄下 3. 我們這里使用pycharm,專門針對python的IDE,用起來非常方便,下載方式就是官網(wǎng)直接下載,用的是社區(qū)版 4. 我們需要安裝環(huán)境,這里我推薦安裝Anaconda在電腦上,這是一個非常方便的包管理工具,可

    2024年02月05日
    瀏覽(33)
  • yolov8n 瑞芯微RKNN和地平線Horizon芯片仿真測試部署,部署工程難度小、模型推理速度快

    yolov8n 瑞芯微RKNN和地平線Horizon芯片仿真測試部署,部署工程難度小、模型推理速度快

    ??特別說明:參考官方開源的yolov8代碼、瑞芯微官方文檔、地平線的官方文檔,如有侵權(quán)告知刪,謝謝。 ??模型和完整仿真測試代碼,放在github上參考鏈接 模型和代碼。 ??因為之前寫了幾篇yolov8模型部署的博文,存在兩個問題:部署難度大、模型推理速度慢。該篇解

    2024年02月01日
    瀏覽(28)
  • 【運維知識高級篇】一篇文章帶你搞懂Git?。℅it安裝+全局配置+Git初始化代碼倉庫+Git四大區(qū)域+Git四種狀態(tài)+Git常用命令+Git分支+Git測試代碼回滾)

    版本流程控制系統(tǒng)(version control system)是一種記錄一個或若干個文件內(nèi)容變化,以便將來查閱特定版本內(nèi)容情況的系統(tǒng),它會記錄文件的所有歷史變化,我們可以隨時恢復(fù)到任何一個歷史狀態(tài),同時支持多人協(xié)作開發(fā)。 目錄 常見的版本管理工具 Git安裝與全局配置 Git初始化

    2024年02月02日
    瀏覽(140)
  • NumPy(1)-常用的初始化方法

    NumPy(1)-常用的初始化方法

    NumPy是Python中科學(xué)計算的基礎(chǔ)包,它是一個Python庫,提供多維數(shù)組對象,各種派生對象(如掩碼數(shù)組和矩陣),以及用于數(shù)組快速操作的各種API,有包括數(shù)學(xué)、邏輯、形狀操作、排序、選擇、輸入輸出、離散傅立葉變換、基本線性代數(shù),基本統(tǒng)計運算和隨機(jī)模擬等等。 功能強(qiáng)

    2024年02月16日
    瀏覽(26)
  • 【隨機(jī)種子初始化】一個神經(jīng)網(wǎng)絡(luò)模型初始化的大坑

    【隨機(jī)種子初始化】一個神經(jīng)網(wǎng)絡(luò)模型初始化的大坑

    半年前寫了一個模型,取得了不錯的效果(簡稱項目文件1),于是整理了一番代碼,保存為了一個新的項目(簡稱項目文件2)。半年后的今天,我重新訓(xùn)練這個整理過的模型,即項目文件2,沒有修改任何的超參數(shù),并且保持完全一致的隨機(jī)種子,但是始終無法完全復(fù)現(xiàn)出半

    2024年02月09日
    瀏覽(29)
  • 模型部署——rknn-toolkit-lite2部署RKNN模型到開發(fā)板上(python版)

    模型部署——rknn-toolkit-lite2部署RKNN模型到開發(fā)板上(python版)

    歡迎學(xué)習(xí)RKNN系列相關(guān)文章,從模型轉(zhuǎn)換、精度分析,評估到部署,推薦好資源: 一、Ubuntu系統(tǒng)上安裝rknn-toolkit 二、使用rknn-toolkit將Pytorch模型轉(zhuǎn)為RKNN模型 三、RKNN模型的評估和推理測試 四、RKNN模型量化精度分析及混合量化提高精度 五、RKNN模型性能評估和內(nèi)存評估 六、rkn

    2024年04月11日
    瀏覽(21)
  • 初始化交換機(jī)的密碼的方法介紹

    1、斷開交換機(jī)的電源并重新給交換機(jī)加電,在給交換機(jī)加電的同時按住交換機(jī)前面板上的“模式(Mode)”按鈕幾秒鐘,仔細(xì)觀察超級終端程序中顯示的交換機(jī)啟動信息。 2、待出現(xiàn)交換機(jī)提示符switch:后,輸入flash_init命令。 3、待上述命令執(zhí)行完成后,輸入load_helper命令。 4、待

    2024年02月05日
    瀏覽(27)
  • 【nginx實踐連載-1】安裝部署配置初始化

    要在Ubuntu上安裝、部署和配置Nginx,可以按照以下步驟進(jìn)行操作: 步驟1:安裝Nginx 打開終端(Terminal)。 運行以下命令更新軟件包索引: 安裝Nginx: 步驟2:啟動Nginx服務(wù) 安裝完成后,Nginx服務(wù)將會自動啟動。您可以使用以下命令檢查Nginx服務(wù)狀態(tài): 如果Nginx未啟動,您可以使

    2024年02月20日
    瀏覽(32)
  • rv1109/1126 rknn 模型部署過程

    rv1109/1126 rknn 模型部署過程

    rv1109/1126是瑞芯微出的嵌入式AI芯片,帶有npu, 可以用于嵌入式人工智能應(yīng)用。算法工程師訓(xùn)練出的算法要部署到芯片上,需要經(jīng)過模型轉(zhuǎn)換和量化,下面記錄一下整個過程。 模型量化需要安裝rk的工具包: rockchip-linux/rknn-toolkit (github.com) 版本要根據(jù)開發(fā)板的固件支持程度來,

    2024年02月14日
    瀏覽(22)
  • 深入理解 Flink(八)Flink Task 部署初始化和啟動詳解

    深入理解 Flink(八)Flink Task 部署初始化和啟動詳解

    核心入口: 部署 Task 鏈條:JobMaster -- DefaultScheduler -- SchedulingStrategy -- ExecutionVertex -- Execution -- RPC請求 -- TaskExecutor JobMaster 向 TaskExecutor 發(fā)送 submitTask() 的 RPC 請求,用來部署 StreamTask 運行。TaskExecutor 接收到 JobMaster 的部署 Task 運行的 RPC 請求的時候,就封裝了一個 Task 抽象,然

    2024年01月17日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包