1. 动态Shape部署问题导入

在TensorRT的早期工程实践中,绝大多数部署方案都建立在“固定Shape”这一前提之上。所谓固定Shape,是指在构建Engine时,输入张量的维度(包括batch、通道、高度、宽度等)被完全写死。例如一个图像分类模型,构建时指定输入为[1, 3, 224, 224],那么生成的Engine就只能接受这一种尺寸的输入。这种模式在实验室验证阶段非常高效:TensorRT可以针对唯一确定的维度做极致的层融合、内核选择与显存复用,推理延迟和吞吐往往能达到最优。

然而,一旦进入真实的生产环境,固定Shape的局限性会迅速暴露。以视频分析场景为例,摄像头分辨率可能是1080p、720p甚至4K,不同来源的帧尺寸并不统一;再比如自然语言处理中的文本分类,每条输入的token数量从几个到几百个不等,序列长度天然可变。如果为每一种可能的尺寸都单独构建一个Engine,不仅构建时间成倍增长,显存占用也会随Engine数量线性膨胀,最终导致部署方案不可维护。这就是从固定Shape走向动态Shape的核心工程驱动力。

动态Shape的本质,是让同一个Engine在运行时接受一定范围内的不同输入维度,而无需重新构建。它把“维度”从编译期常量变成了运行期变量,从而在灵活性与性能之间取得平衡。

固定Shape部署的典型痛点

我们可以把固定Shape部署的痛点归纳为三个层面。第一是尺寸适配问题:当实际输入与构建时指定的尺寸不一致时,TensorRT会直接报错,提示维度不匹配。工程上常见的“补边”“缩放”虽然能规避报错,但会引入额外的预处理开销,甚至改变模型语义。第二是Engine数量爆炸:假设一个模型需要支持batch为1、4、8,分辨率支持224、256、320,那么组合起来就是9个Engine,每个Engine都要独立构建、独立加载、独立占用显存。第三是构建与维护成本:每次模型更新或新增一种输入规格,都要重新走一遍构建流程,CI/CD链路变长,版本管理复杂度上升。

下面这张图对比了固定Shape与动态Shape在部署链路中的差异,重点呈现了Engine数量、构建次数与显存占用随输入规格增长的变化关系。

固定Shape vs 动态Shape:部署链路对比 输入规格组合数 = batch数 × 分辨率数 × 序列长度数 固定Shape部署 输入规格:3种batch × 3种分辨率 = 9 个独立Engine Engine-1 [1,3,224,224] Engine-2 [4,3,224,224] Engine-3 [8,3,224,224] … 共9个 构建次数:9次 显存占用:9份权重 + 9份工作区 新增规格 → 重新构建 痛点 维护复杂 · 显存膨胀 · 构建耗时长 尺寸不匹配直接报错 动态Shape部署 输入规格:3种batch × 3种分辨率 = 1 个动态Engine Optimization Profile 0 min=[1,3,224,224] opt=[4,3,224,224] max=[8,3,320,320] 运行时按实际维度选择内核 构建次数:1次 显存占用:1份权重 + 动态工作区 新增规格 → 调整Profile范围 收益 单一Engine · 显存可控 · 灵活适配 代价:需设置Profile与范围约束 演进

TensorRT动态Shape的能力边界

TensorRT对动态Shape的支持并非“任意维度随意变化”,而是通过Optimization Profile来约束变化范围。每个Profile定义一组输入张量的最小维度(min)、最优维度(opt)和最大维度(max)。运行时传入的实际维度必须落在min与max之间,而opt则用于指导构建器选择在该维度下性能最佳的内核。如果实际维度超出Profile范围,TensorRT会拒绝执行并抛出错误。

这里需要明确几个能力边界。第一,维度数量固定:动态Shape改变的是每个维度的取值,而不是张量的秩(rank)。一个4维输入不能变成5维。第二,范围必须预先声明:min/opt/max必须在构建时确定,运行时不能动态扩展。第三,性能与范围宽度相关:min与max差距越大,构建器需要覆盖的维度组合越多,可能牺牲部分极致优化机会,因此opt的选择非常关键。第四,并非所有层都同等支持动态Shape:大部分常见层(卷积、全连接、池化、激活等)支持良好,但某些特殊插件或自定义层可能需要额外适配。

一个实用的经验是:opt维度应设置为生产环境中最常见的输入规格,而不是简单取min与max的中间值。因为TensorRT会针对opt做内核调优,让最高频的请求走最优路径,整体收益最大。

多Profile部署需求场景

当单一Profile无法覆盖所有业务输入时,就需要引入多Profile。典型场景包括以下几类。

  • 多分辨率视频流混合接入:同一路推理服务同时处理720p与1080p帧,两者维度差异较大,用一个宽范围Profile会导致opt难以兼顾,拆成两个Profile分别优化更合理。
  • 训练与推理共用模型:离线批量推理使用大batch(如32),在线实时推理使用小batch(如1),两者对延迟和吞吐的诉求不同,适合用不同Profile区分。
  • 多租户SaaS服务:不同客户提交的输入长度分布差异明显,为每个租户或每类租户分配独立Profile,可以避免相互干扰。
  • A/B测试与灰度发布:新旧预处理逻辑产生不同维度分布,通过多Profile并行支持,便于对比效果。

多Profile的运行时选择逻辑是:TensorRT按Profile的声明顺序依次匹配,第一个满足“所有输入维度均落在其min/max范围内”的Profile被选中。因此Profile的排列顺序会影响匹配结果,工程上通常把最常用或最严格的Profile放在前面。此外,多个Profile会共享同一份权重,但各自维护独立的工作区(workspace)需求,显存占用并非简单叠加,而是取决于最大Profile的工作区大小。

从问题到方案:本节定位

综合来看,动态Shape部署要解决的核心矛盾是:如何在保持单一Engine、可控显存的前提下,覆盖生产环境中多样且可变的输入维度。TensorRT给出的答案是Optimization Profile机制,而多Profile则进一步扩展了覆盖能力。后续章节将围绕如何定义Profile、如何选择min/opt/max、如何处理多Profile的构建与运行时切换、以及如何验证动态Shape下的性能与正确性展开。本节作为导入,重点在于建立问题意识:固定Shape不是错,但它只适用于输入规格完全可控的场景;一旦输入维度进入“变化区间”,动态Shape与多Profile就是必须掌握的工程手段。

需要特别注意的是,动态Shape并不等于“零成本灵活”。它用一定的性能余量和构建复杂度,换取了部署灵活性。在输入规格实际非常固定的场景中,坚持使用固定Shape反而可能是更优选择。工程决策应基于真实输入分布,而非盲目追求动态化。