想象你是一位建筑设计师,拿到一份图纸后,不需要真的把楼盖起来,就能知道每面墙有多高、每扇窗有多宽、每个房间能放多少家具。这份“纸上推演”的能力,靠的就是你对建筑规范的深刻理解——看到标注就知道尺寸,看到连接就知道承重。ONNX Shape推理(形状推理)做的事情,恰恰就是给 AI 模型配一副这样的“透视眼镜”:不用真正跑一遍推理计算,仅凭模型的输入形状和各个算子的“操作规范”,就能自动推算出所有中间张量和输出的形状信息。 这副眼镜的价值有多大?在真实部署场景中,提前知道每一个张量的形状,意味着运行时可以像装修师傅提前量好尺寸再定制家具一样,一次性把内存分配好、把执行计划优化好,而不是边干边量、手忙脚乱。更关键的是,它在部署前就能发现“这里连不上”的维度不匹配问题,把潜在故障挡在机房之外。这就像你拿到一张内部结构完全透明的建筑图纸,哪里冲突、哪里冗余,一眼便知,部署的可靠性和效率自然大幅提升。对于 AI 从业者来说,掌握 Shape 推理,就是握住了从“模型设计”通往“高效部署”的钥匙——它是 ONNX 这个跨框架互操作标准中承上启下的关键齿轮。
对 AI 从业者的价值:Shape 推理是模型格式与序列化领域的核心工具,掌握它能让你在部署前精准预判内存开销与维度冲突,从源头提升推理效率与可靠性,是 AI 编译器与系统软件方向不可或缺的硬技能。
可视化演示
展示ONNX Shape推理:前向传播从输入节点沿数据流依次推导算子输出形状,完全推理与部分推理对比,及动态Shape的符号推理。
本节配有交互动效(进入视口后自动加载,约 3KB)。
前向传播Shape推理 从输入节点沿数据流方向访问算子 利用算子注册的Shape推理函数推导 out_shape=f(shape_rule,in_shape) 不执行模型即可推导所有张量形状。
Shape推理是什么
想象你去一家定制家具店,橱窗里展示着一套模块化书架的设计图。你告诉店员“我要一面 3 米宽、2.4 米高的墙来放书架”,店员不需要真的把书架搬来试放,只扫一眼设计图上的标准尺寸,就能告诉你:这套书架分成 4 列,每列 60 厘米宽;分成 6 层,每层 40 厘米高,刚好严丝合缝。这就是“设计图 + 输入条件 → 推导出所有部件尺寸”的思维。ONNX Shape 推理玩的正是同样的逻辑:把模型的计算图当作设计图,把输入张量的形状当作墙面尺寸,一层一层地推算出每个中间结果和最终输出的形状。
在 ONNX 的世界里,一个模型本质上是一张有向计算图(Directed Graph):图的节点是算子(Operator),边是张量(Tensor)数据流。Shape 推理要做的事情,就是给定输入张量的形状(比如 [1, 3, 224, 224] 表示一张 224×224 的 RGB 图片),沿着数据流的方向,依据每个算子固有的“形状变化规律”,逐个算出边上所有张量的形状。整个过程不需要真的计算张量里的数值,纯粹是在“形状”这个维度上做推导,就像书架店员只看尺寸表,不用真的搬木头。
ONNX 官方为 Shape 推理提供了 shape_inference 模块,它注册了每个标准算子的形状推导函数(Shape Inference Function)。当模型被加载时,推理器会遍历计算图,对每个节点调用对应的推导函数,把“输入形状”映射成“输出形状”。这个过程发生在真正的推理执行之前,属于静态分析阶段,是编译优化和内存规划的前提。Shape 推理让模型在 ONNX 生态中获得了“可预测性”——无论模型来自 PyTorch、TensorFlow 还是其他框架,只要转换成 ONNX 格式,形状信息就能被统一地推导和验证。
Shape 推理就像一个经验丰富的仓库管理员,不用把每件货物搬出来看,单凭入库单上的分类编号就能报出每件货应该放在哪个货架、占多大空间。这种“纸上谈兵”的能力,让 ONNX 模型在部署之前就已经被摸得一清二楚。
- 模型输入Shape 推理的起点是一个 ONNX 模型,通常通过
onnx.load()加载得到ModelProto对象。 - Shape 推理器ONNX 提供的
shape_inference.infer_shapes()函数,接收模型并返回带形状信息的新模型。 - 形状清单推理结果以
value_info字段的形式附加到每个中间张量上,记录其完整形状。
静态形状推断
回到书架店的例子,最理想的情况是:你给店员的墙尺寸是一个精确的数,比如 3 米整,那么店员能立刻算出每列书架的宽度。ONNX 模型里最幸福的场景也是这样——当输入张量的所有维度都是具体数字(比如 [1, 3, 224, 224])时,Shape 推理可以一路向下,把所有中间张量的形状都精确算出来。这种“给多少信息,就精确推多少”的过程,叫作静态形状推断(Static Shape Inference)。
静态推断的底层机制是规则表查找。ONNX 为每个算子都定义了 Shape 推导规则,这些规则以函数的形式注册在 onnx/defs 目录下。比如 Conv 算子的规则,会根据输入形状 [N, C, H, W]、卷积核形状 [M, C, kH, kW]、步长(stride)和填充(padding)等参数,计算出输出形状 [N, M, H_out, W_out]。这些规则就相当于书架店员手里的“标准尺寸对照表”,只要输入条件齐全,查表就能得到准确答案。
静态形状推断具有确定性和完整性两个显著特点。确定性意味着:同样的输入形状和算子参数,无论推理多少次,得到的结果永远一致。完整性意味着:只要图上所有算子的输入形状都已知,推理器就能为每个中间张量都确定一个精确的形状。这使得推理引擎可以在部署前就完成内存池的规划——知道每一层要分配多大的缓冲区,就像知道每个书架要占多大墙面,一次性把空间安排妥当。
静态形状推断就像给书架店提供了完整的房间尺寸图,店员可以一口气把全屋的家具尺寸都列出来。但在真实世界里,很多场景下我们拿到的并不是一个精确的数字——这时候,静态推断就不够用了。
- 输入高度 H卷积层的输入特征图高度,比如图片是 224 像素高,则 H=224。
- 填充 padding在特征图边缘补零的圈数,目的是控制输出尺寸不缩小太快,常见值为 0、1、2。
- 卷积核 kernel卷积窗口的尺寸,比如 3×3 卷积,则 kernel=3。
- 步长 stride卷积窗口每次滑动的像素数,步长越大,输出越小。
- 输出高度计算将上述参数代入公式,得到输出特征图的高度。
动态维度处理
现在设想一个新的场景:你开了一家连锁书店,要定制一批书架给不同面积的分店使用。每个分店的墙面尺寸都不一样,你不可能为每家店单独设计一套图纸。于是你告诉店员:“书架规格是固定的,但列数可以根据墙面宽度调整。”这里的“墙面宽度”就是一个动态值——在图纸阶段无法确定,只能在装修现场量。ONNX 模型同样面临这个问题:很多时候,模型的输入形状中包含未知维度,最常见的例子就是 batch size(批大小)。训练时用 32 张图一批,部署时可能一次只来 1 张图,推理时就该是 [1, 3, 224, 224],但这个 1 在模型导出时是不知道的。
为了处理这种情况,ONNX 引入了动态维度的概念。在模型输入的定义中,某个维度可以被标记为符号变量(symbolic dimension),比如把维度写成 "batch" 或 "None",表示这个维度的大小在运行时才确定。Shape 推理器遇到这类维度时,不会报错,而是把它当作一个“未知数”继续传播——就像书架店员在图纸上写下“列数 = X”,然后基于 X 推导出每个中间张量的形状表达式,比如 [X, 64, 112, 112]。
动态维度处理的关键在于符号传播机制。推理器会为每个未知维度绑定一个符号,在传播过程中,符号可以参与算术运算,形成符号表达式。例如,Flatten 算子会把 [X, 3, 224, 224] 变成 [X, 150528],其中 150528 是 3×224×224 的计算结果,而 X 原封不动地传递下来。当真正执行推理时,运行时系统拿到具体的 X 值,再把符号表达式替换成实际数字。这就实现了“一次建模,多种批大小”的灵活性。
动态维度处理就像是给图纸留了一扇“可调节”的门,让同一份设计图能适应不同尺寸的店面。但在 ONNX 中,并非所有算子都能优雅地处理符号维度——有些算子要求某些维度必须是确定值,这就需要我们深入了解每个算子的 Shape 规则。
- 符号维度 Xbatch size 被声明为符号变量,代表“运行时才知道的值”。
- 形状传播包含 X 的形状沿着计算图传播,Conv 等算子的规则把 X 原样传递给输出。
- 运行时实例化实际推理时,输入 batch 为 8,X 被替换为 8。
算子Shape规则
书架店的柜台上摆着一本厚厚的《标准化家具尺寸手册》,每一种家具——书架、书桌、衣柜——都有一页专属的尺寸推算规则。ONNX 也有一本这样的“手册”,不过里面的每一条规则对应的是一个算子(Operator)。算子的 Shape 推理规则是 Shape 推理的“砖块”,每个规则精确描述了“给定输入形状和属性,输出形状是什么”。理解和记忆这些规则,是掌握 Shape 推理的必修课。
先来看最常用的 Reshape 算子。它允许你将一个张量重新组织成新的形状,只要元素总数不变。其 Shape 规则简单而严格:输出形状由 shape 属性直接指定,如果其中有值为 0 的维度,则该维度继承输入对应位置的大小;如果有值为 -1 的维度,则该维度被自动推断为“总元素数除以其他维度乘积”。比如输入 [1, 3, 224, 224],Reshape 成 [-1, 150528],-1 会被计算为 1。这是 Shape 推理中最基础的规则之一。
再看卷积 Conv 和矩阵乘法 MatMul 这两个核心计算算子。Conv 的 Shape 规则在上面已经介绍过,它要求输入是 4 维(NCHW),核是 4 维,输出通道数等于核的个数,空间尺寸由步长和填充决定。MatMul 的规则则遵循矩阵乘法的代数约束:两个输入中,除最后两维以外的所有维度必须广播兼容,输出形状为“广播后的批次维度 + 矩阵乘法后的最后两维”。例如 [10, 3, 4] × [10, 4, 5] → [10, 3, 5]。这些规则共同构成了 ONNX 形状推理的“查表目录”。
算子 Shape 规则是 Shape 推理这座大厦的砖瓦。每一块砖都有自己的规格和组合方式,而将这些砖瓦按照计算图的顺序一块块砌起来的过程,就是下一节要讲的“形状传播机制”。
- 原始形状一个 4 维张量
[N, C, H, W],通常是卷积网络中间层的特征图。 - 目标形状shape 属性设置为
[-1, C×H×W],第一个维度不确定,第二个维度是拉平后的元素总数。 - 自动推断推理器计算 -1 位置的值:总元素 N×C×H×W 除以已知维度的乘积 C×H×W,得到 N。
形状传播机制
有了“尺寸手册”(算子规则),接下来就是按照什么顺序查阅、如何把结果记录下来。这就像书架店的店员拿到一张多层书架的图纸,他从顶层开始,一层一层地往下推算每层的高度和隔板数量,每算完一层就把尺寸填到图纸对应的标注栏里。在 ONNX 中,这个“一层一层往下推算”的过程就叫形状传播(Shape Propagation)。
形状传播的核心是图遍历。ONNX 模型是一个有向无环图(DAG),Shape 推理器会从图的输入节点出发,按照拓扑排序的顺序遍历每个算子节点。所谓拓扑排序,就是保证在访问某个算子时,它的所有输入张量的形状都已经计算完毕——就像店员只有知道上一层的隔板高度,才能算下一层的位置。推理器每访问一个节点,就调用该算子的 Shape 规则,计算输出形状,然后把结果记录到一张全局的“形状表”(shape table)中,供后续节点查询。
形状传播机制还承担着冲突检测的重要职责。在传播过程中,如果某个算子的输入形状与该算子的约束相矛盾——比如 MatMul 的两个输入矩阵的“内维”不相等(维度 3 和 5 无法相乘)——推理器会立即抛出错误,指出模型在第几个节点、哪个算子的形状不匹配。这个能力在部署阶段价值巨大:它让维度错误在“模型加载时”就被发现,而不是等到“推理运行时”才崩溃。就像书架店员在图纸阶段就发现“这面墙只有 3 米,但图纸要求书架宽 3.2 米”,可以当场纠正,而不是等书架做好才发现装不下。
形状传播就像一条自动化的流水线:图纸从一端送入,经过一个个工位的依次加工,最终从另一端出来时已经标注好了所有部件的尺寸。任何一个工位发现问题,整条流水线立刻停止报警。这种“边传播边检查”的机制,让 ONNX 模型的部署有了坚实的质量保障。
- 拓扑排序将计算图中的节点排成一个线性序列,保证任何节点的输入都在它之前被处理。
- 逐节点推导依次对每个节点调用 Shape 规则,计算其输出形状。
- 形状表记录每一步的计算结果写入形状表,后续节点直接从表中读取所需输入形状。
Shape推理的价值
现在,我们把视角拉远,看看这双“透视眼镜”在整个 AI 部署流程中到底值多少钱。书架店的例子告诉我们:如果能在图纸阶段发现问题,就绝不要等到家具做完再返工。ONNX Shape 推理的价值,正体现在“提前”这两个字上——提前分配内存、提前发现错误、提前优化计划。
第一项价值是提前分配内存。深度学习推理是内存密集型任务,一个包含数十层的模型,每层都要保存中间张量。如果没有 Shape 推理,推理引擎只能在运行时遇到一个张量就临时申请一块内存,频繁的分配与释放会带来显著的性能开销。有了 Shape 推理,引擎在推理开始前就知道每个张量的精确大小,可以一次性规划好整个内存池,按需复用缓冲区,就像书架店先量好全屋尺寸再统一定制家具,而不是边装边买。
第二项价值是发现维度不匹配问题。在跨框架模型转换中,最常见的错误就是维度顺序搞错——比如 PyTorch 中图片是 [N, C, H, W],而某个自定义算子期望 [N, H, W, C]。Shape 推理通过冲突检测,在模型加载时就能捕捉这类错误。第三项价值是优化执行计划。编译器(如 ONNX Runtime)可以根据形状信息选择最优的 kernel 实现——比如知道矩阵是 [1, 1024] 而不是 [1024, 1],就能选择更高效的向量化路径。形状信息还支持算子融合(Operator Fusion),把多个连续算子合并成一个高效算子,减少内存读写次数。
Shape 推理的价值可以用一句话概括:它把“运行时才发现的问题”提前到了“部署前就解决”。就像好的建筑设计师会在图纸阶段考虑每一根梁的受力,而不是等楼盖好了再加固。对于 ONNX 生态而言,Shape 推理正是这样一个把可靠性和效率同时拉满的关键环节。
- 模型加载ONNX 模型从磁盘加载到内存,此时尚未执行任何计算。
- Shape 推断调用
infer_shapes完成全图形状推导,得到每个张量的形状。 - 部署优化推理引擎基于完整形状信息规划内存和执行计划。
AI 应用场景
ONNX Runtime 内存池优化
阶段:模型部署与推理优化
解决的问题:传统推理引擎在运行时逐层申请内存,频繁的 malloc/free 造成大量 CPU 开销和内存碎片。通过 ONNX Shape 推理预先获取所有中间张量的形状,ONNX Runtime 可以在启动阶段构建统一的内存池,将张量复用率提升到极致。
具体案例:某互联网公司的推荐系统模型包含 200+ 算子、500+ 中间张量。接入 Shape 推理后,推理引擎提前规划出完整内存布局,将峰值内存占用降低 35%,吞吐量提升 20%。更关键的是,模型上线前的 CI 流水线中加入了 Shape 校验,有效拦截了 3 次由于维度不匹配导致的线上事故。
跨框架模型转换验证
阶段:模型格式转换与兼容性检查
解决的问题:将 PyTorch 训练好的模型导出为 ONNX 时,经常遇到“算子实现差异”和“维度约定不同”导致转换后的模型无法正确运行。Shape 推理可以作为转换后的“体检工具”,自动验证每个节点的输入输出形状是否符合预期。
具体案例:算法工程师将 YOLOv8 检测模型从 PyTorch 导出为 ONNX 后,通过 onnx.shape_inference.infer_shapes 发现模型的输出层形状为 [1, 84, 8400] 而非预期的 [1, 8400, 84],从而及时调整了后处理代码的维度顺序,避免了部署后的检测框错乱问题。
Python 演示
import onnxfrom onnx import helper, TensorProtofrom onnx import shape_inference # 构建一个简单的 ONNX 模型: Conv -> Relu -> Flatten -> MatMuldef build_model(): # 定义输入: [1, 3, 224, 224] 的图像 X = helper.make_tensor_value_info('X', TensorProto.FLOAT, [1, 3, 224, 224]) # Conv 权重: 64 个 3x3 卷积核, 输入通道 3 W = helper.make_tensor_value_info('W', TensorProto.FLOAT, [64, 3, 3, 3]) # MatMul 权重: [50176, 1000] M = helper.make_tensor_value_info('M', TensorProto.FLOAT, [50176, 1000]) # 定义算子节点 conv_node = helper.make_node('Conv', ['X', 'W'], ['conv_out'], kernel_shape=[3, 3], pads=[1, 1, 1, 1], strides=[1, 1]) relu_node = helper.make_node('Relu', ['conv_out'], ['relu_out']) flatten_node = helper.make_node('Flatten', ['relu_out'], ['flat_out'], axis=1) matmul_node = helper.make_node('MatMul', ['flat_out', 'M'], ['Y']) # 输出: 1000 类的 logits Y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, [1, 1000]) graph = helper.make_graph( [conv_node, relu_node, flatten_node, matmul_node], 'shape_infer_demo', [X, W, M], [Y] ) return helper.make_model(graph) def main(): model = build_model() # 关键: 执行 Shape 推理 inferred = shape_inference.infer_shapes(model) print("=== Shape 推理结果 ===") for vi in inferred.graph.value_info: dims = [d.dim_value if d.HasField('dim_value') else d.dim_param for d in vi.type.tensor_type.shape.dim] print(f"{vi.name}: {dims}") # 添加一个故意维度不匹配的 MatMul 测试 bad_model = build_model() bad_model.graph.node[3].input[1] = 'M_bad' bad_W = helper.make_tensor_value_info('M_bad', TensorProto.FLOAT, [1000, 1000]) bad_model.graph.value_info.append(bad_W) try: shape_inference.infer_shapes(bad_model) print("\n错误测试: 未检测到问题(不符合预期)") except Exception as e: print(f"\n错误测试: 成功捕获维度错误 -> {type(e).__name__}") if __name__ == '__main__': main()
infer_shapes 推导所有中间张量形状,并验证维度不匹配时能自动报错。from onnx import shape_inference导入 ONNX 官方的 Shape 推理模块。shape_inference.infer_shapes(model)对模型执行 Shape 推理,返回带形状信息的模型副本。inferred.graph.value_info推理结束后,中间张量的形状信息存放在value_info字段中。d.dim_value if d.HasField('dim_value') else d.dim_param处理静态维度(具体数值)和动态维度(符号参数)的取值逻辑。bad_model.graph.node[3].input[1]将第 4 个节点的第二个输入替换为形状不匹配的张量,测试冲突检测。shape_inference.infer_shapes(bad_model)面对维度矛盾,推理器抛出异常,展示其“早期发现错误”的能力。
常见误区
误区我一直以为 Shape 推理就是把模型真实地跑一遍,然后把每个层的输出尺寸打印出来。那和直接推理有什么区别?
正解Shape 推理完全不执行任何数值计算,它只做“形状层面”的符号推导。就像书架店员只看尺寸表算家具尺寸,不需要真的搬木头做家具。真实推理要计算每个张量的数值,而 Shape 推理仅仅输出每个张量的形状(维度列表),不涉及任何浮点运算,因此速度极快,通常毫秒级完成整个模型的形状推导。
为何常见:因为两者都会输出“每一层的输出”,看起来很像,但一个算数值、一个算维度,本质是两码事。
误区只要我输入形状是固定的数字,Shape 推理就能算出所有中间形状,所以动态维度支持没什么用。
正解静态推断确实能处理固定输入,但真实部署中 batch size 往往需要动态变化——线上服务一次可能只来 1 个请求,训练时是 32 个一批。没有动态维度支持,模型只能绑定单一 batch size,要么浪费算力(按 32 跑但实际只有 1),要么无法服务(输入不是 32 就报错)。动态维度让同一份模型文件适配多种输入规模,是生产环境的刚需。
为何常见:很多初学者只在固定 batch 的测试环境里跑模型,没有接触过动态 shape 的场景,容易低估它的重要性。
误区Shape 推理不就是把输入形状抄到输出吗?Reshape 算子应该是最常见的,其他算子的规则大概也差不多。
正解实际上,每个算子的 Shape 规则差异很大。Reshape 是简单的“查属性 + 推断 -1”,但 Conv 要考虑 kernel、stride、padding、dilation 四个参数的空间关系,MatMul 要处理以二维为基准的广播机制,Gather、Slice 等算子还涉及索引维度的删除与新增。制定一个算子的 Shape 规则需要深入理解该算子的语义,这也是 ONNX 官方对算子定义的一部分。
为何常见:初学者最先接触的多半是 Reshape 这类“直来直去”的算子,容易以偏概全。
误区我调用 `infer_shapes` 时报错了,是不是我的模型文件彻底废了?只能重新训练?
正解Shape 推理报错分为两类:一是模型真的有问题(如维度不匹配),这类错误必须修复;二是 Shape 推理器的局限性——某些自定义算子没有注册 Shape 规则,或某个动态维度的约束条件无法被符号表达式表达。遇到后一种情况,可以通过补充 value_info 手动声明中间张量的形状,或使用 ONNX Runtime 等推理引擎自带的 shape 推断能力绕过。模型本身未必有错,先诊断错误类型再行动。
为何常见:把“工具报告了问题”误解为“模型出了问题”,其实有时候是“工具能力不够”。
误区Shape 推理是部署工程师的事,训练阶段的开发用不上。
正解Shape 推理在训练和验证阶段同样有重要价值。比如在 PyTorch 中导出 ONNX 时,torch.onnx.export 内部就会调用 Shape 推理来生成 value_info,用于确定动态轴的范围约束。此外,模型压缩(量化、剪枝)工具也依赖 Shape 信息来重新规划内存布局。可以说,凡是需要对模型结构做静态分析的环节,Shape 推理都有用武之地。
为何常见:大多数人接触 Shape 推理是在部署环节,忽略了它在模型开发管线早期的作用。
面试题
Q1. ONNX Shape 推理的核心目标是什么?
- A.加速模型训练过程
- B.自动推导张量形状← 正确答案
- C.压缩模型文件大小
- D.提升模型识别精度
答案:B。Shape 推理的职责是根据输入形状和算子规则,推导所有中间张量和输出的形状。它不涉及训练加速(A)、模型压缩(C)或精度提升(D)。就像店员根据墙面尺寸推算书架尺寸,目标就是“推导尺寸”。
Q2. 当 ONNX 输入的所有维度都是具体数字时,Shape 推理属于哪种类型?
- A.动态形状推断
- B.符号形状推断
- C.静态形状推断← 正确答案
- D.概率形状推断
答案:C。输入维度全部确定时,推理器能精确推导所有中间形状,这是静态形状推断的特征。动态推断涉及符号变量,与题干“具体数字”矛盾;符号和概率不是 ONNX 的标准分类。
Q3. 在 ONNX 中,输入维度被标记为 "batch" 代表什么含义?
- A.该维度固定为 1
- B.该维度在运行时确定← 正确答案
- C.该维度被删除
- D.该维度自动扩展
答案:B。符号维度(如 "batch")表示该维度大小在运行时才被赋予具体值,推理器将其作为符号传播。它是动态维度处理的核心机制,而非固定值、删除或扩展。
Q4. 对于 Reshape 算子,输出形状中值为 -1 的维度表示什么?
- A.该维度被设置为 0
- B.该维度自动推断← 正确答案
- C.该维度被删除
- D.该维度无限大
答案:B。-1 指示推理器根据元素总数和其他已知维度自动补齐该维度大小。例如 [1, 150528] 中 -1 会被推断为 1,这是 Reshape 规则的核心特性。
Q5. 以下哪个公式是 Conv 输出空间尺寸的正确计算方式?
- A.(H - kernel) / stride
- B.(H + 2*padding - kernel) / stride + 1← 正确答案
- C.(H + padding) / kernel - 1
- D.(H - stride) / padding + kernel
答案:B。标准卷积输出尺寸为 (H + 2*padding - kernel) / stride + 1(向下取整)。其他选项缺少填充补偿或运算关系错误,不符合卷积的几何语义。
Q6. ONNX 中 MatMul 算子对输入形状的基本要求是什么?
- A.最后两维必须相等
- B.倒数第二维必须相等
- C.内维必须匹配← 正确答案
- D.所有维度必须相等
答案:C。MatMul 要求矩阵乘法的内维匹配,即第一个输入的最后一维等于第二个输入的倒数第二维。最后两维相等(A)和所有维度相等(D)过于严格,倒数第二维相等(B)描述错误。
Q7. Shape 推理遍历计算图时,为什么必须使用拓扑排序?
- A.保证计算图是有向无环图
- B.保证每个节点的输入形状已推导← 正确答案
- C.保证算子按字母顺序执行
- D.保证模型文件被正确解析
答案:B。拓扑排序确保在处理某个算子时,它的所有输入张量的形状都已计算完毕,这是形状传播正确性的前提。它不改变图的性质(A)、不按字母排序(C)、与文件解析无关(D)。
Q8. 在形状传播过程中,如果某算子输入形状不满足约束,ONNX 推理器会怎样?
- A.跳过该节点继续传播
- B.随机猜测一个形状
- C.立即抛出维度错误← 正确答案
- D.延迟到运行时再处理
答案:C。冲突检测是 Shape 推理的职责之一,发现维度不匹配会立即抛出异常,这正是“部署前发现问题”的价值所在。跳过(A)、猜测(B)、延迟(D)都不符合严格校验的设计原则。
Q9. Shape 推理为部署带来的价值有哪些?
- A.提前分配内存← 正确答案
- B.发现维度不匹配← 正确答案
- C.提升模型训练精度
- D.优化执行计划← 正确答案
答案:ABD。Shape 推理能提前规划内存池(A)、检测维度错误(B)、辅助执行计划优化(D)。但训练精度提升(C)与形状推导无关,属于模型本身的训练问题。
Q10. 以下哪些情况可能导致 Shape 推理报错?
- A.模型中存在未注册规则的自定义算子← 正确答案
- B.MatMul 输入内维不匹配← 正确答案
- C.输入张量的数值全为零
- D.Reshape 目标形状元素总数不符← 正确答案
答案:ABD。自定义算子无 Shape 规则(A)、MatMul 内维矛盾(B)、Reshape 元素数不一致(D)都会触发 Shape 推理错误。输入数值全为零(C)属于数值层面,不影响形状推导。