1. 课程导入与工程全景
在真实的生产系统中,推理服务很少只跑一个模型。一个视频分析平台可能同时部署检测、跟踪、分类、OCR 四个模型;一个智能客服系统可能并行运行意图识别、实体抽取、向量检索与重排模型。当这些模型都希望借助 NVIDIA GPU 获得低延迟、高吞吐时,问题就从"如何用 TensorRT 优化单个模型"升级为"如何用 TensorRT 组织并服务多个模型"。这正是本课程要解决的核心命题。
什么是 TensorRT 多模型推理服务
TensorRT 多模型推理服务,指的是在同一套服务进程中,基于 TensorRT 运行时同时加载、调度并对外提供多个已优化引擎(engine)的推理能力。它包含三个层次的含义:
- 模型层:每个模型先经过 ONNX 导出、精度校准、层融合与 kernel 自动调优,生成序列化的
.plan引擎文件。 - 运行时层:由 TensorRT Runtime 负责反序列化引擎、分配显存、创建执行上下文(ExecutionContext),并管理输入输出绑定(Binding)。
- 服务层:由 Triton Inference Server 或自研服务框架负责请求路由、批处理调度、并发控制与指标暴露。
需要特别区分两个容易混淆的概念:多模型(multi-model)指同一服务实例内并存多个不同模型;多实例(multi-instance)指同一模型通过多个 ExecutionContext 或 CUDA Stream 并行执行。二者常组合使用,但资源竞争的表现完全不同。
核心挑战:为什么"多模型"比"单模型"难得多
单模型推理时,显存、算力、批处理策略都围绕一个引擎展开,调优空间相对简单。一旦引入多模型,四类矛盾会同时出现:
显存竞争是最先暴露的问题。假设一张 24GB 的 A10 上,检测模型引擎占 1.2GB、分类模型占 0.6GB、OCR 模型占 1.8GB,加上每个 ExecutionContext 的工作区(workspace)与激活值,实际占用往往远超权重之和。若再叠加动态批处理,峰值显存可能翻倍。工程上通常需要为每个模型显式设置 workspace 上限,并预留 15%~20% 的显存余量。
算力与延迟的权衡同样棘手。多个模型共享 SM 与 Tensor Core,若不加约束,高优先级请求会被低优先级的大 batch 拖慢。典型做法是给不同模型分配不同的 CUDA Stream 与优先级,或使用 Triton 的 instance group 限制并发数。
批处理策略冲突:检测模型适合大 batch 提升吞吐,而意图识别模型请求稀疏、延迟敏感,强行合并 batch 反而增加尾延迟。因此多模型服务通常采用"按模型独立配置动态批处理"的策略,而非全局统一。
版本与热更新:生产环境要求模型可灰度、可回滚。引擎文件与 TensorRT 版本、GPU 架构强绑定,跨卡迁移需重新构建,这要求服务层具备模型仓库(model repository)与版本目录管理能力。
典型应用场景
多模型推理服务在以下场景中几乎是刚需:
- 视频结构化:检测 + 跟踪 + 属性识别 + OCR 串联,单路视频每秒需处理数十帧。
- 大模型 RAG 服务:embedding 模型、rerank 模型与生成模型共存,前两者延迟敏感、后者吞吐敏感。
- 工业质检:缺陷检测、分类、分割多模型并行,要求确定性延迟。
- 多租户 AI 平台:不同业务方共享 GPU,需要隔离与配额。
整体技术栈全景
下图给出从模型到服务的完整链路,以及各层的关键对象与关注点。它也是本课程后续章节的路线图:模型转换与优化、引擎构建、运行时调度、服务框架、性能观测。
一个可运行的最小示例:双模型服务
为了让概念落地,下面给出一个基于 Triton 的双模型服务配置骨架。假设我们有两个已构建好的引擎:detector.plan(输入 1×3×640×640,FP16)与 classifier.plan(输入 1×3×224×224,INT8)。模型仓库目录结构如下:
model_repository/
├── detector/
│ ├── config.pbtxt
│ └── 1/
│ └── model.plan
└── classifier/
├── config.pbtxt
└── 1/
└── model.plan
其中 detector/config.pbtxt 的关键字段示例:
name: "detector"
platform: "tensorrt_plan"
max_batch_size: 8
input [{ name: "input" data_type: TYPE_FP16 dims: [3, 640, 640] }]
output [{ name: "output" data_type: TYPE_FP16 dims: [84, 8400] }]
dynamic_batching {
preferred_batch_size: [4, 8]
max_queue_delay_microseconds: 2000
}
instance_group [{ count: 2 kind: KIND_GPU gpus: [0] }]
而 classifier/config.pbtxt 则采用更小的批与更短的排队延迟,因为分类请求通常稀疏且延迟敏感:
name: "classifier"
platform: "tensorrt_plan"
max_batch_size: 16
dynamic_batching {
preferred_batch_size: [1, 4]
max_queue_delay_microseconds: 500
}
instance_group [{ count: 1 kind: KIND_GPU gpus: [0] }]
启动服务后,可通过 HTTP 接口分别请求两个模型:
curl -X POST http://localhost:8000/v2/models/detector/infer \
-d '{"inputs":[{"name":"input","shape":[1,3,640,640],"datatype":"FP16","data":[...]}]}'
观察结果时,重点看三个指标:nv_inference_request_success(成功请求数)、nv_inference_queue_duration_us(排队耗时)与 nv_inference_compute_infer_duration_us(实际推理耗时)。若排队耗时远大于推理耗时,说明批处理窗口或实例数配置不合理;若显存接近上限,则应下调 max_batch_size 或减少 instance count。