pth模型转onnx模型记录

本文详细记录了如何将使用nn.Sequential的PyTorch模型拆分为特征提取网络、图像特征网络和head部分,并分别导出为ONNX格式,以便后续进行RKNN转换,同时提供了关键代码和步骤。

记录一次pth转onnx

nanotrack中pth转onnx(原项目在这里插入图片描述
因为使用nn.Sequential()定义网络,只接受单输入单输出,所以要将原模型进行解构:模板T的特征提取网络、图像X的特征提取网络、模型head部分。这三部分均要进行保存、转换过程。(转换过程中设置好输入参数,方便进行下一步rknn的转换)

pth转onnx:

import argparse
import os
import torch
import sys 

sys.path.append(os.getcwd()) 

from nanotrack.core.config import cfg

from nanotrack.utils.model_load import load_pretrain
from nanotrack.models.model_builder import ModelBuilder

os.environ["CUDA_VISIBLE_DEVICES"] = "0"  

parser = argparse.ArgumentParser(description='lighttrack')

parser.add_argument('--config', type=str, default='./m
<think>我们正在解决RegNet模型从.pth换为ONNX时精度下降的问题。以下是可能的解决方案: 1. **检查换脚本**:确保模型换脚本正确,包括输入尺寸、输出节点设置等。 2. **验证输入数据**:换和推理时使用相同的预处理和后处理。 3. **模型版本对齐**:确保使用的PyTorch、ONNX和推理引擎版本兼容。 4. **操作符支持**:检查ONNX是否支持RegNet中的特殊操作符。 5. **量化影响**:如果使用了量化,尝试不使用量化换。 6. **自定义操作**:实现缺失操作符的ONNX自定义版本。 7. **中间层输出对比**:逐层对比PyTorch和ONNX输出以定位问题层。 8. **使用ONNX Runtime**:验证ONNX模型ONNX Runtime上的精度。 9. **更新换工具**:尝试最新版本的换工具(如PyTorch的ONNX导出)。 ### 操作步骤 1. 导出ONNX模型: ```python import torch from regnet import RegNet # 导入你的RegNet模型 model = RegNet() # 实例化模型 model.load_state_dict(torch.load("model.pth")) model.eval() dummy_input = torch.randn(1, 3, 224, 224) # 根据实际输入尺寸调整 torch.onnx.export( model, dummy_input, "regnet.onnx", opset_version=13, # 建议使用较高版本(如13+) input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}} # 若需动态批处理 ) ``` 2. 验证ONNX模型: ```python import onnxruntime import numpy as np ort_session = onnxruntime.InferenceSession("regnet.onnx") input_name = ort_session.get_inputs()[0].name # 使用相同输入数据 np_input = np.random.randn(1, 3, 224, 224).astype(np.float32) ort_output = ort_session.run(None, {input_name: np_input})[0] # 与PyTorch输出对比 with torch.no_grad(): torch_output = model(torch.from_numpy(np_input)).numpy() print("最大误差:", np.max(np.abs(torch_output - ort_output))) ``` ### 常见问题修复 - **精度误差较大**:尝试增加`opset_version`(如15) - **不支持操作符**: - 查找替代实现(如将`SiLU`拆分为`Sigmoid+Multiply`) - 使用自定义操作符(需在推理引擎中注册) - **动态维度问题**:确保`dynamic_axes`设置正确 ### 高级调试 使用`onnxruntime`的`InferenceSession`配置选项启用扩展日志: ```python sess_options = onnxruntime.SessionOptions() sess_options.log_severity_level = 0 # 0:详细, 1:信息, 2:警告, 3:错误, 4:致命 sess_options.enable_profiling = True ort_session = onnxruntime.InferenceSession("regnet.onnx", sess_options) ``` 通过对比日志可定位计算不一致的层。 §§相关问题§§ 1. 如何为不支持的操作符创建ONNX自定义算子? 2. ONNX Runtime性能优化有哪些技巧? 3. 如何可视化ONNX模型结构以辅助调试? </think>针对RegNet模型从.pth换为ONNX时出现精度下降的问题,以下是系统化的解决方案和关键步骤,结合模型换原理和实践经验: ### 一、核心问题诊断 1. **操作符兼容性问题**(最常见原因) RegNet可能包含ONNX不原生支持的操作: - 特殊激活函数(如SiLU)需显式分解为$sigmoid(x) \times x$ - 自定义池化层需验证输出对齐 - 检查Group Normalization等操作实现差异 2. **量化损失累积** 浮点精度换时易出现$ \Delta \epsilon $累积误差,尤其: - 模型包含深度可分离卷积 - 存在高精度计算分支(如注意力机制) - 参考[^3]中量化策略差异 3. **张量维度对齐错误** ONNX对动态轴支持有限,需检查: ```python torch.onnx.export(..., dynamic_axes={'input': {0: 'batch_size'}}) ``` ### 二、解决方案流程 #### 步骤1:验证基础换 ```python import torch from regnet_model import RegNet # 替换为实际模型加载方式 model = RegNet().eval() model.load_state_dict(torch.load("regnet.pth")) dummy_input = torch.randn(1, 3, 224, 224) # 需匹配训练尺寸 # 关键导出参数 torch.onnx.export( model, dummy_input, "regnet.onnx", opset_version=13, # 推荐≥13以支持新算子 do_constant_folding=True, input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch"}} ) ``` #### 步骤2:精度验证脚本 ```python import onnxruntime as ort import numpy as np # 相同输入对比输出 input_data = np.random.rand(1, 3, 224, 224).astype(np.float32) # PyTorch推理 torch_out = model(torch.tensor(input_data)).detach().numpy() # ONNX推理 ort_sess = ort.InferenceSession("regnet.onnx") onnx_out = ort_sess.run(None, {"input": input_data})[0] # 计算误差 print(f"最大绝对误差: {np.max(np.abs(torch_out - onnx_out))}") print(f"相对误差均值: {np.mean(np.abs((torch_out - onnx_out)/(torch_out + 1e-7)))}") ``` #### 步骤3:针对性修复方案 | 问题类型 | 解决方案 | 代码示例 | |---------|---------|---------| | **不支持的算子** | 实现自定义OP或算子分解 | `torch.onnx.register_custom_op(...)` | | **动态形状错误** | 显式指定动态轴 | `dynamic_axes={'input': {2: 'height', 3: 'width'}}` | | **精度累积误差** | 强制FP32模式导出 | `model.float()` 或禁用量化 | | **归一化层差异** | 冻结BN层参数 | `model.eval()` 并确认training=False | ### 三、高级调试工具 1. **ONNX模型可视化** 使用Netron工具检查计算图:https://netron.app/ - 定位红色警告节点(不支持的操作符) - 验证所有输入/输出维度 2. **层间输出对比** 插入中间层输出检查: ```python # 在模型中插入hook layer_outputs = {} def hook(module, input, output): layer_outputs[module.name] = output model.conv1.register_forward_hook(hook) ``` 3. **ONNX优化器** 使用ONNX Runtime工具包优化: ```bash python -m onnxruntime.tools.convert_onnx_models_to_ort --optimize regnet.onnx ``` ### 四、推荐实践 1. **版本匹配原则**: - PyTorch ≥ 1.10 - ONNX opset ≥ 13 - ONNX Runtime ≥ 1.12 2. **验证环境隔离**: 使用Docker容器确保库版本一致性: ```dockerfile FROM pytorch/pytorch:1.12.1-cuda11.3-cudnn8-runtime RUN pip install onnx onnxruntime-gpu==1.12.0 ``` > **关键提示**:根据引用[^3]的实践,使用`onnx_graphsurgeon`工具修改计算图可解决90%以上兼容性问题,尤其对于自定义OP的插入和替换效果显著。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值