负基础教学,讯为科技家的网课。目的是了解开发流程和技术要点,独立完成项目

一、RKNN Toolkit2 API环境搭载和模型构建前准备

Linux需基本指令操作以及对根文件的功能了解

python和c语言能看懂逻辑就行

深度学习需达到可以独立完成对轻量级yolo模型的训练和导出,对模型修改构建不作要求

架构组成:

1.1 github搜索:rockchip-linux,选择用户,进主页找rknn-toolkit2,并下载

工具对比:

1.2 Miniconda,并创建虚拟环境RKNN

安装Linux 64-bit版本

然后按照指令,拷贝进创建好的目录 softwate里,再 ./运行程序

等待安装,一直yes

打开终端,有(base)说明完成了

终端输入指令 vim .condarc

内容到文档中复制(

链接:https://pan.baidu.com/s/1vJ5WFj6VDs45gA5ZIrROhQ  提取码:fyvy

创建RNKK环境

输入指令 conda activate rknn

就能创建一个新的虚拟环境rknn

再重复前面的拷贝工作,把rknn-toolkit2工具放进环境中

然后是安装几个库

1.3 pycharm,配置中文插件和RKNN解释器

选择Linux版本进行下载,拷贝压缩包

使用tar -vxf命令解压压缩包

ls选择进入pycharm.sh,再./启动pycharm

创桌面快捷

安装中文插件(language那个,第二个),然后重启一下ide

选择新建项目,/home/topeet/rknn

选择先前配置的解释器,选系统解释器,/home/topeet/miniconda3/envs/bin/python3

打开终端,(rknn)确定环境为rknn中

二、RKNN模型构建和加载,精度分析和性能评估

2.1模型构建

API介绍

回到rknn项目中

右键新建目录01_export_rknn

第一步:创建export_rknn.py文件

第二步:输入并运行,调用config接口设置模型预处理、量化方法等参数

from rknn.api import RKNN

if __name__ == '__main__':
    rknn = RKNN(verbose=True, verbose_file="log.txt")
    rknn.config(
    mean_values=[[123.675, 116.28, 103.53]],  # mean_values 表示预处理减去的均值化参数
    std_values=[[58.395, 57.12, 57.375]],     # std_values 表示预处理要除的标准化参数
    quantized_dtype='asymmetric_quantized-u8', # quantized_dtype 表示量化类型
    quantized_algorithm='normal',             # quantized_algorithm 表示量化算法
    quantized_method='channel',               # quantized_method 表示量化的方式
    target_platform='RK3588',                 # target_platform 表示 RKNN 模型的运行平台
    float_dtype='float16',                    # float_dtype 表示 RKNN 中的浮点运算数据类型,不进行模型量化情况下,一般默认float32转换为float16
    optimization_level=3,                     # optimization_level 表示优化等级
    stringization=True,                       # stringization 表示自定义字符串信息
    remove_weight=False,                      # remove_weight 表示是否移除权重信息(生成小模型)
    compress_weight=False,                    # compress_weight 表示是否压缩权重(减小模型体积)
    inputs_yuv_fmt=None,                      # inputs_yuv_fmt 表示 RKNN 模型输入数据的 YUV 格式
    single_core_mode=False                    # single_core_mode 表示模型是否运行在单核模式(仅适用于 RK3588)
)

    rknn.release()

这里调用PyTorch模型加载接口

第三步:

①找到这个资料04_RNKK模型构建找到01_课程用到的资料的01_pytorch模型,把.pt拷到

前面创建的目录01_export_rknn中(resnet8.pt)

②找到这个资料04_RNKK模型构建找到01_课程用到的资料的02_dataset,把.txt和图片拷到

前面创建的目录01_export_rknn中(dataset.txt、图片)

③调用rknn.export_rknn导出的 RKNN 模型路径,然后命令行python运行一下,当目录下出现resnet18.rknn文件,说明转化成功

from rknn.api import RKNN

if __name__ == '__main__':
    rknn = RKNN(verbose=True, verbose_file="log.txt")
    rknn.config(
    mean_values=[[123.675, 116.28, 103.53]],  # mean_values 表示预处理减去的均值化参数
    std_values=[[58.395, 57.12, 57.375]],     # std_values 表示预处理要除的标准化参数
    quantized_dtype='asymmetric_quantized-u8', # quantized_dtype 表示量化类型
    quantized_algorithm='normal',             # quantized_algorithm 表示量化算法
    quantized_method='channel',               # quantized_method 表示量化的方式
    target_platform='RK3588',                 # target_platform 表示 RKNN 模型的运行平台
    float_dtype='float16',                    # float_dtype 表示 RKNN 中的浮点运算数据类型,不进行模型量化情况下,一般默认float32转换为float16
    optimization_level=3,                     # optimization_level 表示优化等级
    stringization=True,                       # stringization 表示自定义字符串信息
    remove_weight=False,                      # remove_weight 表示是否移除权重信息(生成小模型)
    compress_weight=False,                    # compress_weight 表示是否压缩权重(减小模型体积)
    inputs_yuv_fmt=None,                      # inputs_yuv_fmt 表示 RKNN 模型输入数据的 YUV 格式
    single_core_mode=False                    # single_core_mode 表示模型是否运行在单核模式(仅适用于 RK3588,其他板块注意切换)
    )
    rknn.load_pytorch (
        model="./resnet18.pt", # model 表示加载模型的地址
        input_size_list=[[1, 3, 224, 224]], # input_size_list 表示模型输入节点对应图片的尺寸和通道数
    )

    rknn.build (
        do_quantization=True, # do_quantization 表示是否对 RKNN 模型进行量化操作,                         

        dataset="dataset.txt", # dataset 表示要量化的图片
        rknn_batch_size=1 #
    )

    rknn.export_rknn (
        export_path="resnet18.rknn" # export_path 表示导出的 RKNN 模型路径
    )

    rknn.release()

整体流程是固定的,结合文档第四章 RKNN-Toolkit2 API介绍了解熟悉流程

2.2推理测试

回到rknn项目中

右键新建目录02_inference,新建文件inference_pytorch.py

找到这个资料04_RNKK模型构建找到01_课程用到的资料的01_pytorch模型,把.pt拷到

前面创建的目录01_export_rknn中(resnet8.pt)

找到这个资料04_RNKK模型构建找到01_课程用到的资料的02_dataset,把.txt和图片拷到

前面创建的目录01_export_rknn中(dataset.txt、图片)

from rknn.api import RKNN
import cv2

if __name__ == "__main__":

    rknn=RKNN(verbose=Ture)

    rknn.config(
    mean_values=[[123.675, 116.28, 103.53]],
    std_values=[[58.395, 58.395, 58.395]],
    target_platform="RK3588"
    )

    rknn.load_pytorch(
    model="./resnet18.pt", input_size_list=[[1, 3, 224, 224]])

    rknn.build(
    do_quantization=True,
    dataset="dataset.txt",
    )

    rknn.export_rknn(export_path="resnet18.rknn")

    rknn.init_runtime(
    target=None,
    target_sub_class=None,
    device_id=None,
    perf_debug=False,
    eval_mem=False,
    async_mode=False,
    core_mask=RKNN.NPU_CORE_AUTO,
    )

    img = cv2.imread(
    filename="/space_shuttle_224.jpg",
    flags=None
    )

    cv2.cvtColor(
    src=img,
    code=cv2.COLOR_BGR2RGB,
    )
    
    #调用inference接口进行推理
    outputs = rknn.inference(
    inputs=[img],  # inputs表示要推理的数据
    data_format="nhwc"  # data_format表示要推理的数据格式
    )

    rknn.release()

找到文件地址:

\05_RKNN 模型评估-推理测试\01_课程用到的资料\03_后处理程序\demo.py

用于outputs的后处理,把代码拷贝到工程中

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

def show_outputs(output):
    output_sorted = sorted(output, reverse=True)
    top5_str = '\n-----TOP 5-----\n'
    for i in range(5):
        value = output_sorted[i]
        index = np.where(output == value)
        for j in range(len(index)):
            if (i + j) >= 5:
                break
            if value > 0:
                topi = '{:d}: {:.3f}\n'.format(index[j], value)
            else:
                topi = '-1: 0.000\n'
            top5_str += topi
    print(top5_str)

def show_perfs(perfs):
    perfs = 'perfs: {}\n'.format(perfs)
    print(perfs)

def softmax(x):
    return np.exp(x)/sum(np.exp(x))

if __name__ == "__main__":

    rknn=RKNN(verbose=Ture)

    rknn.config(
    mean_values=[[123.675, 116.28, 103.53]],
    std_values=[[58.395, 58.395, 58.395]],
    target_platform="RK3588"
    )

    rknn.load_pytorch(
    model="./resnet18.pt", input_size_list=[[1, 3, 224, 224]])

    rknn.build(
    do_quantization=True,
    dataset="dataset.txt",
    )

    rknn.export_rknn(export_path="resnet18.rknn")

    #调试初始化接口环境
    rknn.init_runtime(
    target=None,    #测试rk3588时,更改为"rk3588" 
    target_sub_class=None,
    device_id=None,
    perf_debug=False,
    eval_mem=False,
    async_mode=False,
    core_mask=RKNN.NPU_CORE_AUTO,
    )

    img = cv2.imread(
    filename="/space_shuttle_224.jpg",
    flags=None
    )

    cv2.cvtColor(
    src=img,
    code=cv2.COLOR_BGR2RGB,
    )
    
    #调用inference接口进行推理
    outputs = rknn.inference(
    inputs=[img],  # inputs表示要推理的数据
    data_format="nhwc"  # data_format表示要推理的数据格式
    )
    
    #对outputs进行后处理
    show_outputs(solfmax(np.array([0][0])))
    
    rknn.release()

完成以后python运行,得到该图片验证最高概率是[812],打开\01_课程用到的资料\04_标签,查看[812]是航天飞船,而我们导入作为验证的图片正是该标签图片,到这里就完成了

这里我们切换运行环境,  找到  target=None,    测试rk3588时,更改为 target="rk3588" 

(如果没有提前配置adb环境,请输入以下指令进行安装:

请输入指令`sudo apt-get install adb`)

装载好远程环境,指路:https://blog.csdn.net/y8_7_16/article/details/147343334?fromshare=blogdetail&sharetype=blogdetail&sharerId=147343334&sharerefer=PC&sharesource=y8_7_16&sharefrom=from_link运行开发板,输入rknn_serve,确保rk3588的adb连接到Ubuntu虚拟机上,见图标

重新运行该程序,得到运行结果,推理完成。

右键文件inference_pytorch.py复制,粘贴在目录02_inference更改命名为inference_rknn.py

就可以实现直接调用,不需要构建rknn模型,再运行程序,会发现速快很多,代码更改为

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

def show_outputs(output):
    output_sorted = sorted(output, reverse=True)
    top5_str = '\n-----TOP 5-----\n'
    for i in range(5):
        value = output_sorted[i]
        index = np.where(output == value)
        for j in range(len(index)):
            if (i + j) >= 5:
                break
            if value > 0:
                topi = '{:d}: {:.3f}\n'.format(index[j], value)
            else:
                topi = '-1: 0.000\n'
            top5_str += topi
    print(top5_str)

def show_perfs(perfs):
    perfs = 'perfs: {}\n'.format(perfs)
    print(perfs)

def softmax(x):
    return np.exp(x)/sum(np.exp(x))

if __name__ == "__main__":

    rknn=RKNN(verbose=Ture)

    #调用load_rknn接口直接调用RKNN模型
    rknn.load_rknn(data="./resnet18.rknn")
    rknn.export_rknn(export_path="resnet18.rknn")

    #调试初始化接口环境
    rknn.init_runtime(
    target="rk3588" ,
    target_sub_class=None,
    device_id=None,
    perf_debug=False,
    eval_mem=False,
    async_mode=False,
    core_mask=RKNN.NPU_CORE_AUTO,
    )

    img = cv2.imread(
    filename="/space_shuttle_224.jpg",
    flags=None
    )

    cv2.cvtColor(
    src=img,
    code=cv2.COLOR_BGR2RGB,
    )
    
    #调用inference接口进行推理
    outputs = rknn.inference(
    inputs=[img],  # inputs表示要推理的数据
    data_format="nhwc"  # data_format表示要推理的数据格式
    )
    
    #对outputs进行后处理
    show_outputs(solfmax(np.array([0][0])))
    
    rknn.release()

2.3精度分析

流程

2.3.1普通量化

右键新建目录03_accuracy_analysis,新建文件accuracy_analysis.py

找到这个资料04_RNKK模型构建找到01_课程用到的资料的01_pytorch模型,把.pt拷到

前面创建的目录01_export_rknn中(resnet8.pt)

找到这个资料04_RNKK模型构建找到01_课程用到的资料的02_dataset,把.txt和图片拷到

前面创建的目录01_export_rknn中(dataset.txt、图片)

复制粘贴构建模型代码,运行

from rknn.api import RKNN

if __name__ == "__main__":

    rknn=RKNN(verbose=Ture)

    rknn.config(
    mean_values=[[123.675, 116.28, 103.53]],
    std_values=[[58.395, 58.395, 58.395]],
    target_platform="RK3588"
    )

    rknn.load_pytorch(
    model="./resnet18.pt", input_size_list=[[1, 3, 224, 224]])

    rknn.build(
    do_quantization=True,
    dataset="dataset.txt",
    )

    rknn.export_rknn(export_path="resnet18.rknn")

    # 使用accuracy_analysis接口进行模型量化精度分析
    rknn.accuracy_analysis(
    inputs=["space_shuttle_224.jpg"],  # inputs用来表示进行推理的图像
    output_dir="./accuracy_output",  # output_dir表示精度分析的输出目录
    target=None,  # target表示目标硬件平台
    device_id=None,  # device_id表示设备的编号
)
    
    rknn.release()

得到的日志中:

  • layer_name:表示模型中各网络层的名称,即当前行对应的是模型里哪一个层。
  • entire(属于 quant_error 分类下):表示该层在整体量化流程中的量化误差(从整体角度体现该层量化后的误差情况)。
  • per layer(属于 quant_error 分类下):表示该层自身(针对单个层)的量化误差(仅衡量当前层单独量化时的误差)。

再使用rknn3588自带的模型推理,找到  target=None,    测试rk3588时,更改为 target="rk3588"

运行开发板,输入rknn_serve,确保rk3588的adb连接到Ubuntu虚拟机上,重新运行程序

得到的日志中:

  • layer_name:模型中各网络层的名称,用于标识当前行对应的是模型里的哪一层。
  • quant_error:量化误差分类,下分两个子项:
    • entire:该层在整体量化流程(从输入到该层等整体链路下)产生的量化误差。
    • per_layer:该层自身单独量化时产生的量化误差。
  • runtime_error:运行时误差分类,下分两个子项:
    • simu_err:(通常指在模拟环境中运行时)产生的误差。
    • golden_err:作为 “黄金基准” 的误差(一般是高精度计算下的参考误差,用于对比衡量实际运行误差与理想情况的差距)。

这些标题从「层标识」「量化阶段误差」「运行阶段误差」三个维度,细分统计模型各层的精度表现,辅助分析量化和运行过程中误差的分布与来源。

2.3.2混合量化

观察得到量化效果后精度下降明显,故采用混合量化功能,减少精度损失

右键新建目录04_hybrid_quantizaton,新建文件step1.py

找到这个资料04_RNKK模型构建找到01_课程用到的资料的01_pytorch模型,把.pt拷到

前面创建的目录01_export_rknn中(resnet8.pt)

找到这个资料04_RNKK模型构建找到01_课程用到的资料的02_dataset,把.txt和图片拷到

前面创建的目录01_export_rknn中(dataset.txt、图片)

from rknn.api import RKNN

if __name__ == "__main__":

    rknn=RKNN(verbose=Ture)

    rknn.config(
    mean_values=[[123.675, 116.28, 103.53]],
    std_values=[[58.395, 58.395, 58.395]],
    target_platform="RK3588"
    )

    rknn.load_pytorch(
    model="./resnet18.pt", input_size_list=[[1, 3, 224, 224]])

    # 使用hybrid_quantization_step1接口进行混合量化的第一步
    rknn.hybrid_quantization_step1(
        dataset="dataset.txt",  # dataset表示模型量化所需要的数据集
        rknn_batch_size=-1,  # 表示自动调整模型输入batch数量
        proposal=False,  # 设置为True,可以自动产生适合量化的配置建议值
        proposal_dataset_size=1  # 第三步需要用的图片
    )


    rknn.release()

运行程序之后生成了以下文件

我们需修改的是后缀为.cfg文件,把某些量化层改为非量化层,因为input.25层精度下降(由日志可得),找到custom_quantize_layers做出以下修改,注意冒号:后面有空格

custom_quantize_layers: {  
    // 自定义量化层的配置区域,用于指定特定层的量化方式
    input.25: float16,     // 将名为input.25的网络层,设置为使用float16类型进行量化
    '142': float16

接下来创建step2.py

from rknn.api import RKNN

if __name__ == '__main__':
    rknn = RKNN()

    # 调用hybrid_quantization_step2接口进行混合量化的第二个步骤
    rknn.hybrid_quantization_step2(
        model_input="resnet18.model",  # model_input表示第一步生成的模型文件
        data_input="resnet18.data",  # data_input表示第一步生成的配置文件
        model_quantization_cfg="resnet18.quantization.cfg",  # model_quantization_cfg表示第一步生成的量化配置文件
    )

    # 调用量化精度分析接口 评估RKNN模型
    rknn.accuracy_analysis(
        inputs=["space_shuttle_224.jpg"],
        output_dir="./snapshot",
        target="RK3588"
    )

    # 调用RKNN模型导出接口导出RKNN模型
    rknn.export_rknn(export_path="./resnet18.rknn")
    rknn.release()

最后运行可知,该层精度得到提升

从哪获取需要更改网络层为非量化效果,通过该网站,打开.rknn模型导入查看网络层结构Netronhttps://netron.app/

重新打开step1.py,把  proposal=False,  设置为proposal=True,可以自动产生适合量化的配置建议值,再重新运行

再打开.cfg文件,则能看见自动添加好需混合量化的层

再运行step2.py

完成最终的混合量化结果

2.4模型评估

右键新建目录05_eval,新建文件eval.py

找到这个资料04_RNKK模型构建找到01_课程用到的资料的01_pytorch模型,把.pt拷到

前面创建的目录01_export_rknn中(resnet8.pt)

找到这个资料04_RNKK模型构建找到01_课程用到的资料的02_dataset,把.txt和图片拷到

前面创建的目录01_export_rknn中(dataset.txt、图片)

from rknn.api import RKNN

if __name__ == '__main__':
    rknn = RKNN()

    # 使用load_rknn接口导入rknn模型
    rknn.load_rknn(path="./resnet18.rknn")

    # 使用init_runtime接口初始化运行时环境
    rknn.init_runtime(
        target="RK3588", #只能在板上运行
        perf_debug=None,  # perf_debug表示是否开启性能评估的debug模式
        eval_mem=None,  # eval_mem表示是否使能内存评估
    )

    # 使用eval_perf接口进行性能评估
    rknn.eval_perf(
        inputs=["space_shuttle_224.jpg"],  # inputs表示要测试的图片
        data_format=None,  # data_format表示要推理的数据模式
        is_print=True,  # is_print表示使能打印性能信息
    )

    rknn.release()

启动板子adb服务成功连接到虚拟机,点击运行

日志显示对应的运行时间,和FPS

再将 perf_debug=None, eval_mem=None修改为 perf_debug=True, eval_mem=False就能把各个性能评估参数显示出来了。

对于 内存评估 代码

from rknn.api import RKNN

if __name__ == '__main__':
    rknn = RKNN()

    # 使用load_rknn接口导入rknn模型
    rknn.load_rknn(path="./resnet18.rknn")

    # 使用init_runtime接口初始化运行时环境
    rknn.init_runtime(
        target="RK3588",
        perf_debug=True,  # perf_debug表示是否开启性能评估的debug模式
        eval_mem=True,  # eval_mem表示是否使能内存评估
    )

    # 使用eval_perf接口进行性能评估(当前为注释状态)
    # rknn.eval_perf(
    #     inputs=["space_shuttle_224.jpg"],  # inputs表示要测试的图片
    #     data_format=None,  # data_format表示要推理的数据模式
    #     is_print=True,  # is_print 表示使能打印性能信息
    # )

    # 使用eval_memory接口进行内存评估
    rknn.eval_memory(
        is_print=True,  # 表示使能打印内存评估信息
    )

    rknn.release()

三、RKNN Toolkit lite2使用

吧 

右键新建目录06_rknnToolkitlite2,新建文件rknnToolkitlite2.py

将05_eval的文件.rknn和图片拷到新目录中

①使用rknn.api

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

def show_outputs(output):
    output_sorted = sorted(output, reverse=True)
    top5_str = '\n-----TOP 5-----\n'
    for i in range(5):
        value = output_sorted[i]
        index = np.where(output == value)
        for j in range(len(index)):
            if (i + j) >= 5:
                break
            if value > 0:
                topi = '{:d}: {:.3f}\n'.format(index[j], value)
            else:
                topi = '-1: 0.000\n'
            top5_str += topi
    print(top5_str)

def show_perfs(perfs):
    perfs = 'perfs: {}\n'.format(perfs)
    print(perfs)

def softmax(x):
    return np.exp(x)/sum(np.exp(x))

if __name__ == '__main__':
    rknn = RKNN()

    # 使用load_rknn接口直接加载RKNN模型
    rknn.load_rknn(path="./resnet18.rknn")

    # 调用init_runtime接口初始化运行时环境
    rknn.init_runtime(
        core_mask=0,  # 表示NPU的调度模式
        target="RK3588"
    )

    # 使用opencv获取推理的图片数据
    img = cv2.imread(filename="./space_shuttle_224.jpg")
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # 调用Inference接口进行推理测试
    outputs = rknn.inference(
        inputs=[img],
        data_format=None
    )

    show_outputs(softmax(np.array(outputs[0][0])))
    rknn.release()

②使用rknnlite.api,可以拷贝到开发板上运行的程序

from rknnlite.api import RKNNLITE
import cv2
import numpy as np

def show_outputs(output):
    output_sorted = sorted(output, reverse=True)
    top5_str = '\n-----TOP 5-----\n'
    for i in range(5):
        value = output_sorted[i]
        index = np.where(output == value)
        for j in range(len(index)):
            if (i + j) >= 5:
                break
            if value > 0:
                topi = '{:d}: {:.3f}\n'.format(index[j], value)
            else:
                topi = '-1: 0.000\n'
            top5_str += topi
    print(top5_str)

def show_perfs(perfs):
    perfs = 'perfs: {}\n'.format(perfs)
    print(perfs)

def softmax(x):
    return np.exp(x)/sum(np.exp(x))

if __name__ == '__main__':
    rknn = RKNNLITE()

    # 使用load_rknn接口直接加载RKNN模型
    rknn.load_rknn(path="./resnet18.rknn")

    # 调用init_runtime接口初始化运行时环境
    rknn.init_runtime(
        core_mask=0,  # 表示NPU的调度模式
    )

    # 使用opencv获取推理的图片数据
    img = cv2.imread(filename="./space_shuttle_224.jpg")
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # 调用Inference接口进行推理测试
    outputs = rknn.inference(
        inputs=[img],
        data_format=None
    )

    show_outputs(softmax(np.array(outputs[0][0])))
    rknn.release()

此前开发板上我们已经配置好rknnToolkitlite2工具使用环境,大致过程如下:

进入(base)

这里需使用python命令创建python3.9的环境和rknn环境

conda create -n rknn python=3.9

conda activate rknn

进入(rknn)

然后是拷rknnToolkitlite2软件包并安装好,pip安装opencv包

。。。

最后直接找到我们拷过来的使用rknnlite.api工具的rknnToolkitlite2.py,python运行,可直接得到推理结果

四、RKNPU2 各个api讲解

先创建新文档,打开终端,把CMAKE拷进文件夹里(\09_RKNN2通API讲解\01_课程用到的资料\01_Cmake工程示例)

mkdir work

cd work 
./

文件内指定了编译器路径

现在使用指令删除该文件,把\09_RKNN2 通用 API 讲解 \01_课程用到的资料 \02_交叉编译器 文件内编译器重新拷进去,再把第三方库的\09_RKNN2 通用 API 讲解 \01_课程用到的资料 \03_第三方库的3rdparty拷到work目录下

然后右键运行build.sh,

五、RKNPU2 C例程框架讲解

项目1:yolov5实时目标分类

项目2:sort目标追踪

项目3:车牌识别

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐