rk3399proyolov5人工智能加速推理解决方案(代码片段)

信迈科技DSP+ARM+FPGA 信迈科技DSP+ARM+FPGA     2022-12-06     734

关键词:

0. 前言:

本文介绍了YOLOv5s算法在国产瑞芯微电子RK3399ProD上的部署推理.介绍整个的流程,并基于RK3399Pro简单的介绍下RKNN的Python接口使用,并记录一些踩过的坑。本文仅做交流使用,文中有什么理解的不到位的或者谬误,也欢迎大家能够交流下。

1. 部署流程

  1. 在服务器端或者电脑端进行训练,训练完成后将.pt文件转换成ONNX格式
  2. 电脑端使用rknn-toolkit1.6.0将ONNX模型转换成RKNN模型
  3. RK3399Pro中进行模型推理 其中第二步,转换模型,可以在装了rknn-toolkit的rk3399Pro中,之前不知道的时候都是在这个开发板中进行转换的,不过还是建议在电脑端Ubuntu18.04系统下进行转换,可以将量化的batch设置的大一些,量化的速度快一些。
  4. 本文采用的开发板为信迈科技XM-3399-02
     

2. 环境准备

环境问题可能是比较棘手的问题,因为好多人都是在这个问题上出现了各种各样的bug,最好的办法是直接在Ubuntu上拉取他们提供的docker,直接拉取,环境都给配置好了,然后转换模型。 然后开发板选择官方的开发板,官方的开发板环境是最友好的,官方的RK3399Pro里面给安装好了环境,不怎么需要配置环境,不怎么会遇到问题,用于算法的验证还是很好的。

接下来是我在Ubuntu上配置的环境(使用的比较笨的方法QAQ),该环境是根据RKNN提供的手册进行安装的,其中,想要安装最终的rknn-toolkit1.6.0及以上版本,需要提前安装好依赖库,并且依赖库的版本要求非常的严格,版本不能有任何的不一样,在Rockchip_Quick_Start_RKNN_Toolkit_V1.6.1_CN.pdf文件中。 在Ubuntu上,我安装的是3.6版本的Python,其余的环境是按照下面的库依赖,严格配置的。安装好依赖库之后,去rockchip的官方仓库下载编译好的whl文件,直接在环境中pip install + xxx.whl就行了

rockchip官方git  https://github.com/rockchip-linux/rknn-toolkit

3. 服务器端或者电脑端训练YOLOv5s

项目地址: https://github.com/littledeep/YOLOv5-RK3399Pro

训练这部分并不用多说什么,仓库拉出来,根据自己的数据集改好参数,然后进行训练,YOLOv5的训练还是挺友好的。

不过训练YOLOv5的过程中,我选择在common文件中,将silu层全部换成了RuLe层,因为对准换后的RKNN模型有加速作用,这样总体的mAP会稍微降一些,经过测试总体的mAP降低的。
 

Rockchip_Developer_Guide_RKNN_Toolkit_Custom_OP_V1.6.1_CN.pdf在该文件中有详细的解释,使用ReLU激活层会融合一些层,从而进行优化。


4. 模型转换--->ONNX

根据github项目需要先将PyTorch训练出的.pt模型转换成ONNX格式。根据项目的Repo直接转换即可。 在命令行输入 :
python3 models/export_op.py --rknn_mode
即可。


5. 模型转换--->RKNN


将转换出来的模型xxxx.onnx复制到convert文件夹下面,convert文件夹需要有转换脚本,dataset.txt的量化文件,量化图片。量化的图片建议200张,batch尽量设置的大一些。 在命令行输入:
python rknn_convert.py
rknn_convert.py文件代码

import yaml
from rknn.api import RKNN
import cv2

_model_load_dict = 
    'caffe': 'load_caffe',
    'tensorflow': 'load_tensorflow',
    'tflite': 'load_tflite',
    'onnx': 'load_onnx',
    'darknet': 'load_darknet',
    'pytorch': 'load_pytorch',
    'mxnet': 'load_mxnet',
    'rknn': 'load_rknn',
    

yaml_file = './config.yaml'


def main():
    with open(yaml_file, 'r') as F:
        config = yaml.load(F)
    # print('config is:')
    # print(config)

    model_type = config['running']['model_type']
    print('model_type is '.format(model_type))#检查模型的类型

    rknn = RKNN(verbose=True)



#配置文件
    print('--> config model')
    rknn.config(**config['config'])
    print('done')


    print('--> Loading model')
    load_function = getattr(rknn, _model_load_dict[model_type])
    ret = load_function(**config['parameters'][model_type])
    if ret != 0:
        print('Load yolo failed! Ret = '.format(ret))
        exit(ret)
    print('done')

    ####
    #print('hybrid_quantization')
    #ret = rknn.hybrid_quantization_step1(dataset=config['build']['dataset'])


    if model_type != 'rknn':
        print('--> Building model')
        ret = rknn.build(**config['build'])
        print('acc_eval')
        rknn.accuracy_analysis(inputs='./dataset1.txt', target='rk3399pro')
        print('acc_eval done!')

        if ret != 0:
            print('Build yolo failed!')
            exit(ret)
    else:
        print('--> skip Building model step, cause the model is already rknn')


#导出RKNN模型
    if config['running']['export'] is True:
        print('--> Export RKNN model')
        ret = rknn.export_rknn(**config['export_rknn'])
        if ret != 0:
            print('Init runtime environment failed')
            exit(ret)
    else:
        print('--> skip Export model')


#初始化
    print('--> Init runtime environment')
    ret = rknn.init_runtime(**config['init_runtime'])
    if ret != 0:
        print('Init runtime environment failed')
        exit(ret)
    print('done')


    print('--> load img')
    img = cv2.imread(config['img']['path'])
    print('img shape is '.format(img.shape))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    inputs = [img]
    print(inputs[0][0:10,0,0])
#推理
    if config['running']['inference'] is True:
        print('--> Running model')
        config['inference']['inputs'] = inputs
        #print(config['inference'])
        outputs = rknn.inference(inputs)
        #outputs = rknn.inference(config['inference'])
        print('len of output '.format(len(outputs)))
        print('outputs[0] shape is '.format(outputs[0].shape))
        print(outputs[0][0][0:2])
    else:
        print('--> skip inference')
#评价
    if config['running']['eval_perf'] is True:
        print('--> Begin evaluate model performance')
        config['inference']['inputs'] = inputs
        perf_results = rknn.eval_perf(inputs=[img])
    else:
        print('--> skip eval_perf')


if __name__ == '__main__':
    main()

running:
  model_type: onnx       # 转换模型的类型
  export: True          		 # 转出模型
  inference: False		 
  eval_perf: True


parameters:
  caffe:
    model: './mobilenet_v2.prototxt'
    proto: 'caffe' #lstm_caffe
    blobs: './mobilenet_v2.caffemodel'
  
  tensorflow:
    tf_pb: './ssd_mobilenet_v1_coco_2017_11_17.pb'
    inputs: ['FeatureExtractor/MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/mul_1']
    outputs: ['concat', 'concat_1']
    input_size_list: [[300, 300, 3]]

  tflite:
    model: './sample/tflite/mobilenet_v1/mobilenet_v1.tflite'

  onnx:      # 填写要转换模型的model
    model: './best_noop.onnx'   #best_op.onnx   #best_noop.onnx

    #C:\\Users\\HP\\Desktop\\CODE\\yolov5_for_rknn-master\\weights\\best.onnx

  darknet:
    model: './yolov3-tiny.cfg'
    weight: './yolov3.weights'

  pytorch:
    model: './yolov5.pt'
    input_size_list: [[3, 512, 512]]

  mxnet:
    symbol: 'resnext50_32x4d-symbol.json'
    params: 'resnext50_32x4d-4ecf62e2.params'
    input_size_list: [[3, 224, 224]]

  rknn:
    path: './bestrk.rknn'

config:
  #mean_value: [[0,0,0]]
  #std_value: [[58.82,58.82,58.82]]
  channel_mean_value: '0 0 0 255' # 123.675 116.28 103.53 58.395 # 0 0 0 255
  reorder_channel: '0 1 2' # '2 1 0'
  need_horizontal_merge: False
  batch_size: 1
  epochs: -1
  target_platform: ['rk3399pro']
  quantized_dtype: 'asymmetric_quantized-u8'
#asymmetric_quantized-u8,dynamic_fixed_point-8,dynamic_fixed_point-16
  optimization_level: 3

build:
  do_quantization: True
  dataset: './dataset.txt' # '/home/zen/rknn_convert/quant_data/hand_dataset/pic_path_less.txt'
  pre_compile: False

export_rknn:
  export_path: './best_noop1.rknn'

init_runtime:
  target: rk3399pro
  device_id: null
  perf_debug: False
  eval_mem: False
  async_mode: False

img: &img
  path: './test2.jpg'

inference:
  inputs: *img
  data_type: 'uint8'
  data_format: 'nhwc' # 'nchw', 'nhwc'
  inputs_pass_through: None 

eval_perf:
  inputs: *img
  data_type: 'uint8'
  data_format: 'nhwc'
  is_print: True


其中在设置config部分的参数时,建议看看官方的API介绍,去选择相应的参数部分,在文件Rockchip_User_Guide_RKNN_Toolkit_V1.6.1_CN.pdf


6. RK3399Pro中模型推理
在detect文件夹下,其中data/image下面放的是需要检测的图片,在models文件夹下放的是转换的RKNN模型

最后点开shell 执行:
python rknn_detect_for_yolov5_original.py
即可 在开发板中会生成模型推理的结果和时间


推理的时间比较快,60毫秒左右,这个推理速度和我在笔记本电脑(3060)上使用模型detect的速度是差不多的。


7.模型预编译


解决模型的加载时间过长的问题

from rknn.api import RKNN
if __name__ == '__main__':
    # Create RKNN object
    rknn = RKNN()
# Load rknn model
ret = rknn.load_rknn('./best_as_200.rknn')
if ret != 0:
    print('Load RKNN model failed.')
    exit(ret)
# init runtime
ret = rknn.init_runtime(target='rk3399pro', rknn2precompile=True)
if ret != 0:
    print('Init runtime failed.')
    exit(ret)
# Note: the rknn2precompile must be set True when call init_runtime
ret = rknn.export_rknn_precompile_model('./best_pre_compile.rknn')
if ret != 0:
    print('export pre-compile model failed.')
    exit(ret)
rknn.release()


转换的环境是在RK3399Pro中,方法很笨但是有效。

将生成的模型继续使用模型的推理代码,在RK3399Pro中进行预测,模型推理速度50毫秒左右,有20FPS,使用Python接口还是比较快的了。


Reference:

https://github.com/EASY-EAI/yolov5
https://github.com/soloIife/yolov5_for_rknn
https://github.com/ultralytics/yolov5
https://github.com/rockchip-linux/rknn-toolkit
https://blog.csdn.net/weixin_42237113/category_10147159.html?spm=1001.2014.3001.5482

rk3399pro+k7/a7fpga+ai国产人工智能图像处理平台

rk3399pro简介rk3399pro是瑞星微新出来的带NPU的ARM芯片,在发布之前,NPU的算力2.4TOPS,而发现之后实测达到了3.0TOPS,如此强大的计算能力,jetsonnano的计算能力是0.47TFlops,两个单位有区别,只能用实际的网... 查看详情

rk3399pro+k7/a7fpga+ai国产人工智能图像处理平台

rk3399pro简介rk3399pro是瑞星微新出来的带NPU的ARM芯片,在发布之前,NPU的算力2.4TOPS,而发现之后实测达到了3.0TOPS,如此强大的计算能力,jetsonnano的计算能力是0.47TFlops,两个单位有区别,只能用实际的网... 查看详情

新手向tensorflow安装教程:rk3399上运行谷歌人工智能

从AlphaGo大胜柯洁后,谷歌的人工智能备受关注。人工智能好像离我们好远,深度学习算法貌似非常复杂。但其实看看你的手机上的语音助手,相机上的人脸识别,今日头条上帮你自动筛选出来的新闻,还有各大音乐软件的歌曲... 查看详情

新手向tensorflow安装教程:rk3399上运行谷歌人工智能

从AlphaGo大胜柯洁后,谷歌的人工智能备受关注。人工智能好像离我们好远,深度学习算法貌似非常复杂。但其实看看你的手机上的语音助手,相机上的人脸识别,今日头条上帮你自动筛选出来的新闻,还有各大音乐软件的歌曲... 查看详情

rk3399如何选择系统呢?

...单,API丰富,接口通用,除了RKNN、RGA特殊的加速单元以外,其他所有的加速单元均可以通过android自带的API操作。兼容性稳定 查看详情

当嵌入式遇上人工智能,用ok3399-c来做个ai“云监工”!

人工智能(AI)可以从实时视频流中检测出重要信息,从街道上收集可靠的实时数据并通过AI推理对其进行压缩,帮助智慧城市更轻松地管理资源,并改善生活质量、生产力和紧急响应速度。为实现出色的效率,视觉... 查看详情

初识rk3399以及相关资料汇总

...性能的处理器,适用于计算、个人移动互联网设备和其他智能设备应用。基于big.little架构,它集成了双核Cortex-A72和四核Cortex-A53与单独的NEON协处理器。许多嵌入式强大的硬件引擎为高端应用程序提供了优化的性能。RK3399支持多... 查看详情

rk3399芯片可以应用于哪些领域?

...、内容和方法的智慧化变革。搭载RK3399的智慧教育一体机解决方案可满足课堂的白板书写功能,支持多点触控,感应灵敏迅速,支持触控笔和手指的自由书写,媲美真实书写体验,高精准红外触摸技术延时不超过3毫秒,且可以... 查看详情

rk3399驱动开发|11-rk3399以太网调试(基于linux5.4.32内核)

...Ethernetdriversupport),果然都是模块:三、问题解决将驱动直接选择编译进内核:四、测试查看网卡:ping测试ÿ 查看详情

rk3399驱动开发|11-rk3399以太网调试(基于linux5.4.32内核)

...Ethernetdriversupport),果然都是模块:三、问题解决将驱动直接选择编译进内核:四、测试查看网卡:ping测试ÿ 查看详情

超强兼容性与扩展能力的视壮rk3399,vr游戏盒子热用

...容性与扩展能力,使其可应用于VR、游戏盒子、平板等多智能终端:1、对VR类设备:RK3399具备20ms延时、90Hz刷新、4KUHD解码、2K低余晖(LowPersistence)屏幕、高精度定位跟踪系统、超强HDR摄像技术、超强的3D处理能力以及超高清H.265/H.26... 查看详情

fireflyrk3399pcpro开发板资料

一.基本介绍产品介绍:Firefly|让科技更简单,让生活更智能开发板规格书:https://download.t-firefly.com/product/Board/RK3399/Document/Hardware/ROC-RK3399-PC%20Pro/Specification/ROC-RK3399-PC%20Pro%20%E4%BA%A7%E5%9 查看详情

fireflyrk3399pcpro开发板资料

一.基本介绍产品介绍:Firefly|让科技更简单,让生活更智能开发板规格书:https://download.t-firefly.com/product/Board/RK3399/Document/Hardware/ROC-RK3399-PC%20Pro/Specification/ROC-RK3399-PC%20Pro%20%E4%BA%A7%E5%9 查看详情

rk3399驱动开发|09-基于rk808pmic的电源管理驱动

...RK808(datasheet)是Rockchip针对便携式系统的一个完整电源解决方案,里面集成了四个buckDC-DC转换器、八个高性能ldo、两个低Rds开关、使用I2C接口、可编程的电源序列和一个RTC。RK808 查看详情

资源共享完整版rk3399芯片手册《rk3399technicalreferencemanual1.4》

【资源共享】完整版RK3399芯片手册《RK3399TechnicalReferenceManual1.4》650)this.width=650;"id="aimg_3039"src="http://developer.t-firefly.com/data/attachment/forum/201706/16/112147jxqtoxzoxxsrrstk.jpg"class="zoom"width 查看详情

rk3399开发板上插拔usb鼠标程序崩溃(代码片段)

...—>onCreate——>onResume。直接的现象就是程序会崩溃。解决办法:在AndroidManifest.xml中设置如下属性,即可解决<activityandroid:configChanges=" 查看详情

rk3399系统移植|移植linux原生5.4.32内核

....编译4.测试三、rootfs挂载问题1.问题描述2.问题分析3.问题解决源码一、linux原生内核初试1.下载 查看详情

rk3399系统移植|移植linux主线5.4.32内核

....编译4.测试三、rootfs挂载问题1.问题描述2.问题分析3.问题解决源码一、linux原生内核初试1.下载 查看详情