3. OptimizationProfile参数详解
在 TensorRT 的动态 Shape 部署中,OptimizationProfile(优化配置文件)是连接“网络定义”与“运行时实际输入”的桥梁。它告诉构建器:这个网络在运行时可能遇到哪些输入尺寸范围,以及在哪个尺寸上最值得做极致优化。一个 Profile 由三组维度构成:min、opt、max,它们共同描述了一个输入张量的合法取值空间。
min / opt / max 的语义
对于每个动态输入张量,Profile 要求给出三个维度向量:
- min shape:运行时允许的最小尺寸,任何小于它的输入都会导致
setInputShape失败或推理结果不可信。 - max shape:运行时允许的最大尺寸,超过它同样会被拒绝。
- opt shape:构建器认为“最典型、最常出现”的尺寸。TensorRT 会以 opt shape 为基准进行 kernel 自动调优(tactic selection),因此 opt 选得准不准,直接决定实际推理性能。
三者必须满足逐维约束:min[i] ≤ opt[i] ≤ max[i]。注意这是逐维关系,而不是整体体积关系。例如 min=[1,3,224,224]、opt=[4,3,512,512]、max=[8,3,608,608] 是合法的;但如果某一维出现 min[i] > opt[i],构建阶段就会报错。
多输入多输出 Profile 的维度约束
当网络有多个动态输入时,一个 Profile 必须为每一个动态输入都指定 min/opt/max。TensorRT 在运行时按 Profile 整体匹配:调用 setInputShape(tensorName, shape) 时,所有输入的实际 shape 必须同时落在同一个 Profile 的范围内,不能出现“输入 A 用 Profile 0、输入 B 用 Profile 1”的混用。
输出张量的维度通常由输入和网络结构推导得出,不需要在 Profile 中显式指定;但若输出维度依赖 shape tensor 或数据相关操作,则其范围会随输入范围自动变化,需要保证 max 输入下输出不会超出显存预算。
多 Profile 的典型用途是覆盖差异较大的业务场景。例如同一检测网络:
| Profile | 输入 NCHW (min) | 输入 NCHW (opt) | 输入 NCHW (max) | 适用场景 |
|---|---|---|---|---|
| P0 | [1,3,320,320] | [1,3,416,416] | [1,3,640,640] | 实时单帧 |
| P1 | [4,3,320,320] | [8,3,416,416] | [16,3,640,640] | 离线批处理 |
运行时通过 context.setOptimizationProfileAsync(profileIndex, stream) 切换 Profile。切换后必须重新设置所有输入 shape,否则会沿用旧值导致维度不匹配。
shape tensor 与 execution tensor 的区别
这是动态 Shape 中最容易混淆的一对概念,必须从“张量在图中扮演什么角色”来区分。
- Execution tensor(执行张量):承载真实数据的张量,参与卷积、矩阵乘等计算,其 shape 在运行时由 Profile 约束。例如输入图像张量
input:0、输出检测框张量output:0。 - Shape tensor(形状张量):承载“维度数值”的整型张量,本身不参与数值计算,而是被其他算子用来决定输出形状。例如
shape_of(input)的输出、gather取出的某一维长度、concat拼接出的目标尺寸。
关键差异在于:execution tensor 的 shape 由 Profile 的 min/opt/max 直接约束;而 shape tensor 的值在运行时才确定,构建器只能根据 Profile 范围推断其可能取值。因此,凡是依赖 shape tensor 的算子(如 resize、slice、fill),其输出维度在构建期是“范围”而非固定值。
实际配置示例
下面用 Python API 展示一个双输入网络的 Profile 设置过程。假设网络有两个动态输入:image(NCHW)和 scale(标量 shape tensor)。
profile = builder.create_optimization_profile()
# execution tensor:图像输入
profile.set_shape(
"image",
min=(1, 3, 320, 320),
opt=(1, 3, 416, 416),
max=(1, 3, 640, 640)
)
# shape tensor:标量,值域固定为 [1]
profile.set_shape("scale", min=(1,), opt=(1,), max=(1,))
config.add_optimization_profile(profile)
# 运行时
context.set_optimization_profile_async(0, stream)
context.set_input_shape("image", (1, 3, 416, 416))
context.set_input_shape("scale", (1,))
这里 scale 是 shape tensor,它的“shape”是 (1,),而它的“值”在运行时通过 set_input_shape 之外的方式(如 set_tensor_address 配合 host 数据)写入。很多初学者会把 shape tensor 的 shape 与 value 混淆,导致 set_input_shape 报维度错误。
set_input_shape 时传入了错误的维度数量。shape tensor 的 shape 是它自身的维度(如 (1,) 或 (4,)),而不是它承载的数值。例如 shape_of 输出是 4 维向量,其 shape 为 (4,),不是 (1,3,H,W)。Profile 选择与性能判断
构建完成后,可以通过 engine.get_profile_shape(profile_index, tensor_name) 回读每个 Profile 的 min/opt/max,确认与预期一致。运行时若输入 shape 落在多个 Profile 的交集内,TensorRT 会选择第一个匹配的 Profile,因此 Profile 的注册顺序会影响实际使用的优化策略。
判断 Profile 是否合理,可以观察两个信号:一是 set_input_shape 是否成功返回;二是推理延迟是否接近 opt shape 下的预期。如果实际输入长期偏离 opt,性能会明显下降,此时应调整 opt 或增加 Profile 覆盖该尺寸段。
最后强调一点:min/opt/max 的设定不是“越宽越好”。范围越宽,构建器需要为更多尺寸组合准备 kernel,构建时间与显存占用都会上升。工程上应基于真实业务分布收窄范围,把 opt 放在最高频的尺寸上,这才是 Profile 调优的核心。