2、核心架构差异:TensorRT的图优化引擎 vs TensorRT-LLM的流式批处理引擎
好,咱们直接切入正题。很多人刚接触这两个东西时,第一反应是:“TensorRT-LLM不就是TensorRT加了个大模型支持吗?”
嗯,这个想法其实挺危险的。我刚开始也这么以为,结果在项目里踩了不少坑。说白了,它们的核心架构设计哲学完全不同。一个是为静态图做极致优化,另一个是为动态生成做流式处理。今天我就把这两个引擎的底裤扒开,给你看个明白。
2.1 TensorRT的图优化引擎:静态图的“雕刻家”
TensorRT的核心,我习惯叫它“图优化引擎”。它的工作方式,你可以想象成一个雕刻家——拿到一块完整的石头(计算图),然后一刀一刀地雕琢,直到变成完美的艺术品。
具体来说,它做了这几件事:
- 层融合(Layer Fusion):把连续的卷积、BN、ReLU合并成一个kernel。我在项目中遇到过,一个ResNet50的模型,光这一步就能减少30%的显存访问。
- 精度校准(INT8/FP8):通过校准数据集,把FP32的权重映射到INT8。嗯,这里要注意,校准集选不好,精度会崩。
- 内核自动调优(Kernel Auto-Tuning):针对你的GPU型号,暴力搜索最优的kernel配置。我记得有一次,同一个模型在A100和V100上,TensorRT选出来的kernel完全不同。
核心特点:整个优化过程是离线完成的。你输入一个ONNX模型,它输出一个序列化的plan文件。推理时,直接加载plan文件执行,不再做任何优化。
你想想看,这种架构的好处是什么?确定性。一旦plan文件生成,每次推理的路径都是固定的,延迟非常稳定。但坏处也很明显——它假设你的输入形状是固定的。如果你的batch size或者序列长度变了,对不起,重新优化一遍吧。
2.2 TensorRT-LLM的流式批处理引擎:动态生成的“指挥家”
到了大模型时代,情况完全变了。LLM的推理不是一次性的前向传播,而是一个自回归生成过程:每次生成一个token,然后把新的token拼回去,再跑一次。
这就带来了两个核心挑战:
- 变长序列:每个请求的输入长度和输出长度都不一样。
- 动态批处理:不同请求可能处于生成的不同阶段,有的刚进来,有的快结束了。
TensorRT-LLM的流式批处理引擎,就是专门为这个场景设计的。它不像TensorRT那样把整个图优化好再执行,而是在推理过程中动态调度。
我举个例子你就明白了:
// TensorRT-LLM的流式批处理伪代码
while (有未完成的请求) {
// 1. 收集当前所有活跃请求的输入
batch = gather_active_requests(requests);
// 2. 动态填充(Padding)到当前batch的最大长度
padded_batch = dynamic_padding(batch);
// 3. 执行一次前向传播
outputs = model.forward(padded_batch);
// 4. 对每个请求,采样下一个token
for each request in requests {
next_token = sample(outputs[request]);
request.append(next_token);
// 5. 如果请求生成了终止符,把它移出batch
if (next_token == EOS) {
requests.remove(request);
// 释放显存,给新请求用
}
}
// 6. 如果有新请求进来,加入batch
new_requests = accept_new_requests();
requests.extend(new_requests);
}
看到了吗?每一步都在动态调整batch的组成。这就是流式批处理引擎的核心——它不是一个固定的执行计划,而是一个持续运行的调度循环。
个人经验:我在部署一个70B的模型时,刚开始用静态batch,显存利用率只有40%。换成流式批处理后,利用率直接飙到85%以上。说白了,静态batch是在“等”最慢的那个请求,流式batch是在“抢”每一个空闲的计算单元。
2.3 核心差异对比:一张表说清楚
| 维度 | TensorRT 图优化引擎 | TensorRT-LLM 流式批处理引擎 |
|---|---|---|
| 优化时机 | 离线(编译时) | 在线(推理时) |
| 输入形状 | 固定(需要指定max batch/size) | 动态(支持变长序列) |
| 批处理策略 | 静态批处理(所有请求同时开始,同时结束) | 动态批处理(请求随时加入/离开) |
| 显存管理 | 预分配固定大小的显存池 | 按需分配,支持KV Cache的Page管理 |
| 适用场景 | CV、传统NLP(BERT等) | 大语言模型(GPT、LLaMA等) |
| 延迟特性 | 低且稳定 | 受batch组成影响,有波动 |
2.4 架构对比图:一图胜千言
下面这张SVG图,我画了两个引擎的核心流程对比。左边是TensorRT的静态图优化,右边是TensorRT-LLM的流式批处理。你一看就明白。
2.5 避坑指南:我曾经踩过的坑
最后,分享几个我在实际项目中遇到的坑,希望能帮你少走弯路:
坑1:用TensorRT跑LLM
我曾经试过把GPT的整个计算图导出成ONNX,然后用TensorRT优化。结果呢?模型文件大了10倍,而且每次输入长度变化都要重新编译。折腾了两周,最后放弃了。说白了,TensorRT不适合自回归生成场景。
坑2:忽略流式批处理的显存碎片
刚开始用TensorRT-LLM时,我发现随着服务运行时间变长,显存碎片越来越严重。后来才知道,KV Cache的Page管理需要合理配置。我建议你根据最大并发数,提前预留好Page池的大小。
我的建议:如果你在做CV或者BERT类的模型,直接用TensorRT就好,简单高效。但如果你在搞LLM,别犹豫,直接上TensorRT-LLM。它的流式批处理引擎,就是为这个场景量身定做的。
好了,这一章的核心内容就这些。记住一句话:TensorRT优化的是“图”,TensorRT-LLM调度的是“流”。理解了这个本质区别,后面的内容你就知道该怎么选了。
公众号:蓝海资料掘金营,微信deep3321