静态形状与动态形状:从固定到灵活的演进
做TensorRT部署这些年,我遇到过不少让人头疼的问题。其中最典型的,就是模型跑起来好好的,换个输入尺寸就崩了。嗯,这就要从静态形状和动态形状说起了。
静态形状的定义与限制
静态形状,说白了就是模型在构建时就把输入输出的尺寸定死了。比如你定义一个输入是[1, 3, 224, 224],那它这辈子就只能处理224x224的图片。多一分不行,少一分也不行。
在TensorRT中,静态形状的构建流程是这样的:
// 静态形状示例
nvinfer1::IBuilder* builder = nvinfer1::createInferBuilder(logger);
nvinfer1::INetworkDefinition* network = builder->createNetwork();
// 输入张量,形状固定
nvinfer1::ITensor* input = network->addInput(
"input", nvinfer1::DataType::kFLOAT,
nvinfer1::Dims4{1, 3, 224, 224} // 这里写死了
);
// 构建引擎
nvinfer1::IBuilderConfig* config = builder->createBuilderConfig();
nvinfer1::IHostMemory* serializedModel = builder->buildSerializedNetwork(*network, *config);
静态形状的限制很明显:
- 灵活性为零:换一个尺寸就得重新构建引擎
- 部署成本高:生产环境往往需要处理多种尺寸
- 资源浪费:为了覆盖所有场景,你可能得维护多个引擎文件
我曾经踩过的坑:有个客户要求模型同时处理480p和1080p的视频流。我一开始图省事,只做了静态形状的1080p版本。结果480p的输入进来,显存占用和计算量完全没降下来,白白浪费了资源。后来我才意识到,静态形状在这种场景下就是给自己挖坑。
动态形状的引入背景
为什么会需要动态形状?你想想看,现实世界的输入哪有那么规整?
- 用户上传的图片,尺寸五花八门
- 视频流的分辨率可能动态切换
- NLP任务中,句子长度千差万别
静态形状在这些场景下就显得力不从心了。TensorRT从5.0版本开始引入了动态形状支持,说白了就是允许你在运行时指定输入的实际尺寸。
动态形状的核心概念有三个:
| 概念 | 说明 | 示例 |
|---|---|---|
| 最小尺寸 | 模型能处理的最小输入 | [1, 3, 128, 128] |
| 最优尺寸 | 性能最优的输入尺寸 | [1, 3, 224, 224] |
| 最大尺寸 | 模型能处理的最大输入 | [1, 3, 512, 512] |
关键点:动态形状不是无限制的。你需要在构建引擎时指定一个范围,TensorRT会在这个范围内做优化。超出范围?对不起,跑不了。
动态形状的适用场景
我个人习惯把动态形状的应用场景分成三类:
1. 图像处理类任务
目标检测、图像分割这些任务,输入图片的原始尺寸往往不一致。我记得有个项目是做工业质检的,产品尺寸经常变化,用动态形状就特别合适。
// 动态形状配置示例
nvinfer1::IOptimizationProfile* profile = builder->createOptimizationProfile();
profile->setDimensions("input", nvinfer1::OptProfileSelector::kMIN,
nvinfer1::Dims4{1, 3, 128, 128});
profile->setDimensions("input", nvinfer1::OptProfileSelector::kOPT,
nvinfer1::Dims4{1, 3, 224, 224});
profile->setDimensions("input", nvinfer1::OptProfileSelector::kMAX,
nvinfer1::Dims4{1, 3, 512, 512});
config->addOptimizationProfile(profile);
2. 视频分析场景
视频流的分辨率可能动态变化。比如监控摄像头,白天用高清模式,晚上为了省带宽切到低分辨率。用动态形状,一个引擎就能搞定。
3. NLP和语音任务
文本长度、语音时长都是不确定的。用动态形状处理变长输入,比静态形状优雅得多。
我的建议:如果你确定生产环境的输入尺寸是固定的,比如人脸识别门禁,那就用静态形状。性能更好,也更简单。但如果你不确定,或者场景多变,直接上动态形状。别犹豫,犹豫就会败北。
不过要注意,动态形状不是银弹。它带来的代价是:
- 构建时间更长:TensorRT需要为范围内的多个尺寸做优化
- 引擎文件更大:包含了多个尺寸的优化策略
- 性能可能略低:相比专门为某个尺寸优化的静态引擎
嗯,这就是静态形状和动态形状的基本情况。下一节我们会深入动态形状的具体实现,包括如何配置优化策略、如何处理多profile等实战内容。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。