3、原始模型准备与预处理:选择适合的深度学习模型(如PyTorch、TensorFlow、ONNX),进行必要的预处理(如归一化、输入尺寸调整),确保模型可被RKNN-Toolkit2正确解析
在RKNN模型转换的完整链路中,原始模型的准备与预处理是决定后续量化精度与部署稳定性的基石。许多开发者在完成模型训练后,直接将其送入RKNN-Toolkit2进行转换,却常常遭遇算子不支持、输入尺寸不匹配、归一化方式错误导致的精度骤降等问题。本章将系统讲解如何选择适合的深度学习模型格式、如何执行必要的预处理操作,以及如何确保模型能够被RKNN-Toolkit2正确解析,从而为后续的batch size调整与精度验证打下坚实基础。
3.1 模型格式选择:从训练框架到RKNN的桥梁
核心原理
RKNN-Toolkit2作为Rockchip提供的模型转换工具,其内部维护了一套算子库和模型解析器,能够将不同深度学习框架训练的模型转换为RKNN格式。然而,不同框架的模型在算子定义、张量布局、动态维度支持等方面存在差异,这直接影响转换的成功率和精度。PyTorch模型通常以动态图形式存在,包含大量Python运行时逻辑,无法直接被RKNN-Toolkit2解析;TensorFlow的SavedModel或冻结图(.pb)虽然结构清晰,但部分算子(如自定义Op)需要额外映射;ONNX作为一种开放格式,提供了标准化的算子集和计算图描述,是目前RKNN-Toolkit2支持最完善的格式。
判断方法或操作流程
选择模型格式时,应遵循以下优先级原则:ONNX优先,其次为TensorFlow冻结图,最后考虑PyTorch导出。具体操作流程如下:
- 检查算子兼容性:使用RKNN-Toolkit2提供的
rknn.load_onnx()或rknn.load_tensorflow()加载模型,观察是否出现"Unsupported Op"或"Warning"日志。 - 导出ONNX模型:若原始模型为PyTorch,使用
torch.onnx.export()导出,需指定opset_version=11或更高版本,并设置dynamic_axes处理动态batch维度。 - 简化模型结构:使用
onnx-simplifier工具消除冗余节点,减少转换时的解析负担。 - 验证模型完整性:使用
onnxruntime加载导出的ONNX模型,运行一次推理,确保输出与原始PyTorch模型一致。
案例拆解:PyTorch YOLOv5模型导出为ONNX
假设我们有一个训练好的YOLOv5s模型(PyTorch格式),目标是在RK3588平台上部署。初始现象是直接使用rknn.load_pytorch()加载时,工具报错"AttributeError: 'YOLOv5' object has no attribute 'eval'"。分析发现,RKNN-Toolkit2对PyTorch模型的支持有限,仅能解析通过torch.jit.trace或torch.jit.script导出的TorchScript模型,而YOLOv5的检测头包含动态控制流,无法直接trace。
解决路径如下:
- 使用YOLOv5官方提供的
export.py脚本,导出ONNX模型:python export.py --weights yolov5s.pt --include onnx --opset 12。 - 导出后使用
onnxruntime验证输出张量形状为[1, 25200, 85](batch=1, anchors=25200, classes+5),与PyTorch输出一致。 - 使用
onnx-simplifier简化模型,将Shape、Gather等动态节点静态化。 - 最终使用
rknn.load_onnx(model='yolov5s.onnx')成功加载,转换过程无警告。
此案例中,关键指标是导出后的ONNX模型在onnxruntime下的推理输出与原始PyTorch模型的余弦相似度应大于0.99。若相似度低于0.95,则需检查导出时的opset_version或模型中的自定义算子。
常见误区或总结复盘
- 误区一:认为所有PyTorch模型都能直接通过
load_pytorch()加载。实际上,RKNN-Toolkit2仅支持TorchScript格式,且要求模型结构完全静态。 - 误区二:忽略ONNX的算子版本。低版本opset可能缺少某些算子(如
ScatterND),导致转换失败。 - 误区三:导出ONNX后不进行验证,直接送入RKNN-Toolkit2,导致后续精度问题难以定位。
总结:模型格式选择的核心是确保模型结构静态化、算子标准化、验证闭环化。ONNX作为中间格式,是连接训练框架与RKNN的最佳桥梁。
3.2 数据预处理:归一化、尺寸调整与布局转换
核心原理
RKNN模型在NPU上执行推理时,输入数据需要满足特定的数值范围和内存布局。原始训练时的预处理(如ImageNet的mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225])必须与RKNN-Toolkit2配置的mean_values和std_values完全一致。此外,输入尺寸需与模型定义时的input_size_list匹配,且数据布局需为NCHW(PyTorch默认)或NHWC(TensorFlow默认),RKNN-Toolkit2在转换时会根据config中的reorder_channel参数自动处理通道顺序。
判断方法或操作流程
预处理配置的完整流程如下:
- 确定归一化参数:从训练脚本中提取mean和std值,注意是逐通道的浮点数数组。
- 设置输入尺寸:在
rknn.config()中指定mean_values=[[m1,m2,m3]]、std_values=[[s1,s2,s3]],并设置target_platform='rk3588'。 - 调整输入张量布局:若模型为PyTorch导出(NCHW),而RKNN默认使用NHWC,需在
rknn.config()中设置reorder_channel='0 1 2'(表示保持RGB顺序)或'2 1 0'(转换为BGR)。 - 验证预处理一致性:使用
rknn.list_support()查看支持的算子,并通过rknn.init_runtime()加载模拟器,输入一张预处理后的图片,对比输出与原始模型输出的差异。
案例拆解:MobileNetV2分类模型的预处理配置
假设我们有一个TensorFlow训练的MobileNetV2模型,输入尺寸为224x224,训练时归一化方式为tf.keras.applications.mobilenet_v2.preprocess_input,该函数将像素值从[0,255]映射到[-1,1](即mean=127.5, std=127.5)。初始目标是在RKNN上达到与TensorFlow一致的Top-1准确率(约71.8%)。
操作步骤如下:
- 在
rknn.config()中设置mean_values=[[127.5,127.5,127.5]]、std_values=[[127.5,127.5,127.5]]。 - 由于TensorFlow模型默认输入为NHWC,而RKNN内部使用NCHW,需设置
reorder_channel='0 1 2'(保持RGB顺序)。 - 使用
rknn.load_tensorflow(tf_pb='mobilenetv2.pb', input_size_list=[[1,224,224,3]])加载模型。 - 转换后,使用
rknn.inference(inputs=[img])进行推理,其中img为经过cv2.resize和img.astype('float32')的原始图像(未归一化),因为RKNN会在NPU内部自动执行归一化。
结果对比:转换后的RKNN模型在100张测试图片上的Top-1准确率为71.5%,与TensorFlow的71.8%相差0.3%,在可接受范围内。若准确率下降超过1%,则需检查reorder_channel是否设置错误(如RGB与BGR混淆)。
常见误区或总结复盘
- 误区一:在送入RKNN推理前,手动对输入图片进行归一化,导致数据被归一化两次,精度严重下降。正确做法是:RKNN的
inference接口会自动应用配置的mean/std,输入应为原始像素值(0-255)。 - 误区二:忽略
reorder_channel参数。若模型训练时使用RGB顺序,而RKNN默认按BGR处理,则颜色通道错乱,精度几乎归零。 - 误区三:输入尺寸与
input_size_list不一致。例如模型输入为224x224,但送入320x320的图像,RKNN会报错或自动裁剪,导致特征丢失。
总结:预处理配置的核心是“一致性”——归一化参数、输入尺寸、通道顺序必须与训练时完全一致。建议在转换前编写一个验证脚本,使用同一张图片分别通过原始模型和RKNN模型推理,对比输出差异。
3.3 确保模型可被RKNN-Toolkit2正确解析:算子映射与结构检查
核心原理
RKNN-Toolkit2在加载模型时,会将模型的计算图逐节点映射到NPU支持的算子库中。若遇到不支持的算子(如Einsum、GatherND),工具会抛出警告或直接失败。此外,模型的输入输出张量名称、形状、数据类型(float32/float16)也需要与RKNN的预期匹配。通过rknn.summary()可以查看模型的结构概览,包括每层的算子类型、输出形状和参数量。
判断方法或操作流程
确保模型可解析的检查流程如下:
- 加载模型并查看日志:执行
rknn.load_onnx(model='model.onnx'),观察控制台输出。若出现"WARNING: Op [X] is not supported",则需记录该算子名称。 - 使用
rknn.summary()检查结构:输出模型的总层数、算子类型分布、输入输出张量信息。 - 处理不支持的算子:若存在不支持的算子,可尝试以下方案:a) 修改模型结构,用支持的算子替代(如将
GatherND替换为多个Gather+Reshape);b) 使用onnx2rknn的custom_op注册自定义算子;c) 将模型拆分为多个子图,分别转换后合并。 - 验证输入输出张量:确保输入张量的形状为
[batch, channels, height, width](NCHW)或[batch, height, width, channels](NHWC),且数据类型为float32。
rknn.accuracy_analysis()方法,可以在转换后对模型进行逐层精度分析,定位精度损失的具体层。该功能在batch size调整后尤为重要,可帮助判断量化误差是否随batch增大而累积。
案例拆解:处理ONNX模型中的不支持的Resize算子
某目标检测模型在转换时,RKNN-Toolkit2报错"Unsupported Op: Resize (mode='linear', coordinate_transformation_mode='align_corners')"。初始现象是转换中断,无法生成RKNN模型。分析发现,RKNN的Resize算子仅支持nearest和bilinear模式,且align_corners参数不支持。
解决路径:
- 使用
onnxruntime检查模型中的Resize节点参数,确认其mode和coordinate_transformation_mode。 - 修改ONNX模型,将
Resize替换为Upsample(旧版算子)或使用ConvTranspose替代。具体操作:使用onnx_graphsurgeon库编辑模型图,删除原Resize节点,插入新的Upsample节点,并设置mode='nearest'。 - 重新导出ONNX,再次加载到RKNN-Toolkit2,转换成功。
此案例中,关键指标是替换后的模型在onnxruntime下的输出与原始模型的平均绝对误差(MAE)小于0.01。若MAE过大,说明替换算子改变了特征图语义,需调整替代方案。
常见误区或总结复盘
- 误区一:认为所有ONNX模型都能直接转换。实际上,RKNN对动态形状(如动态batch)支持有限,需在导出时固定batch维度或使用
dynamic_axes但转换时指定具体值。 - 误区二:忽略
rknn.summary()的输出,导致模型结构错误(如输入输出张量名称不匹配)未被发现。 - 误区三:在转换前不进行精度验证,直接部署到硬件,导致问题排查困难。
总结:确保模型可解析的关键是“提前检查、逐层验证、及时替换”。建议在转换前使用rknn.list_support()查看目标平台支持的算子列表,并对照模型结构进行预检。
3.4 综合案例:从PyTorch模型到RKNN的完整预处理流程
为综合展示上述知识点,我们设计一个完整的端到端案例:将PyTorch训练的ResNet18模型(输入224x224,1000类)转换为RKNN格式,并验证batch size=1时的精度。
背景与约束:目标平台为RK3588,NPU算力6 TOPS,内存带宽足够。模型在ImageNet验证集上Top-1准确率为69.7%。要求转换后精度损失不超过1%。
操作流程:
| 步骤 | 操作 | 关键参数/命令 | 验证指标 |
|---|---|---|---|
| 1. 导出ONNX | 使用torch.onnx.export | opset_version=12, dynamic_axes={'input':{0:'batch'}} | onnxruntime输出与PyTorch一致 |
| 2. 简化模型 | onnx-simplifier | --overwrite-input-shape 1,3,224,224 | 简化后模型大小减小5% |
| 3. 配置RKNN | rknn.config | mean_values=[[0.485,0.456,0.406]], std_values=[[0.229,0.224,0.225]], reorder_channel='0 1 2' | 无警告 |
| 4. 加载模型 | rknn.load_onnx | model='resnet18.onnx', input_size_list=[[1,3,224,224]] | 加载成功,无Unsupported Op |
| 5. 转换模型 | rknn.build | do_quantization=True, dataset='dataset.txt' | 量化后模型大小约4.5MB |
| 6. 精度验证 | rknn.accuracy_analysis | 输入100张验证集图片 | Top-1准确率≥68.7% |
结果对比:转换后的RKNN模型Top-1准确率为69.2%,损失0.5%,满足要求。若损失超过1%,则需检查dataset.txt中的校准图片是否覆盖足够多的类别,或调整量化方案(如使用do_quantization=False进行浮点转换对比)。
风险与代价:使用动态batch导出时,RKNN-Toolkit2在转换时会固定batch为1,若后续需要调整batch size,需重新转换模型。此外,量化校准数据集的大小直接影响精度,建议至少使用500张代表性图片。
复盘经验:预处理流程中,最耗时的是算子兼容性检查和精度验证。建议编写自动化脚本,将导出、简化、转换、验证串联起来,减少人工干预。同时,保留原始模型和预处理配置的版本记录,便于问题回溯。
rknn.config()中修改input_size_list的batch维度,并重新执行rknn.build(),无需修改模型结构。