• 【RK3588】Firefly 瑞芯微板子入门知识、和环境篇


    公司买了块瑞芯微的移动开发板,准备将公司的主营业务的AI模型,从服务器主机,移动到开发板上面。所以,就选择了瑞芯微的RK3588的板子。

    从目前市面上出现的板子来看,主要的还是以瑞芯微的板子为主,比如鸣辰1号等等。接着,也就有了我学习的内容。

    这里将我学习的过程记录和分享到这里,一是帮助新手快速入手,二是帮助自己进行记录,以便在我忘记之前如何弄的时候,及时的可以快速查看。参考资料主要是来自于官方给的文档,还有网上热心网友的分享,在此感谢。

    其中,RK3588的主要参考链接集合到这里,如下:

    • ROC-RK3588S-PC网页教程:https://wiki.t-firefly.com/zh_CN/ROC-RK3588S-PC/index.html
    • Core-3588J资料下载:https://www.t-firefly.com/doc/download/161.html
    • 技术文档:https://wiki.t-firefly.com/zh_CN/ROC-RK3588S-PC/index.html
    • 官方论坛首页:https://dev.t-firefly.com/portal.php?mod=topic&topicid=11
    • 发邮件,请教官方问题

    下面的内容,也是基于上述资料进行展开的,只是对自己感兴趣和遇到的一些问题做了些记录,整体上是大差不差。

    一、RK3588基本内容

    板子的相关资料,官方和网络开放的一些资料,对其中对了很详尽的描述和介绍,我在这里就不做进一步的赘述了。贴一个功能和输入、输出接口的官方介绍如下图这样:

    在这里插入图片描述
    下文主要参照文档:RKNN SDK 快速上手指南,这个文件是官方的文档,自行查找即可,建议直接参照这个文档,会描述的比较详尽,接近于手把手教学。配合网页教程,会更佳。

    RKNN SDK的下载地方,包括了NPU Demo和配置所需要的文件。有1.3.01.2.0两个版本,我选择的是1.3.0的版本进行实验。文档包括:

    • RKNN Toolkit2 快速上手指南(Rockchip_Quick_Start_RKNN_Toolkit2_CN-1.3.0.pdf
    • RKNN-Toolkit2 用户使用指南(Rockchip_User_Guide_RKNN_Toolkit2_CN-1.3.0.pdf

    都存储在:RK_NPU_SDK_1.3.0\rknn-toolkit2-1.3.0\doc文件夹下,这两个文档比较重要,能够帮助我们快速部署和快速转换自己的模型,后面会主要用到这两个文档。

    rknn sdk

    二、入门上手

    2.1、安装ADB

    ADB的安装与使用,也可以参考这里:ADB 使用

    2.1.1、ADB是个什么东西?

    ADB全称Android Debug Bridge,中文翻安卓调试桥。专业术语就不讲解释了,简单来说就是可以通过这个命令用电脑控制手机,或者是其他的安卓设备,比如这个板子,就是安卓的系统。

    所以,为了控制这个板子,就要在自己电脑上面,搞个ADB,有了这个东西,才能与自己的板子通信,给他发指令,控制他去干活。下面就按照官方教程,在自己的电脑上,进行安装吧。

    拿到时候,我也没搞明白,为啥不直接把板子脸上屏蔽,直接操作。刷Linux系统是可以的,我这里还是用出厂自带的安卓系统,就通过这个安卓调试桥,用PC作为媒介,给板子发命令和传送和查看板子内的文件

    adb常用命令如下,这个也是后面常用到的命令

    adb root 			以root权限重启adb服务
    adb reboot 			重启设备
    adb kill-server		终止adb服务进程
    
    adb remount 		将system分区重新挂载为可读写分区
    adb push   	将本地文件复制到设备
    adb pull   	从设备复制文件到本地
    adb shell 			进入板子系统
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    更多adb命令,参考这里:adb命令大全

    2.1.2、window下安装ADB

    就按照他说的来,先去下载驱动,把驱动安装好。然后再来下载这个adb.zip,解压后进行安装。没有遇到什么问题,测试发现安装成功,就完事了。

    我也没搞明白,为啥去用window去首先做了,可能就是因为不了解,先按教程说的做得了。

    这块内容有很详尽的介绍,并且我也是参照这块做的,没有发现什么问题,就不做过多解释了。

    adb

    下面是在 ROC-RK3588S-PC 上运行demo的展示结果:

    在这里插入图片描述

    ROC-RK3588S-PC网页教程NPU使用一节的步骤,可以实现对官方demo的复现,打印结果如下:(根据你自己运行的demo的不同,打印的内容也不同)

    在这里插入图片描述
    这是rknn_ssd_demo,也就是目标检测算法SSD的RKNN的版本实现方法。其中

    • 加载的模型是.rknn
    • rknn_ssd_demo是经过编译后的c语言版本,速度有所提升

    在下一节中,主要就是仿照官方的方法:

    • 将自己pytorch训练的yolov5的模型,给转成.rknn版本
    • 生成yolov5的c语言版本,进行加速

    2.2、更新板子的 rknn_server 和 librknnrt.so

    在这里插入图片描述

    正常输出运行结果:

    在这里插入图片描述

    2.3、创建和激活的rknn虚拟环境

    前面的环境按照,都是为了这一刻,能够激活环境,进行操作。进入激活的python环境,需要这样操作:

    root@zyyl-Lenovo:~# adb devices
    List of devices attached
    c21389c12d9b5c0b	device
    
    root@zyyl-Lenovo:~# adb root && adb remount
    adbd is already running as root
    remount succeeded
    
    root@zyyl-Lenovo:~# virtualenv -p /usr/bin/python3 venv      #  选择一个python解释器来创建虚拟化环境
    created virtual environment CPython3.8.10.final.0-64 in 749ms
      creator CPython3Posix(dest=/root/venv, clear=False, global=False)
      seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, pkg_resources=latest, via=copy, app_data_dir=/root/.local/share/virtualenv/seed-app-data/v1.0.1.debian.1)
      activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator
      
    root@zyyl-Lenovo:~# source venv/bin/activate			# 激活虚拟化环境
    (venv) root@zyyl-Lenovo:~# 
    
    root@zyyl-Lenovo:~# deactive 		# 退出虚拟化环境
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    虚拟环境的部分,更多可参考这里:virtualenv介绍及基本使用

    创建虚拟环境的一些记录:假设我在某个位置创建了一个虚拟环境,那么就会创建一个 venv 的文件夹,如下所示:

    创建虚拟环境的地址
    那么,我在下次采用source venv/bin/activate 激活虚拟环境的时候,就需要在文件夹下面进行操作。

    激活虚拟环境

    下面是运行官方example时候,打印的结果。还好官方已经给出了yolov5的案例,我们就可以先参照这里,对自己的模型,进行转换了。

    在这里插入图片描述

    三、模型转换

    下面以paddlepaddle OCR任务为例,简单的给个模型转换的过程和代码,如下

    3.1、onnx 2 rknn

    import cv2
    from rknn.api import RKNN
    import numpy as np
    import onnxruntime as ort
    
    """
    /home/hkl/project/ISSUES/RKNN_SDK/RK_NPU_SDK_1.3.0/rknpu2_1.3.0/examples/rknn_paddlle_ocr
    """
    onnx_model = 'onnx_github/repvgg_s.onnx' #onnx路径
    save_rknn_dir = 'onnx_github/repvgg_s.rknn'#rknn保存路径
    
    def norm(img):
        mean = 0.5
        std = 0.5
        img_data = (img.astype(np.float32)/255 - mean) / std
        return img_data
    
    if __name__ == '__main__':
    
        # Create RKNN object
        rknn = RKNN(verbose=True)
    
        # image = np.random.randn(1,3,32,448).astype(np.float32)             # 创建一个np数组,分别用onnx和rknn推理看转换后的输出差异,检测模型输入是1,3,640,640 ,识别模型输入是1,3,32,448
        image = cv2.imread('./imgs_data_rec/14.jpg')
        image = cv2.resize(image, (448, 32))
        image = np.expand_dims(image, axis=0)  # 添加批次维度
        image = np.transpose(image, (0, 3, 1, 2))  # 重新排列通道维度
    
        onnx_net = ort.InferenceSession(onnx_model)                        # onnx推理
    
        onnx_infer = onnx_net.run(None, {'input': norm(image)})                    # 如果是paddle2onnx转出来的模型输入名字默认是 "x"
    
        # pre-process config
        print('--> Config model')
        rknn.config(mean_values=[[127.5, 127.5, 127.5]], std_values=[[127.5, 127.5, 127.5]],
                    target_platform='rk3588')  # 需要输入为RGB#####需要转化一下均值和归一化的值
        print('done')
    
        # Load ONNX model
        print('--> Loading model %s' % onnx_model)
        ret = rknn.load_onnx(model=onnx_model)
        if ret != 0:
            print('Load %s failed!' % onnx_model)
            exit(ret)
        print('done')
        # Build model
        print('--> Building model')
        # rknn.build(do_quantization=False)
        ret = rknn.build(do_quantization=True, dataset='datasets_rec.txt')
        #do_quantization是否对模型进行量化,datase量化校正数据集,pre_compil模型预编译开关,预编译 RKNN 模型可以减少模型初始化时间,但是无法通过模拟器进行推理或性能评估
        if ret != 0:
            print('Build net failed!')
            exit(ret)
        print('done')
    
        # Export RKNN model
        print('--> Export RKNN model')
        ret = rknn.export_rknn(save_rknn_dir)
        if ret != 0:
            print('Export rknn failed!')
            exit(ret)
    
        ret = rknn.init_runtime(target='rk3588', device_id="1f2bb12b381c00c1")            # 两个参数分别是板子型号和device_id,device_id在双头usb线连接后通过 adb devices查看
        if ret != 0:
            print('init runtime failed.')
            exit(ret)
        print('done')
    
        # Inference
        print('--> Running model')
        outputs = rknn.inference(inputs=[image])
    
        # perf
        print('--> Begin evaluate model performance')
        perf_results = rknn.eval_perf(inputs=[image])              # 模型评估
        print('done')
        print()
    
        print("->>模型前向对比!")
        print("--------------rknn outputs--------------------")
        print(outputs[0])
        print()
    
        print("--------------onnx outputs--------------------")
        print(onnx_infer[0])
        print()
    
        std = np.std(outputs[0]-onnx_infer[0])
        print(std)                                # 如果这个值比较大的话,说明模型转换后不太理想
    
        rknn.release()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    参考链接:【工程部署】手把手教你在RKNN上部署OCR服务(上)

    3.2、 rknn predict

    这里的预测部分,是以paddle OCR官方给出的案例。对于瑞芯微官方的文档里面,也有好几个案例可供参考,其中提供了python的版本和C++的版本,建议去那里看看。

    import numpy as np
    import cv2
    from rknn.api import RKNN
    import torch
    # from label_convert import CTCLabelConverter
    
    class CTCLabelConverter(object):
        """ Convert between text-label and text-index """
    
        def __init__(self, character):
            # character (str): set of the possible characters.
            dict_character = []
            with open(character, "rb") as fin:
                lines = fin.readlines()
                for line in lines:
                    line = line.decode('utf-8').strip("\n").strip("\r\n")
                    dict_character += list(line)
            # dict_character = list(character)
    
            self.dict = {}
            for i, char in enumerate(dict_character):
                # NOTE: 0 is reserved for 'blank' token required by CTCLoss
                self.dict[char] = i + 1
            #TODO replace ‘ ’ with special symbol
            self.character = ['[blank]'] + dict_character+[' ']  # dummy '[blank]' token for CTCLoss (index 0)
    
        def encode(self, text, batch_max_length=None):
            """convert text-label into text-index.
            input:
                text: text labels of each image. [batch_size]
            output:
                text: concatenated text index for CTCLoss.
                        [sum(text_lengths)] = [text_index_0 + text_index_1 + ... + text_index_(n - 1)]
                length: length of each text. [batch_size]
            """
            length = [len(s) for s in text]
            # text = ''.join(text)
            # text = [self.dict[char] for char in text]
            d = []
            batch_max_length = max(length)
            for s in text:
                t = [self.dict[char] for char in s]
                t.extend([0] * (batch_max_length - len(s)))
                d.append(t)
            return (torch.tensor(d, dtype=torch.long), torch.tensor(length, dtype=torch.long))
    
        def decode(self, preds, raw=False):
            """ convert text-index into text-label. """
            preds_idx = preds.argmax(axis=2)
            preds_prob = preds.max(axis=2)
            result_list = []
            for word, prob in zip(preds_idx, preds_prob):
                if raw:
                    result_list.append((''.join([self.character[int(i)] for i in word]), prob))
                else:
                    result = []
                    conf = []
                    for i, index in enumerate(word):
                        if word[i] != 0 and (not (i > 0 and word[i - 1] == word[i])):
                            result.append(self.character[int(index)])
                            conf.append(prob[i])
                    result_list.append((''.join(result), conf))
            return result_list
    
    
    def narrow_224_32(image, expected_size=(224,32)):
        ih, iw = image.shape[0:2]
        ew, eh = expected_size
        scale = eh / ih
        # scale = eh / max(iw,ih)
        nh = int(ih * scale)
        nw = int(iw * scale)
        image = cv2.resize(image, (nw, nh), interpolation=cv2.INTER_CUBIC)
        top = 0
        bottom = eh - nh - top
        left = 0
        right = ew - nw - left
    
        new_img = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(114, 114, 114))
        return new_img
    
    
    if __name__ == '__main__':
        dict_path = r"./onnx_github/dict_text.txt"
        converter = CTCLabelConverter(dict_path)
        # Create RKNN object
        rknn = RKNN()
    
        ret = rknn.load_rknn('onnx_github/rec.rknn')
    
        # Set inputs
        img = cv2.imread('imgs_data_rec/21.jpg')
        # img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # origin_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        image = narrow_224_32(img, expected_size=(448, 32))
    
        # init runtime environment
        print('--> Init runtime environment')
        ret = rknn.init_runtime(target='rk3588',device_id="1f2bb12b381c00c1")
        if ret != 0:
            print('Init runtime environment failed')
            exit(ret)
        print('done')
    
        # Inference
        print('--> Running model')
        outputs = rknn.inference(inputs=[image])
    
        # perf
        print('--> Begin evaluate model performance')
        perf_results = rknn.eval_perf(inputs=[image])
        print('done')
    
        feat_2 = torch.from_numpy(outputs[0])
        print(feat_2.size())
    
        txt = converter.decode(feat_2.detach().cpu().numpy())
        print(txt)
        cv2.imshow("img",img)
        cv2.waitKey()
        rknn.release()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    四、总结

    关于瑞芯微RK3588芯片的第一篇文章,主要就是记录了一些基本的环境按照,Linux系统与板子的联调,以及转换模型,是现在虚拟环境,和板端的运行。

    第一阶段肯定还是先实操瑞芯微官方给的一些案例,这样出现了问题,可以及时的找到解决方法。下一篇文章就是根据官方给的yolo v5的案例,完整的记录模型转换中的步骤,和遇到的问题。


    最后,如果您觉得本篇文章对你有帮助,欢迎点赞 👍,让更多人看到,这是对我继续写下去的鼓励。本系列文章都不会设定 VIP 和付费,如果能再点击下方的红包打赏,给博主来一杯咖啡,那就太好了。💪

  • 相关阅读:
    一文带你了解MySQL数据库基础
    小程序如何设置余额充值
    ApplicationContext种类
    【问题解决】 网关代理Nginx 301暴露自身端口号
    Promise, async, await实现异步编程,代码详解
    【无标题】
    (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
    leetcode(力扣) 188. 买卖股票的最佳时机 IV (动态规划)
    HBase的逻辑结构与物理结构
    【课程总结】Day11(中):手势图像识别实战(Vgg16和ResNet)
  • 原文地址:https://blog.csdn.net/wsLJQian/article/details/125143080