深度学习模型部署(四)——RKNN

发布于:2025-05-23 ⋅ 阅读:(26) ⋅ 点赞:(0)

一、RKNN部署及工具包安装

参考1:https://blog.csdn.net/qq_40280673/article/details/136211086#/
参考2:瑞芯微官方教程
RKNN部署针对瑞芯微芯片优化,支持NPU硬件加速,需要安装rknn-toolkit,用于将pytorch模型转换为RKNN模型
以下操作均在ubuntu中进行
运行环境要求如下:
在这里插入图片描述

1、安装python及相关依赖

sudo apt-get install python3 python3-dev python3-pip
sudo apt-get install libxslt1-dev zlib1g zlib1g-dev libglib2.0-0 libsm6 libgl1-mesa-glx libprotobuf-dev gcc

2、创建虚拟环境

# 创建虚拟环境
conda create -n your_env_name
# 激活虚拟环境
conda activate your_env_name

3、下载系统依赖及rknn-tookit安装包

系统依赖的库:requirements_cpxx-1.5.0.txt;
rknn-toolkit2安装包:rknn_toolkit2-1.5.0+fa95b5c-cpxx-linux_x86_64.whl
上述两个文件自取:
通过网盘分享的文件:libpackages
链接: https://pan.baidu.com/s/10xjTZ2Wr8CgGFV80tfXmZA 提取码: wwzn
【注】 cpxx取决于安装的python版本,如我的环境是ubuntu22.04,python版本3.10,因此我需要安装的是requirements_cp310-1.5.0.txt和rknn_toolkit2-1.5.0+fa95b5c-cp310-linux_x86_64.whl

4、安装系统依赖及rknn-toolkit2

激活需要安装的虚拟环境,运行以下指令时,执行目录须为txt文件和whl文件所在目录,也可以指定文件所在路径

pip install -r requirements_cp310-1.5.0.txt -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
pip install rknn_toolkit2-1.5.0+1fa95b5c-cp310-cp310-linux_x86_64.whl -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple

【注】 安装过程中可能有包下载不成功,可以手动pip安装,多试几个镜像源,或者爬梯子安装,一定要确保所有包安装成功

二、pytorch模型转换为rknn模型

我的文件结构如下:
在这里插入图片描述
datasets.txt的内容为
在这里插入图片描述

1、torch.nn.module——>rknn

参考1:https://blog.csdn.net/qq_40280673/article/details/136229500#/ 大佬的公众号有源码包,可以下载后执行
我参考着导出了一下yolov11n-cls模型:
【注】 要使用相同版本的pytorch导出模型并转为RKNN模型,否则会因为前后版本不一致导致RKNN转换失败。

# yolov11n-cls.pt转rknn模型
'''
1、导入RKNN包
2、实例化RKNN对象
3、定义数据预处理和量化方法
4、加载pytorch模型,即'.pt'文件
5、构建rknn模型
6、导出rknn模型
7、释放RKNN对象
'''
from rknn.api import RKNN

if __name__=="__main__":
    rknn = RKNN()
    '''
    初始化RKNN对象时,可以设置verbose和verbose_file参数:
    verbose:是否在屏幕上打印详细的日志信息
    verbose_file:日志文件
    示例:将详细日志信息输出到屏幕,并写入到build.log文件中
    rknn=RKNN(verbose=True,verbose_file='./build.log')
    '''

    rknn.config(
        mean_values=[[0.0, 0.0, 0.0]], 
        std_values=[[1.0, 1.0, 1.0]],
        target_platform='rk3588'
    )
    '''
    def config(
    mean_values: Any | None = None, 
        输入的均值,用于数据预处理中的normalization,如mean_values=[128, 128, 128]]表示输入的三个通道的值减去128
    std_values: Any | None = None, 
        输入的标准差,用于数据预处理中的normalization,如std_values=[[128, 128, 128]]表示输入的三个通道减去均值后再除以128
    quantized_dtype: str = 'asymmetric_quantized-8',
        量化类型,目前支持asymmetric_quantized-8、asymmetric_quantized-16
    quantized_algorithm: str = 'normal',
        计算每一层的量化参数时采用的量化算法,目前支持normal、mmse和kl_divergence
        normal:速度快,推荐量化数据量一般为20-100张左右
        mmse:暴力迭代方式,速度较慢,但精度比normal要高,推荐量化数据量20-50张左右
        kl_divergence:所有时间比normal多,比mmse少,适用于feature分布不均匀的场景,推荐量化数据量20-100张左右
    quantized_method: str = 'channel',
        目前支持layer、channel
        layer:每层的weight只有一套量化参数
        channel:每层的weight的每个通道都有一套量化参数,因此channel会比layer精度高
    target_platform: Any | None = None,
        指定RKNN模型是基于那个目标芯片平台生成的,目前支持‘rk3566’、‘rk3588’等
    quant_img_RGB2BGR: bool = False,
        表示在加载量化图像时是否需要先做RGB2BGR的操作(一般用在Caffe模型上)。如果有多个输入,则用列表包括起来,如[True, True, False]
        该配置只对jpg/jpeg/png/bmp格式的图片有效
        该配置仅用于量化阶段(build接口)读取量化图像或量化精度分析(accuracy_analysis接口),并不会保存在最终的RKNN模型中,因此如果模型的输入为bgr,则调用toolkit2的inference或C-API的run函数之前需要保证传入的图像数据为BGR格式
    float_dtype: str = 'float16',
        用于制定非量化情况下的浮点的数据类型,目前只支持float16
    optimization_level: int = 3,
        模型优化等级,通过修改该值可以关掉部分或全部模型转换过程中使用到的优化规则
        optimization_level=3:打开所有优化选项
        optimization_level=1或2:关闭一部分可能会对部分模型精度产生影响的优化选项
        optimization_level=0:关闭所有优化选项
    custom_string: Any | None = None,
        添加自定义字符串信息到RKNN模型,可以在runtime时通过query查询到该信息,方便部署时根据不同的RKNN模型做特殊处理
    remove_weight: bool = False,
        去除conv等权重以生成一个RKNN的从模型,该从模型可以与带完整权重的RKNN模型共享权重以减少内存消耗
    compress_weight: bool = False,
        压缩模型权重,可以减小RKNN模型的大小
    inputs_yuv_fmt: Any | None = None,
    single_core_mode: bool = False,
        是否仅生成单核模型,可以减小RKNN模型的大小和内存消耗,目前仅对RK3588生效
    dynamic_input: Any | None = None,
        用于根据用户制定的多组输入shape,来模拟动态输入的功能,
        格式为[[input0_shapeA, input1_shapeA, ...], [input0_shapeB, input1_shapeB, ...], ...]
        假设原始模型只有一个输入,shape为[1, 3, 224, 224],但需要该模型支持3种不同的输入shape,如[1, 3, 224, 224], [1, 3, 192, 192]和[1, 3, 160, 160]
        可以设置dynamic_input=[1, 3, 224, 224], [1, 3, 192, 192]和[1, 3, 160, 160],转换成RKNN模型后进行推理时,需要传入对应shape的数据
        【注】需要原始模型支持动态输入才可以开启此功能
    model_pruning: bool = False,
        对模型进行无损剪枝,对于权重稀疏的模型,可以减小转换后RKNN模型的大小和计算量
    op_target: Any | None = None,
        用于指定OP的具体执行目标(如NPU/CPU/GPU等)
        格式为{'op0_output_name':'cpu', 'op1_output_name':'npu',...}
        'op0_output_name'和'op1_output_name'对应op的输出tensor名,可以通过精度分析(accuracy_analysis)返回结果中获取
        'cpu'和'npu'表示该tensor对应的op的执行目标是CPU或NPU
    **kwargs: Any
    )
    无返回值
    '''
    rknn.load_pytorch(
        model = "yolov11n-cls.pt",
        input_size_list = [[1, 3, 480, 480]]
    )
    '''
    def load_pytorch(
    model: Any,
        pytorch模型文件(.pt)路径,必须是torchscript格式的
    input_size_list: Any
        每个输入节点对应的shape,所有输入shape存放在一个列表中
    )   
    返回值:0:导入成功;-1;导入失败
    '''

    rknn.build(
        do_quantization=True,
        dataset='datasets.txt'
    )
    '''
    def build(
    do_quantization: bool = True,
        是否对模型进行量化
    dataset: Any | None = None,
        用于量化校正的数据及,目前仅支持文本文件格式,用户可以把用于校正的图片(jpg、bmp或png格式)放到一个.txt文件中,文本文件中每一方存放一条路径信息,如a.jpg
        如果有多个输入,每个输入对应的文件用空格隔开,如a.jpg b.jpg
    rknn_batch_size: Any | None = None
        模型的输入batch参数调整,如果设置为大于1,则可以在一次推理中同时推理多帧输入图像或输入数据
        会同时改变输入和输出的batch
    )
    返回值:0:构建成功;-1:构建失败
    '''
    rknn.export_rknn(
        export_path="yolov11n-cls.rknn"
    )
    '''
    def export_rknn(
    export_path: Any,
        导出模型文件的路径
    cpp_gen_cfg: Any | None = None,
        是否生成C++部署示例,生成文件:模型路径同文件夹下,
        生成rknn_deploy_demo文件夹、说明文档;
        支持验证模型推理是,各CAPI接口耗时;验证推理结果的余弦精度;支持常规API接口;支持图片/NPY输入
    **kwargs: Any
    )
    返回:0:导出成功;-1:导出失败
    '''
    print("finisned")
    rknn.release()

2、torch.nn.module——>onnx——>rknn

可以通过onnx作为中转解决pytorch导出和转换rknn模型的版本不一致问题
参考2:瑞芯微的官方教程
可以看出,onnx转rknn的程序与torch模型转rknn唯一的不同就是在加载模型时,使用load_onnx()
【注】 onnx的opset版本需要注意,如果导出失败可以根据报错提示,去修改导出onnx文件中的opset的版本号,如报错信息为ValueError: Unsupport onnx opset 17, need <= 12!,在导出onnx文件中设置model.export(format=“onnx”, opset=11) 即可

from rknn.api import RKNN

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

    rknn.config(mean_values=[[0.0, 0.0, 0.0]],
                std_values=[[1.0, 1.0, 1.0]],
                target_platform='rk3588')
    
    rknn.load_onnx('yolov11n-cls.onnx')
    '''
    def load_onnx(
    model: Any,
        onnx模型文件路径
    inputs: Any | None = None,
        模型输入节点(tensor名),支持多个输入节点,所有输入节点名放在一个列表中
    input_size_list: Any | None = None,
        每个输入节点对应的shape,所有输入shape放在一个列表中。如果inputs有设置,input_size_list也需要设置
    input_initial_val: Any | None = None,
        设置模型输入的初始值,格式为ndarray的列表。主要用于将某些输入固化为常量,对于不需要固化为常量的输入可以设置为None
    outputs: Any | None = None
        模型的输出节点(tensor名),支持多个输出节点,所有输出节点名放在一个列表中
    )
    返回值:0:导入成功;-1:导入失败
    '''

    rknn.build(do_quantization=True,
               dataset='datasets.txt')
    
    rknn.export_rknn('yolov11n-cls.rknn')

    rknn.release()
    

三、模型推理

模型推理有两种方式:
1、在PC上运行非RKNN模型
2、在NPU上运行RKNN模型

1、在PC上运行非RKNN模型

在这里插入图片描述

实现步骤为:

'''
1、实例化RKNN对象
2、调用Config接口设置模型的预处理参数
3、调用load_pytorch、load_onnx接口导入pytorch\onnx模型等
4、调用build接口构建RKNN模型
5、调用ini_runtime接口初始化运行环境,注意设置target=None,表示在模拟器上运行
6、导入要推理的数据并预处理数据
7、调用inference接口进行推理,获取推理结果
8、释放RKNN对象
'''

实现代码如下:

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

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

    rknn.config(
        mean_values=[[0.0, 0.0, 0.0]], 
        std_values=[[1.0, 1.0, 1.0]],
        target_platform='rk3588'
        
    )

    # rknn.load_pytorch('yolov11n-cls.pt',
    #                   input_size_list=[[1, 3, 480, 480]])
    rknn.load_onnx('yolov11n-cls.onnx',
                   input_size_list=[[1, 3, 480, 480]])

    rknn.build(do_quantization=True, 
               dataset='datasets.txt', 
               rknn_batch_size=-1)
    
    rknn.init_runtime(
        target=None,
        # 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='A6_6499.bmp')
    img = cv2.resize(img, (480, 480))
    cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    outputs = rknn.inference(
        inputs=[img],
        data_format="nhwc",
        '''
        cv2.imread()读取的图像数据的layout为NHWC,data_format的默认值为NHWC,如果模型的输入不是通过cv2.imread()读取,需要设置正确的data_format值
        '''
    )
    print(np.array(outputs[0][0]))
    rknn.release()


2、在NPU上运行RKNN模型

2.1 推理前的准备工作

1)确保开发板的USB OTG连接到PC,并正确识别到设备。可以通过adb device命令查询相应设备,也可调用rknn-toolkit2的list_devices接口查询相应设备。

rknn = RKNN()
rknn.list_devices()
'''
def list_devices():无参数,
	返回adb_devices列表和ntb_devices列表,如果设备为空,则返回空列表
'''
rknn.release()

输出为:
*************************
all device(s) with adb mode:
VD46C3KM6N
*************************

2)参考https://github.com/rockchip-linux/rknpu2/blob/master/rknn_server_proxy.md说明更新开发板的runtime库和rknn_server库,并确保rknn_server服务已经启动(大部分平台需要手动通过串口启动)
3)调用init_runtime接口初始化运行环境时需要指定target参数(开发平台,如target=‘rk3588’)和device_id参数(由步骤2list_devices中获取,如本例程中device_id=‘VD46C3KM6N’)。

2.2 模型推理实现步骤
在这里插入图片描述

'''
运行RKNN模型,不需要设置模型预处理参数,也不需要构建RKNN模型,推理流程:
1、实例化RKNN对象
2、调用load_rknn导入RKNN模型
3、调用init_runtime初始化,注意设置target='rk3588', device_id的值需要通过rknn.list_devices获取
4、导入要处理的数据并处理成需要的输入格式
5、调用inference进行推理并获取推理结果
6、释放RKNN对象
'''

实现代码:

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

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

    rknn.load_rknn('yolov11n-cls.rknn')

    rknn.init_runtime(target='rk3588',
    device_id='VD46C3KM6N')

    img = cv2.imread(filename='A6_6499.bmp')
    img = cv2.resize(img, (480, 480))
    cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    outputs = rknn.inference(
        inputs=[img],
        data_format="nhwc", 
        '''
        cv2.imread()读取的图像数据的layout为NHWC,data_format的默认值为NHWC,如果模型的输入不是通过cv2.imread()读取,需要设置正确的data_format值
        '''
        
    )
    print(np.array(outputs[0][0]))
    rknn.release()

四、模型量化

RKNN模型量化是一种将深度学习模型从浮点精度(如FP32)转换为低比特整数(如INT8)的技术,旨在减少模型体积、提升推理速度并降低功耗。量化对象:权重量化(模型参数从浮点转为整数)、激活量化(推理时中间特征图的数值转换)
4.1 量化原理:

1)线性量化原理

  • 使用比例因子scale和零点zero_point将浮点值映射到整数区间, quantized_value = round(float_value / scale) + zero_point
  • 反量化是还原近似原始值,float_value ≈ (quantized_value - zero_point) * scale

2)校准过程(PTQ)

  • 通过校准数据集统计各层激活值的动态范围,确定最优scale和zero_point
  • 关键作用:减少量化误差,避免数值溢出或截断

3)量化类型

  • 对称量化:零点为0,适合权重分布对称的场景
  • 非对称量化,零点非0,适合偏态分布数据
  • 混合精度量化:敏感层保留FP16,其他层用INT8

4.2 量化精度分析

重点函数为accuracy_analysis()
【注】 该接口只能在build和hybrid_quantization_step2之后调用。
【注】 如未制定target,且原始模型应该为已量化的模型,否则会调用失败
【注】 该接口使用的量化方式与config中制定的一致。

4.2.1 量化精度分析步骤

  • 实例化RKNN对象
  • 设置模型预处理和量化参数
  • 调用load_onnx等接口导入模型
  • 调用build构建模型
  • 调用accuracy_analysis进行量化精度分析
  • 释放RKNN对象

4.2.2 代码实现

from rknn.api import RKNN

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

    rknn.config(
        mean_values=[[0.0, 0.0, 0.0]],
        std_values=[[1.0, 1.0, 1.0]],
        target_platform='rk3588'
    )

    rknn.load_onnx('yolov11n-cls.onnx')

    rknn.build(do_quantization=True, 
               dataset='datasets.txt')
    
    rknn.accuracy_analysis(inputs=['A6_6499.bmp'],
                           output_dir='snapshot',
                           target=None,         # 如果连接了开发板,target='rk3588', device_id=设备编号
                           device_id=None)
    '''
    推理并产生快照,也就是dump出每一层的tensor数据,会dump出包括fp32和quant两种数据类型的快照,用于计算量化误差。
    
    def accuracy_analysis(
    inputs: Any,
        图像(jpg/png/bmp/npy等)路径list
    output_dir: str = './snapshot',
        输出目录,所有快照都保存在该目录下,默认值为'./snapshot'
        如果没有设置target,在output_dir下会输出:
            1、simulator目录:保存整个量化模型在simulator上完整运行时每一层的结果(已经转成float32)
            2、golden目录:保存整个浮点模型在simulator上完整跑下来时每一层的结果
            3、error_analysis.txt:记录simulator上量化模型逐层运行时每一层的结果与golden浮点模型逐层运行时每一层的结果的余弦距离(entire_error cosine),以及量化模型取上一层的浮点结果作为输入时,输出与浮点模型的余弦距离(single_error cosine)
        如果有设置target,则在output_dir里还会多输出:
            1、runtime目录:保存整个量化模型在NPU上完整运行时每一层的结果(已转成float32)
            2、error_analysis.txt:在上述记录内容的基础上,还会记录量化模型在simulator上逐层运行时每一层的结果的余弦距离
    target: Any | None = None,
        目标硬件平台,如果设置了target,则会获取NPU运行时每一层的结果,并进行精度分析
    device_id: Any | None = None
        设备编号,如果pc连接多台设备时,需要指定该参数
    )
    返回值:0:成功;-1:失败
    '''
    
    rknn.release()

4.2.3 输出

在这里插入图片描述
在这里插入图片描述
上图右侧有两列数值输出,其中entire表示simulator上量化模型逐层运行时每一层的结果与golden浮点模型逐层运行时每一层的结果的余弦距离,即量化模型整体输出与原始浮点模型(golden)的误差,反映端到端的累计误差;sigle表示量化模型取上一层的浮点结果作为输入时,输出与浮点模型的余弦距离,反映单层量化精度。值越接近于1表示误差越小。
【警惕关键现象1】 误差值范围,越接近1 表示量化误差越小,若出现显著下降(如0.99以下)须警惕精度损失
【警惕关键现象2】 NaN值,表示张量全零或数值极端,可能由无法激活或量化溢出导致。若存在须检查校准数据或量化参数。

4.2.4 优化建议

1)敏感层定位:对比entire和single误差差异较大层,优先采用混合量化
2)校准数据优化:若误差集中在前几层,需检查输入数据预处理是否与训练一致
3)量化策略调整:对误差突增层尝试非对称量化或调整量化粒度

4.3 混合量化

量化功能可能会使模型特殊模型的精度下降,为了在性能和精度之间做更好的平衡,混合优化功能,可以根据用用户的手动指定某些层是否进行量化。

4.3.1 混合量化步骤

  • 生成混合量化配置文件,hybrid_quatization_step1()
  • 修改第一步生成的量化配置文件(.quantization.cfg)
  • 生成新的RKNN模型,hybrid_quantization_step2()

4.3.2 生成混合量化配置文件

重要API为hybrid_quatization_step1(),执行以下代码会生成临时模型文件(.model)、数据文件(.data)和量化配置文件(.quantization.cfg)
步骤为:

  • 实例化RKNN对象
  • 设置模型预处理参数config
  • 加载模型文件, onnx等
  • 调用hybrid_quantization_step1()
  • 释放RKNN对象
from rknn.api import RKNN

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

    rknn.config(
        mean_values=[[0.0, 0.0, 0.0]],
        std_values=[[1.0, 1.0, 1.0]],
        target_platform='rk3588'
    )

    rknn.load_onnx('./yolov11n-cls.onnx')

    rknn.hybrid_quantization_step1(
        dataset='./datasets.txt',
        proposal=True,
    )
    '''
    用于生成临时模型文件(.model)、数据文件(.data)和量化配置文件(.quantization.cfg)
    def hybrid_quantization_step1(
    dataset: Any | None = None,
        量化用的数据集
    rknn_batch_size: Any | None = None,
        模型的输入batch参数的调整
    proposal: bool = False,
        产生混合量化的配置建议
    proposal_dataset_size: int = 1
        proposal使用的dataset的张数,默认为1.
        因proposal功能比较耗时,所以默认只是用1张,也就是dataset里的第一张
    )
    '''

    rknn.release()

yolov11n-cls.quatization.cfg文件内容如下

custom_quantize_layers:
    /model.0/conv/Conv_output_0: float16
    /model.0/act/Mul_output_0: float16
    /model.1/conv/Conv_output_0: float16
    /model.2/m.0/cv1/conv/Conv_output_0: float16
    /model.2/m.0/cv1/act/Mul_output_0: float16
    /model.2/m.0/Add_output_0: float16
    /model.2/Concat_output_0: float16
    /model.4/m.0/cv2/conv/Conv_output_0: float16
    /model.4/m.0/cv2/act/Mul_output_0: float16
    /model.4/m.0/Add_output_0: float16
    /model.4/Concat_output_0: float16
    /model.4/cv2/conv/Conv_output_0: float16
    /model.4/cv2/act/Mul_output_0: float16
    /model.5/conv/Conv_output_0: float16
    /model.6/m.0/m/m.0/cv1/act/Mul_output_0: float16
    /model.6/m.0/m/m.0/cv2/conv/Conv_output_0: float16
    /model.6/m.0/m/m.0/cv2/act/Mul_output_0: float16
    /model.6/m.0/m/m.0/Add_output_0: float16
    /model.6/m.0/cv3/act/Mul_output_0: float16
    /model.6/Concat_output_0: float16
    /model.8/m.0/m/m.0/cv1/act/Mul_output_0: float16
    /model.8/m.0/m/m.0/cv2/conv/Conv_output_0: float16
    /model.8/m.0/m/m.0/cv2/act/Mul_output_0: float16
    /model.8/m.0/m/m.0/Add_output_0: float16
    /model.8/m.0/m/m.1/cv1/conv/Conv_output_0: float16
    /model.8/m.0/m/m.1/Add_output_0: float16
    /model.8/m.0/m/m.1/cv1/act/Mul_output_0: float16
    /model.8/m.0/m/m.1/cv2/conv/Conv_output_0: float16
    /model.8/m.0/m/m.1/cv2/act/Mul_output_0: float16
    /model.8/m.0/Concat_output_0: float16
    /model.8/m.0/cv3/conv/Conv_output_0: float16
    /model.8/m.0/cv3/act/Mul_output_0: float16
    /model.8/Concat_output_0: float16
    /model.8/cv2/conv/Conv_output_0: float16
    /model.8/cv2/act/Mul_output_0: float16
    /model.9/cv1/conv/Conv_output_0: float16
    /model.9/cv1/act/Mul_output_0: float16
    /model.9/Split_output_0: float16
    /model.9/Concat_output_0: float16
    /model.9/Split_output_1: float16
    /model.9/m/m.0/attn/qkv/conv/Conv_output_0: float16
    /model.9/m/m.0/Add_output_0: float16
    /model.9/m/m.0/attn/Reshape_output_0: float16
    /model.9/m/m.0/attn/Split_output_0: float16
    /model.9/m/m.0/attn/Softmax_output_0: float16
    /model.9/m/m.0/attn/Transpose_1_output_0: float16
    /model.9/m/m.0/attn/MatMul_1_output_0: float16
    /model.9/m/m.0/attn/Reshape_1_output_0: float16
    /model.9/m/m.0/attn/Add_output_0: float16
    /model.9/m/m.0/attn/proj/conv/Conv_output_0: float16
    /model.9/m/m.0/ffn/ffn.0/act/Mul_output_0: float16
    /model.9/m/m.0/ffn/ffn.1/conv/Conv_output_0: float16
    /model.9/cv2/act/Mul_output_0: float16
    /model.10/conv/conv/Conv_output_0: float16
    /model.10/conv/act/Mul_output_0: float16
    /model.10/pool/GlobalAveragePool_2conv_0: float16
    /model.10/pool/GlobalAveragePool_output_0: float16
    /model.10/linear/Gemm_output_0_conv: float16
quantize_parameters:
    images:
        qtype: asymmetric_quantized
        qmethod: layer
        dtype: float32
        min:
        -   0.0
        max:
        -   255.0
        scale: []
        zero_point: []
        ori_min:
        -   0.0
        ori_max:
        -   255.0
      ...
      

其中,custom_quatize_layers是一个自定义量化tensor字典,用户可以将tensor名和相应的量化类型添加到该字典中,即可实现将该tensor作为输出的层的运算类型改为指定的运算类型。上面的文件是我的rknn导出的cfg文件,可以看出custom_quatize_layers已经列了一些优化层了。
quantize_parameters:是模型中每个tensor的量化参数,每一个tensor都是一个字典,每个字典的key为tensor的名,字典的value为量化参数,如果没有经过量化,dtype值为float16

4.3.3 修改第一步生成的量化配置文件(.quantization.cfg)
为了测试一下混合量化,我自己修改了一下我的cfg文件,在上一步量化精度分析中,下面两层的entire和single误差差值有一点点大

[exSwish] /model.4/cv1/act/Mul_output_0                          0.999917  0.999983       
[Split] /model.4/Split_output_0                                  			0.999907  0.999983

因此修改yolov11n-cls.quatization.cfg文件如下
【注】 custom_quantize_layers格式问题,官方文档给的是custom_quantize_layers:{x:float16, x2:float16},但是我这边会报错,改成YAML格式的就好了,不晓得为啥。YAML不需要{},也不需要,作为分割,只要缩进做好就可,详细请参考下述代码

custom_quantize_layers:
    /model.4/cv1/act/Mul_output_0:float16
    /model.4/Split_output_0:float16
 # 将/model.4/cv1/act/Mul_output_0,/model.4/Split_output_0设置为float16,即不进行量化

quantize_parameters:
    images:
        qtype: asymmetric_quantized
        qmethod: layer
        dtype: float32
        min:
        -   0.0
        max:
        -   255.0
        scale: []
        zero_point: []
        ori_min:
        -   0.0
        ori_max:
        -   255.0
    /model.0/conv/Conv_output_0:
        qtype: asymmetric_quantized
        qmethod: layer
        dtype: int8
        min:
        -   -15024.08984375
        max:
        -   9862.2978515625
        scale:
        -   97.59367723651961
        zero_point:
        -   26
        ori_min:
        -   -15024.08984375
        ori_max:
        -   9862.2978515625

4.3.4 生成新的RKNN模型,hybrid_quantization_step2()
步骤为:

  • 实例化RKNN对象
  • 调用hybrid_quantization_step2()
  • 调用accuracy_analysis()再次评估模型,验证混合量化效果
  • 导出RKNN模型
  • 释放RKNN模型
# 混合量化前
[exSwish] /model.4/cv1/act/Mul_output_0                          0.999917  0.999983       
[Split] /model.4/Split_output_0                                  0.999907  0.999983

# 混合量化后
[exSwish] /model.4/cv1/act/Mul_output_0                          0.999791  1.000000       
[Split] /model.4/Split_output_0                                  0.999786  1.000000 

五、模型部署

待更新


网站公告

今日签到

点亮在社区的每一天
去签到