TensorRT转换onnx的Transpose算子遇到的奇怪问题

近来把一个模型导出为onnx并用onnx simplifier化简后转换为TensorRT engine遇到非常奇怪的问题,在我们的网络中有多个检测头时,转换出来的engine的推理效果是正常的,当网络中只有一个检测头时,转换出来的engine的推理效果奇差,类别得分经sigmoid()计算出来的很多很大的值,导致输出上百万个3D box,这明显不正常。

开始以为3D box的C++后处理解码部分有问题,调查折腾了不少时间发现根本没什么大问题,然后想起模型只有一个检测头输出不正常,有多个头时检测头时反而正常,于是去仔细翻看模型网络的实现代码,也没发现什么不对的,很郁闷,想到把用于TensorRT生成engine的onnx可视化出来看有何差异,刚开始看也没发现什么特别的,感觉展示出来的结构都很正确没毛病啊:

那为何多个检测头就正常一个检测头就不行呢?再仔细看代码,发现heatmap这个分支的输出tensor在作permute(onnx里对应的是Transpose)后有这么一句有关:

      result['hm_preds'] =  torch.cat(hm_preds_list, dim=-1)

hm_preds_list是个list,当有多个head时,会有多个hm_preds加入到这个[ ]里,只有一个检测头时就只有一个hm_preds加入这个[ ]里,很显然,当hm_preds_list里只有一个hm_preds时,torch.cat()不会作实质操作,只是依据hm_preds_list里的数据直接输出tensor而已,那我强制只有一个检测头时

<think>我们正在处理一个PyTorch TensorRT ONNXengine时的维度不兼容错误,具体错误信息是“Sub_471维度不兼容广播操作”。这个错误通常发生在尝试进行减法操作(Sub)时,两个输入张量的形状不满足广播规则。 ### 错误原因分析 在深度学习中,广播(Broadcasting)是一种允许不同形状张量进行数学运算的机制。但是,广播需要满足特定规则: 1. 两个张量从后往前逐维度比较,每个维度必须相等,或者其中一个为1,或者其中一个不存在(即维度缺失)。 2. 如果两个张量在某个维度上数值不相等且都不为1,则无法广播。 错误信息中的“Sub_471”表示在计算图中有一个减法操作(节名为Sub_471),其输入的两个张量形状不满足广播规则,导致无法进行减法运算。 ### 可能原因 1. **模型导出问题**:在将PyTorch模型导出为ONNX模型时,可能由于动态维度或某些操作导致ONNX模型中出现了不兼容的形状。 2. **TensorRT版本问题**:使用的TensorRT版本可能对某些ONNX操作支持不完善,或者对广播规则的解释有差异。 3. **模型结构问题**:模型中的某些操作(如减法)的两个输入张量在运行时确实具有不兼容的形状。 ### 解决步骤 #### 1. 检查ONNX模型 使用工具(如Netron)可视化ONNX模型,定位到节“Sub_471”,查看其输入张量的形状。注意检查输入形状是否确实不兼容。 #### 2. 验证ONNX模型 使用ONNX Runtime运行模型,输入一些测试数据,检查是否有错误。这可以帮助确认是ONNX模型本身的问题还是TensorRT转换问题。 ```python import onnxruntime as ort import numpy as np # 加载ONNX模型 ort_session = ort.InferenceSession('model.onnx') # 准备输入数据(根据模型输入形状) input_name = ort_session.get_inputs()[0].name input_shape = ort_session.get_inputs()[0].shape # 注意:将动态维度(如batch)替换为具体值(例如1) input_shape = [1 if dim is None or dim < 0 else dim for dim in input_shape] dummy_input = np.random.randn(*input_shape).astype(np.float32) # 运行推理 try: ort_session.run(None, {input_name: dummy_input}) print("ONNX模型运行成功") except Exception as e: print(f"ONNX模型运行失败: {e}") ``` #### 3. 修改模型 如果ONNX模型本身没有问题,那么可能是TensorRT转换问题。尝试以下方法: - **更新TensorRT和PyTorch**:确保使用最新版本。 - **使用ONNX Simplifier**:简化ONNX模型,可能消除不必要的操作。 ```bash pip install onnx-simplifier python -m onnxsim model.onnx simplified_model.onnx ``` - **显式指定输入形状**:在导出ONNX模型时,使用固定输入形状(避免动态维度)。 ```python torch.onnx.export(model, dummy_input, "model.onnx", input_names=["input"], output_names=["output"], dynamic_axes=None) # 不使用动态轴 ``` #### 4. 调整TensorRT转换参数 在转换时,可以尝试设置明确的优化配置文件(Optimization Profile)来指定输入形状范围,特别是当模型包含动态形状时。 ```python import tensorrt as trt logger = trt.Logger(trt.Logger.WARNING) builder = trt.Builder(logger) network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser = trt.OnnxParser(network, logger) # 解析ONNX模型 with open("model.onnx", "rb") as f: if not parser.parse(f.read()): for error in range(parser.num_errors): print(parser.get_error(error)) # 配置优化配置文件 profile = builder.create_optimization_profile() # 假设输入名为"input",并设置最小、最优、最大形状 profile.set_shape("input", (1, 3, 224, 224), (1, 3, 224, 224), (1, 3, 224, 224)) config = builder.create_builder_config() config.add_optimization_profile(profile) # 构建引擎 engine = builder.build_engine(network, config) ``` #### 5. 修改模型结构 如果以上方法无效,可能需要修改模型结构: - 避免使用动态形状。 - 检查模型中的减法操作,确保两个输入张量可以广播。如果不能,考虑使用重塑(reshape)或置(transpose)等操作调整形状。 ### 总结 该错误通常由模型形状问题引起,通过检查ONNX模型、验证运行、简化模型、固定输入形状等方法通常可以解决。如果问题依旧,可能需要深入模型结构进行修改。 §§相关问题§§ 1. 如何可视化ONNX模型的结构? 2. 在PyTorch中导出ONNX模型时如何设置动态轴? 3. TensorRT的优化配置文件(Optimization Profile)有什么作用? 4. 广播规则(Broadcasting)在深度学习中是如何工作的?</think>### PyTorch TensorRT ONNXEngine维度不兼容错误分析 您遇到的`Sub_471维度不兼容广播操作`错误通常发生在TensorRT尝试解析ONNX模型时,减法操作(Sub)的输入张量形状不满足广播规则。以下是详细分析和解决方案: --- ### 错误根本原因 1. **广播规则冲突** TensorRT要求操作符输入张量必须满足[Numpy广播规则](https://numpy.org/doc/stable/user/basics.broadcasting.html)[^1]: - 规则1:从尾部维度开始逐维比较 - 规则2:每个维度必须相等 **或** 其中一个为1 **或** 其中一个维度不存在 - 示例:`[3, 1, 5]` 和 `[2, 1]` 可广播 → `[3, 2, 5]` - **错误触发**:当`Sub_471`节的输入维度如`[N,C,H,W]`与`[1,C,1,1]`不匹配时 2. **动态维度处理差异** ONNX允许动态维度(如`batch_size`用`-1`表示),但TensorRT需要显式指定优化配置文件: ```python profile = builder.create_optimization_profile() profile.set_shape("input_name", min=(1,3,224,224), opt=(8,3,224,224), max=(32,3,224,224)) # [^2] ``` 3. **PyTorch导出问题** - 未冻结的模型参数(如BatchNorm) - 使用了TensorRT不支持的算子(如某些自定义操作) - 动态控制流(if/for)未正确处理 --- ### 解决方案步骤 #### 1. 检查ONNX模型结构 使用Netron可视化模型(https://netron.app),定位`Sub_471`节: - 检查输入张量维度 - 确认是否包含动态维度(`-1`) #### 2. 显式指定输入维度 导出ONNX时固定动态维度: ```python torch.onnx.export( model, dummy_input, "model.onnx", input_names=["input"], output_names=["output"], dynamic_axes=None, # 禁用动态轴 opset_version=12 # 推荐opset ) ``` #### 3. 添加TensorRT优化配置 ```python import tensorrt as trt builder = trt.Builder(TRT_LOGGER) network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser = trt.OnnxParser(network, TRT_LOGGER) # 关键步骤:设置维度范围 profile = builder.create_optimization_profile() profile.set_shape("input", min=(1,3,224,224), opt=(8,3,224,224), max=(16,3,224,224)) config = builder.create_builder_config() config.add_optimization_profile(profile) # 解析并构建 with open("model.onnx", "rb") as f: parser.parse(f.read()) engine = builder.build_engine(network, config) ``` #### 4. 手动广播兼容性 若维度不匹配,在PyTorch中插入重塑层: ```python # 原始问题代码 x = layer_a(input) # [N, C, H, W] y = layer_b(input) # [C, 1, 1] output = x - y # 触发错误 # 修复方案 y_reshaped = y.view(1, y.shape[0], 1, 1) # [1, C, 1, 1] output = x - y_reshaped # 可广播至[N,C,H,W] ``` #### 5. 验证ONNX模型 使用ONNX Runtime验证导出正确性: ```python import onnxruntime as ort sess = ort.InferenceSession("model.onnx") outputs = sess.run(None, {"input": np.random.rand(8,3,224,224).astype(np.float32)}) ``` --- ### 扩展建议 1. **版本兼容性检查** ``` PyTorch 1.10+ | TensorRT 8.2+ | ONNX opset 12+ ``` 2. **使用ONNX Simplifier** 简化模型结构: ```bash pip install onnx-simplifier python -m onnxsim input.onnx output.onnx ``` 3. **替代方案** 考虑使用TensorRT的PyTorch直接转换: ```python from torch2trt import torch2trt model_trt = torch2trt(model, [dummy_input], max_batch_size=16) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arnold-FY-Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值