记录一次复杂的 ONNX 到 TensorRT 动态 Shape 转换排错过程

我在将 encoder 的 ONNX 模型转换成 TensorRT 格式时遇到了错误:“shape tensor must have build-time extent”。从报错信息看,ONNX 的 Range 算子在转换时被视为 shape tensor,而 TensorRT 要求 shape tensor 在 build 时维度必须是已知常量。

通过 Netron.app 可视化发现,Range 算子的 limit 参数依赖于上一个 Cast 算子的输出:

为了进一步排查,我向 ONNX 图中添加了额外的输出 tensor,打印 Range 算子上下游的输入和输出:

definspect_all_tensors(onnx_path,target_tensor_name,input_feed):model=onnx.load(onnx_path)inferred_model=onnx.shape_inference.infer_shapes(model)all_tensors=(list(inferred_model.graph.value_info)+list(inferred_model.graph.input)+list(inferred_model.graph.output))fortinall_tensors:ift.nameintarget_tensor_name:model.graph.output.append(t)modified_model_bytes=model.SerializeToString()sess=onnxruntime.InferenceSession(modified_model_bytes)output_names=[output.nameforoutputinsess.get_outputs()]outputs=sess.run(output_names,input_feed)results={name:valueforname,valueinzip(output_names,outputs)}forname,valueinresults.items():print(f"{name}:{value.shape}{value.dtype}{value}")

打印结果如下:

onnx::ReduceSum_851: (1,) int64 [1] onnx::Unsqueeze_953: (1,) int64 [0] /ReduceMax_output_0: () int64 13 /Range_output_0: (13,) int64 [ 0 1 2 3 4 5 6 7 8 9 10 11 12] /Unsqueeze_output_0: (1, 13) int64 [[ 0 1 2 3 4 5 6 7 8 9 10 11 12]] /Where_output_0: (2,) int64 [ 1 13] /Expand_output_0: (1, 13) int64 [[ 0 1 2 3 4 5 6 7 8 9 10 11 12]]

这里的 Range 输出长度达 13,考虑到后续图中不太可能存在如此高维的 tensor,因此错误日志的含义可能是:

这里试图让一个数据张量(Range 的输出)的长度(extent)依赖于一个形状张量,而 TensorRT 在构建时无法将这个依赖关系静态化。

替换后的结构图如下。由于 TopK 仅支持 f32 和 f16 类型的 tensor,因此需要在 TopK 的输入输出端加上 Cast 算子:

我尝试用 TopK 算子代替 ReduceMax,使其生成一个 shape tensor 而非 data tensor,但仍然出现错误:

Error[9]: [graph.cpp::computeInputExecutionUses::553] Error Code 9: Internal Error (/TopK_for_/ReduceMax: ITopKLayer cannot be used to compute a shape tensor)

TopK 的输出依然不能作为 shape tensor,因为:

TensorRT 可以处理动态形状,但有一个前提:所有用来决定张量形状的计算,必须只依赖于输入的【形状】,而不能依赖于输入的【内容/值】。

因此,根源在于输入设置不合理。这里的输入x_lens是一个一维动态 tensor,表示这个 batch 的输入长度,最终在上图的一些节点计算下变成一个 mask tensor。如果直接将输入改为该 mask tensor,就可以避免上述错误:

defsolve_replace_dynamic_range_with_mask_input(onnx_path):model=onnx.load(onnx_path)ir_version=model.ir_version graph=gs.import_onnx(model)x_len_mask=gs.Variable(name=f"x_len_mask",dtype=np.bool_,shape=['N','L'])fornodeingraph.nodes:fori,input_tinenumerate(node.inputs):ifinput_t.name=="/GreaterOrEqual_output_0":print(f"found node :{node}")node.inputs[i]=x_len_mask inputs_to_delete_set=["x_lens"]outputs_to_delete_set=["encoder_out_lens"]graph.inputs=[inpforinpingraph.inputsifinp.namenotininputs_to_delete_set]graph.outputs=[outforoutingraph.outputsifout.namenotinoutputs_to_delete_set]graph.inputs.append(x_len_mask)graph.cleanup()graph.toposort()onnx.save(gs.export_onnx(graph,ir_version=ir_version),"./onnx/encoder_mask_input_solved.onnx")

我直接将通过x_lens输入得到的 tensor/GreaterOrEqual_output_0替换成动态输入 tensorx_len_mask,然后删除原有的输入x_lens以及通过x_lens得到的输出encoder_out_lens。接着重新通过 trtexec 进行转换,整个转译时间比之前长了很多,这个问题大概率得到解决,但后面出现了新的问题:

Error Code 2: Internal Error (/encoder/Slice_2 requires bool I/O but node can not be handled by Myelin. Dynamic shapes are not equal for slice params.)

原因出在/encoder/Slice_2节点的输入是动态输入x_len_mask。因此,我只能把 Slice 节点也替换掉。这里使用Range + Gather来替换 Slice 节点,但问题在于 Range 节点的 limit 参数不支持 INF,只能通过 Shape 以及 Gather 算子获取。最终的网络结构如下:

继续转换后,这个过程持续时间很长,上面的算子不兼容问题应该算是解决了,但在构建优化配置的时候出现了错误:

[12/13/2025-17:14:45] [I] [TRT] Local timing cache in use. Profiling results in this builder pass will not be stored.

[12/13/2025-17:14:45] [V] [TRT] Constructing optimization profile number 0 [1/1].

[12/13/2025-17:14:45] [E] Error[2]: [shapeContext.cpp::checkVolume::2379] Error Code 2: Internal Error (Assertion bound >= 0 failed.)

很奇怪,ONNX 模型本身可以正常运行,且结果与原模型一致,但在转换时就出现错误:

/usr/src/tensorrt/bin/trtexec --onnx=./onnx/encoder.onnx --saveEngine=./tensorrt/encoder.engine --minShapes=x:1x16x80,x_len_mask:1x4 --optShapes=x:8x512x80,x_len_mask:8x252 --maxShapes=x:16x384000x80,x_len_mask:16x191996 --verbose

一开始以为是 minShapes 给的太小导致出现了小于 0 的 shape,但后面扩大到x:1x128x80,x_len_mask:1x60也没能解决问题。我想通过打印每个 tensor 的 shape 来检查,但始终不是很方便。后来使用 polygraphy 检查是哪个 tensor 的 shape 出现了问题:

polygraphy run --onnxrt ./onnx/encoder_range_gather_mask_input_solved_v1.onnx --input-shapes 'x:[1,16,80]' 'x_len_mask:[1,8]' polygraphy run --onnxrt ./onnx/encoder-iter-5576000-avg-20-simplified.onnx --input-shapes 'x:[1,16,80]' 'x_lens:[16]'

但这次出现了不一样的错误:

'/encoder/0/layers.0/self_attn_weights/Where' Status Message ... axis == 1 || axis == largest was false. Attempting to broadcast an axis by a dimension other than 1. 4 by 8

问题越来越多了,我怀疑是 TensorRT 的版本太低,导致 dynamic shape 支持得不好。随后找 SRE 升级了 CUDA 驱动至 12.4,然后使用基于 TensorRT 10.0 的基础镜像,Dockerfile 如下:

# nVidia TensorRT Base Image # https://docs.nvidia.com/deeplearning/frameworks/container-release-notes/index.html#rel-25-06 # tensorrt 10.x support more onnx ops with dynamic shape ARG TRT_CONTAINER_VERSION=24.05 FROM nvcr.io/nvidia/tensorrt:${TRT_CONTAINER_VERSION}-py3 ARG ONNXRUNTIME_REPO=https://github.com/Microsoft/onnxruntime ARG ONNXRUNTIME_BRANCH=main # Adjust as needed # Check your CUDA arch: https://developer.nvidia.com/cuda-gpus ARG CMAKE_CUDA_ARCHITECTURES=75 RUN apt-get update &&\ apt-get install -y sudo git bash unattended-upgrades RUN unattended-upgrade WORKDIR /code ENV PATH=/usr/local/nvidia/bin:/usr/local/cuda/bin:/code/cmake-3.31.5-linux-x86_64/bin:${PATH} # Prepare onnxruntime repository & build onnxruntime with TensorRT RUN git clone --single-branch --branch ${ONNXRUNTIME_BRANCH} --recursive ${ONNXRUNTIME_REPO} onnxruntime &&\ /bin/sh onnxruntime/dockerfiles/scripts/install_common_deps.sh &&\ trt_version=${TRT_VERSION:0:4} &&\ # /bin/sh onnxruntime/dockerfiles/scripts/checkout_submodules.sh ${trt_version} &&\ cd onnxruntime &&\ /bin/sh build.sh --allow_running_as_root --parallel --build_shared_lib --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu/ --use_tensorrt --tensorrt_home /usr/lib/x86_64-linux-gnu/ --config Release --build_wheel --skip_tests --skip_submodule_sync --cmake_extra_defines '"CMAKE_CUDA_ARCHITECTURES='${CMAKE_CUDA_ARCHITECTURES}'"' &&\ pip install /code/onnxruntime/build/Linux/Release/dist/*.whl &&\ cd ..

然后直接使用最原始的 ONNX 模型进行转换,果然,之前的错误消失了,但又出现了新的问题:

[01/06/2026-12:05:53] [E] Error[4]: [graphShapeAnalyzer.cpp::analyzeShapes::2084] Error Code 4: Miscellaneous (IConditionalOutputLayer /encoder/1/encoder/encoder_pos/If_OutputLayer: /encoder/1/encoder/encoder_pos/If_OutputLayer: dimensions not compatible for if-conditional outputs)

通过 Netron.app 发现这个节点的 then 分支输出是空的,估计是之前用 onnxoptimizer 给优化掉了。查看从 PyTorch 导出的原始 ONNX 模型发现,两个分支的输出是完整的。随后使用最原始的 ONNX 模型进行转换,出现错误:

[01/06/2026-12:19:30] [E] [TRT] ModelImporter.cpp:836: ERROR: ModelImporter.cpp:194 In function parseNode: [6] Invalid Node - /encoder/1/downsample/Softmax

原因在于 TensorRT 要求 Softmax 算子的输入 Tensor 必须是二维及以上,第一维表示 batch_size。这里的输入其实是常量 bias,在 ONNX 中是 initializer,因此直接将该常量输入和 Softmax 算子合并成一个常量 initializer。但再次转换后,问题依然存在:

Miscellaneous (IConditionalOutputLayer /encoder/1/encoder/encoder_pos/If_OutputLayer: /encoder/1/encoder/encoder_pos/If_OutputLayer: dimensions not compatible for if-conditional outputs)

这里的 ONNX 模型中存在一个 If 算子,它的 else_branch 和 then_branch 子图输出 shape 不一致,导致上述问题。其中 then_branch 输出的是固定 size 的 tensor,但 else_branch 输出的是 dynamic size 的 tensor。这个问题比较棘手,因为 else_branch 的输出 size 有可能大于 then_branch 的输出 size,无法通过 padding 到固定 size 解决。可能可行的办法是预设一个较大的 max_len,然后在两个 branch 的输出都进行 padding,再使用 mask 控制参与计算的部分,但这种方案无疑过于复杂。因此,这次尝试暂时告一段落。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1136744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VDMA初始化配置详解:基于Zynq平台的新手教程

打通视频传输的“任督二脉”:手把手教你搞定Zynq平台VDMA初始化你有没有遇到过这样的场景?在Zynq上跑HDMI输出,画面撕裂、卡顿频发;想用CPU搬运图像数据,结果A9核心直接飙到100%;换了一种分辨率&#xff0c…

速递|刷新港股纪录!MiniMax上市超额认购79倍,主权基金密集下单

速递|刷新港股纪录!MiniMax上市超额认购79倍,主权基金密集下单 谢照青 Z Finance 2026年1月8日 23:02 北京 来源:腾讯财经 文:谢照青 即将于1月9日敲钟上市的大模型公司MiniMax,创下近年来港股IPO机构认购历史记录。此次参与Mi…

元类魔法:无需显式命名

在编程中,尤其是涉及到高级Python功能时,元类(metaclass)经常被用来在类创建时进行一些特殊的操作或修改。然而,一个常见的问题是如何在元类内部引用自身而无需显式地使用元类的名称。本文将探讨如何实现这一技巧,并通过一个具体的实例来说明。 问题背景 假设我们有一个…

单层锚点图哈希(Anchor Graph Hashing)训练函数实现详解

前言 在无监督哈希学习领域,Anchor Graph Hashing(AGH)以其高效的锚点图结构和对数据流形结构的精准捕捉而广受关注。单层AGH通过少量的锚点(landmarks)构建稀疏的相似度图,避免了传统图哈希方法中高昂的全图构建成本,同时保持了良好的检索性能。本文将深入解析单层AGH…

AI音频生成新方向:多情感中文TTS+Flask接口,助力有声书自动化生产

AI音频生成新方向:多情感中文TTSFlask接口,助力有声书自动化生产 引言:语音合成的进阶需求——从“能说”到“会表达” 在有声书、虚拟主播、智能客服等应用场景中,传统的语音合成(Text-to-Speech, TTS)技术…

MATLAB实现球面哈希(Spherical Hashing)编码函数详解

球面哈希(Spherical Hashing)编码函数在MATLAB中的实现与解析 球面哈希(Spherical Hashing,简称SpH)是一种独特且高效的无监督哈希方法,与传统的超平面投影哈希不同,它使用一组超球面作为哈希函数的分界。每个哈希比特对应一个超球体(由球心和半径定义),样本位于球内…

影视后期提效方案:AI辅助镜头动态化处理

影视后期提效方案:AI辅助镜头动态化处理 引言:静态图像的动态革命 在影视后期制作中,传统镜头动态化处理往往依赖复杂的动画建模、关键帧设定或实拍补录,耗时且成本高昂。随着生成式AI技术的突破,Image-to-Video&#…

DeepSeek 的 mHC

DeepSeek 的 mHC 纪牛牛 吃果冻不吐果冻皮 2026年1月9日 22:43 四川 在小说阅读器中沉浸阅读 原文:https://zhuanlan.zhihu.com/p/1991140563672664024 大约在去年同一时间段(2025年1月初),DeepSeek 凭借 R1 的发布彻底革新了…

压缩哈希(Compressed Hashing)学习算法详解

压缩哈希(Compressed Hashing,简称CH)是一种高效的无监督哈希学习方法,旨在将高维数据映射到低维二进制空间,同时保留数据的局部相似性。该算法通过引入地标点(landmarks)来构建稀疏表示,从而降低维度并提升计算效率,非常适用于大规模近邻搜索和检索任务。 本文将基于…

emwin字体与图片资源:从添加到显示的完整指南

emWin字体与图片资源:从设计到显示的实战全解析你有没有遇到过这样的情况?精心设计了一套UI界面,图标美观、文字清晰,结果烧录进嵌入式设备后——中文变成方块,图片颜色发紫,启动画面卡顿半秒才出来&#x…

agent系统:架构、应用与评估全景综述

agent系统:架构、应用与评估全景综述 原创 无影寺 AI帝国 2026年1月9日 22:05 广东 背景与核心问题 基础模型已使自然语言成为计算的实用接口,但大多数现实任务并非单轮问答。这些任务涉及从多个来源收集信息、随时间维护状态、在工具间进行选择&#…

局部敏感判别分析(LSDA)算法详解与MATLAB实现

局部敏感判别分析(LSDA)算法详解与MATLAB实现 在有监督降维任务中,经典的线性判别分析(LDA)追求全局类间分离和类内紧致,但往往忽略数据的局部几何结构。当数据分布在非线性流形上时,LDA 的表现会大打折扣。局部敏感判别分析(Locality Sensitive Discriminant Analysi…

零基础指南:MOSFET基本工作原理与半导体区域分布

从零开始读懂MOSFET:不只是“开关”,更是电场的艺术你有没有想过,手机充电器为什么能做到又小又快?无人机的电机控制为何如此精准?这些背后都藏着一个功不可没的小元件——MOSFET。它不像CPU那样引人注目,却…

内卷还是变革?智谱唐杰最新演讲:大模型瓶颈期,普通人该如何抓住这3大趋势?

这个时候,可能大部分人都会把目光放到智谱的 CEO 张鹏身上,而我觉得唐杰可能是智谱成功最重要的一环。 唐杰老师是清华大学教授、智谱 AI 首席科学家,也是国内最懂大模型的人之一。 他在智谱上市前夕发了篇长微博,谈 2025 年对大…

SMBus协议层次结构:系统学习物理层与命令层

深入理解SMBus:从物理层到命令层的系统级解析在嵌入式系统和现代计算机架构中,我们常常需要让多个小功能芯片“说同一种语言”——比如温度传感器上报数据、电池管理IC报告剩余电量、内存模块自述规格。这些看似简单的任务背后,离不开一条低调…

企业级域名 SSL 证书信息采集与巡检

背景 在当前数字化时代,SSL 证书是保障企业网络传输安全、验证网站身份及维护用户信任的基石。尤其对于拥有众多域名的企业而言,SSL 证书的有效性直接关系到业务的连续性与安全性。传统手动管理方式难以应对证书数量多、易遗漏的挑战,证书一…

企业级域名 SSL 证书信息采集与巡检

背景 在当前数字化时代,SSL 证书是保障企业网络传输安全、验证网站身份及维护用户信任的基石。尤其对于拥有众多域名的企业而言,SSL 证书的有效性直接关系到业务的连续性与安全性。传统手动管理方式难以应对证书数量多、易遗漏的挑战,证书一…

学长亲荐8个AI论文软件,助你搞定本科生论文格式规范!

学长亲荐8个AI论文软件,助你搞定本科生论文格式规范! 论文写作的“隐形助手”:AI 工具如何改变你的学术之路 对于许多本科生来说,撰写论文不仅是对知识的检验,更是对时间管理、逻辑思维和语言表达能力的综合挑战。尤其…

保姆级教程!AI智能体的可解释因果缰绳全解析:手把手带你用大模型提取因果反馈。

文章摘要 本文介绍了一种创新的方法,利用大语言模型(LLM)代理从原始文本中自动提取因果反馈模糊认知图谱(FCM)。通过三步系统指令,LLM能够系统性地识别文本中的关键概念和因果关系,构建动态系统…

图解说明时序逻辑电路的信号时序关系

时序逻辑电路的信号时序关系:从波形图看懂触发器如何“记住”时间你有没有遇到过这样的情况?明明逻辑设计完全正确,Verilog代码也综合通过了,仿真看起来也没问题——但烧进FPGA后系统就是不稳定,偶尔出错、数据跳变、状…