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

2024-02-18 08:04

本文主要是介绍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而已,那我强制只有一个检测头时也作和有多个检测头时一样的算子运算会如何?于是修改代码当网络只配置有一个检测头时,将这个hm_preds tensor自己和自己强制来个Concat,也就是相当于torch.cat([hm_preds, hm_preds], dim=-1),然后为保持输出tensort的维度不变进行了切片,得到的网络结果是这样:

然后导出onnx并用onnx simplifier化简,生成TensorRT engine后推理结果就正常了!

那为何强制加了Concat后输出结果就正常了呢?再回头看从pytorch导出onnx和onnx化简全过程中网络结构上的变化,发现上面有一个检测头和有多个检测头时的网络的onnx图,发现,只有一个检测头时,像上面提到,因为torch.cat()没有实质操作,pytorch导出onnx时虽然在onnx生成了Concat算子节点,但是后面用onnx simplifier化简时,它会把这个Concat算子节点删掉,Transpose算子的输出就直接作为网络的hm_preds输出了,而有多个检测头时,torch.cat()会有实质拼接操作,Concat算子自然被onnx simplifier保留了,所以生成的TensorRT engine的推理结果正常!

于是我修改脚本,当网络只有一个检测头时,在调用onnx simplifier化简网络后,在Transpose算子节点后和网络的输出节点hm_preds之间强制增加Concat算子节点(注意指定attrs={"axis":-1})

然后再生成TensorRT engine,然后用这个engine推理就一切正常了!

再回头仔细想想这个问题的最终原因,当只有一个检测头时,TensorRT在对hm_preds tensor 作Transpose后因为后续没有其他算子了,没有触发输出Transpose后的tensor值而是把原始tensor值输出了?或者因为Transpose输出的hm_preds tensor在加入hm_preds_list后,因为hm_preds_list不是tensor,TensorRT把它丢弃了,直接用的Transpose处理前的tensor值?只能等后面哪天有时间再实验找找根本原因。

附上增加Concat节点的相关代码(:

  hm_node = graph.outputs[1]check_node = hm_node.inputs[0]if check_node.op == 'Transpose':  # only one head, no concat, need to add it forciblytranspose_out = [gs.Variable("transpose_out", shape=hm_node.shape, dtype=hm_node.dtype)]check_node.outputs = transpose_outgraph.layer(name="Concat_199", op= 'Concat', inputs=transpose_out, outputs=[hm_node], attrs={"axis":-1})graph.cleanup().toposort()

我们修改onnx使用的NVIDIA的ONNX GraphSurgeon,它封装后用起来比较简单,感觉比直接使用onnx的API修改网络容易得多,具体文档和examples可参见:

ONNX GraphSurgeonicon-default.png?t=N7T8https://docs.nvidia.com/deeplearning/tensorrt/onnx-graphsurgeon/docs/index.html

 Examplesicon-default.png?t=N7T8https://github.com/NVIDIA/TensorRT/tree/main/tools/onnx-graphsurgeon/examples

这篇关于TensorRT转换onnx的Transpose算子遇到的奇怪问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/720543

相关文章

mybatis和mybatis-plus设置值为null不起作用问题及解决

《mybatis和mybatis-plus设置值为null不起作用问题及解决》Mybatis-Plus的FieldStrategy主要用于控制新增、更新和查询时对空值的处理策略,通过配置不同的策略类型... 目录MyBATis-plusFieldStrategy作用FieldStrategy类型每种策略的作

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

Python Jupyter Notebook导包报错问题及解决

《PythonJupyterNotebook导包报错问题及解决》在conda环境中安装包后,JupyterNotebook导入时出现ImportError,可能是由于包版本不对应或版本太高,解决方... 目录问题解决方法重新安装Jupyter NoteBook 更改Kernel总结问题在conda上安装了

pip install jupyterlab失败的原因问题及探索

《pipinstalljupyterlab失败的原因问题及探索》在学习Yolo模型时,尝试安装JupyterLab但遇到错误,错误提示缺少Rust和Cargo编译环境,因为pywinpty包需要它... 目录背景问题解决方案总结背景最近在学习Yolo模型,然后其中要下载jupyter(有点LSVmu像一个

解决jupyterLab打开后出现Config option `template_path`not recognized by `ExporterCollapsibleHeadings`问题

《解决jupyterLab打开后出现Configoption`template_path`notrecognizedby`ExporterCollapsibleHeadings`问题》在Ju... 目录jupyterLab打开后出现“templandroidate_path”相关问题这是 tensorflo

如何解决Pycharm编辑内容时有光标的问题

《如何解决Pycharm编辑内容时有光标的问题》文章介绍了如何在PyCharm中配置VimEmulator插件,包括检查插件是否已安装、下载插件以及安装IdeaVim插件的步骤... 目录Pycharm编辑内容时有光标1.如果Vim Emulator前面有对勾2.www.chinasem.cn如果tools工

在MySQL执行UPDATE语句时遇到的错误1175的解决方案

《在MySQL执行UPDATE语句时遇到的错误1175的解决方案》MySQL安全更新模式(SafeUpdateMode)限制了UPDATE和DELETE操作,要求使用WHERE子句时必须基于主键或索引... mysql 中遇到的 Error Code: 1175 是由于启用了 安全更新模式(Safe Upd

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明