机器学习数学基础专题【左扬精讲】—— 大模型推理与部署:从 PyTorch 到 ONNX / TensorRT / vLLM
机器学习数学基础专题【左扬精讲】—— 大模型推理与部署:从 PyTorch 到 ONNX / TensorRT / vLLM
训练只是大模型落地的第一步。
训练好的模型要真正服务于用户,必须经过推理优化与部署:用 ONNX 跨平台导出,用 TensorRT 做 GPU 极致加速,用 vLLM 处理高吞吐在线服务。
本文从推理基础出发,讲解大模型推理的核心挑战(KV Cache、量化、批处理)、主流部署框架的设计思路,以及如何为不同场景选择最合适的技术栈。
本文所有代码片段均为通用 PyTorch 2.x / ONNX / TensorRT / vLLM 写法,可在对应版本环境中运行验证 。
本文涉及的核心框架:
torch.onnx ← PyTorch 模型导出 ONNX
onnxruntime ← ONNX 模型推理引擎
tensorrt / torch_tensorrt ← NVIDIA GPU 极致推理加速
vllm ← 高吞吐 LLM 在线服务框架
bitsandbytes ← 模型量化(INT8 / INT4)
torch.compile ← PyTorch 2.0 原生图优化
推理优化 ONNX TensorRT vLLM 量化 KV Cache PagedAttention Continuous Batching 模型导出 部署 torch.compile
学习重点提示
★ 必须掌握
- 必须掌握:推理与训练的核心区别 — 推理不需要梯度,专注低延迟和高吞吐
- 必须掌握:KV Cache 的作用 — 避免每生成一个 token 都重新计算历史 attention
- 必须掌握:ONNX 导出的基本流程 — torch.onnx.export + onnxruntime 验证
- 必须掌握:vLLM 的 PagedAttention 解决了 LLM 推理的核心瓶颈
★ 建议掌握
- 建议掌握:INT8 / INT4 量化的精度-性能权衡
- 建议掌握:torch.compile 的图捕获与算子融合
- 建议掌握:Continuous Batching 提升 GPU 利用率
本文目录
- 一、推理与训练的本质区别 — What & Why
- 二、KV Cache:自回归推理的核心优化
- 三、ONNX:跨框架模型导出
- 四、TensorRT:NVIDIA GPU 极致优化
- 五、torch.compile:PyTorch 原生图优化
- 六、量化:INT8 / INT4 的精度-性能权衡
- 七、vLLM 与 PagedAttention:高吞吐 LLM 服务
- 八、部署框架选型指南
- 九、常见问题 FAQ(20 组)
- 十、Roadmap 后续预告
一、推理与训练的本质区别 — What & Why
What — 推理和训练的核心区别是什么?
训练需要前向传播 + 反向传播 + 参数更新,追求最小化损失;推理只需要前向传播,追求低延迟、高吞吐、低显存。两者对硬件、精度、优化方向的需求完全不同。
Why — 为什么不能直接用训练代码做推理?
问题一:训练保留计算图是为了反向传播
训练时所有中间变量都保留(用于 backward),推理不需要这些,可以大幅节省显存。
问题二:训练用 fp32 保证精度,推理可以用更低精度
推理对数值误差的容忍度更高,可以用 INT8、INT4 量化加速。
问题三:训练是批处理的,推理是逐请求的
训练每个 batch 一次处理多个样本,推理每个请求独立处理,延迟敏感。
没有推理优化会发生什么?
- 显存占用高,单卡只能跑几个并发请求。
- 延迟高,用户等待时间过长。
- GPU 利用率低,单次请求用不满算力。
# 方向 1: 关闭梯度
with torch.no_grad():
outputs = model(inputs)
# 方向 2: 切换到 eval 模式
model.eval()
# 方向 3: 量化
model_int8 = torch.quantization.quantize_dynamic(
model, {torch.nn.Linear}, dtype=torch.qint8
)
# 方向 4: 图编译优化
model = torch.compile(model, mode="reduce-overhead")
这四个优化可以叠加使用,逐层提升推理性能 。
二、KV Cache:自回归推理的核心优化
What — KV Cache 是什么?
自回归 LLM 生成时,每个新 token 都依赖之前所有 token 的 K 和 V。在没有 KV Cache 的情况下,每生成一个 token 都要重新计算整段历史的 K 和 V,计算量是 O(n^2)。有了 KV Cache,已生成的 K 和 V 被缓存,每步只需计算新 token 的 K 和 V,复杂度降至 O(n)。
Why — 为什么 KV Cache 如此重要?
对于 2048 token 的输入,KV Cache 可以让推理速度提升约 10~20 倍,显存占用增加有限(线性而非平方增长)。它是所有现代 LLM 推理框架的基础。
没有 KV Cache 会发生什么?
- 生成长文本时延迟指数级增长,无法实时响应。
- GPU 算力浪费在重复计算上,单次请求吞吐极低。
- 长上下文场景几乎不可用。
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("gpt2").cuda().eval()
tokenizer = AutoTokenizer.from_pretrained("gpt2")
inputs = tokenizer("Hello, my name is", return_tensors="pt").to("cuda")
# use_cache=True 启用 KV Cache(默认 True)
outputs = model.generate(
**inputs,
max_new_tokens=50,
use_cache=True,
do_sample=False,
)
print(tokenizer.decode(outputs[0]))
HuggingFace Transformers 在 generate() 中默认启用 KV Cache。对于自回归生成,必须设置 use_cache=True 否则会非常慢 。
三、ONNX:跨框架模型导出
What — ONNX 是什么?
Open Neural Network Exchange (ONNX) 是一个开放的模型表示格式,由 Meta 和微软联合发起。它定义了一个标准的计算图,可以在不同框架(PyTorch、TensorFlow、JAX)之间互转模型,并在不同硬件(CPU、GPU、NPU)上运行。
Why — 为什么需要 ONNX?
问题一:训练和部署框架不同
训练通常用 PyTorch,部署可能用 TensorFlow、CoreML、TensorRT。直接转换代价巨大。
问题二:硬件多样性
CPU 服务器、移动端、边缘设备的推理引擎不同。ONNX 提供统一的中间表示。
问题三:算子优化
ONNX Runtime 在底层做了大量算子融合、量化、并行化优化,比原始 PyTorch 推理更快。
没有 ONNX 会发生什么?
- 每个部署平台都要重新实现推理代码。
- 无法利用 ONNX Runtime 的优化能力。
import torch
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("gpt2").eval()
dummy_input = torch.zeros(1, 8, dtype=torch.long) # batch=1, seq=8
# 导出 ONNX
torch.onnx.export(
model,
(dummy_input,),
"gpt2.onnx",
input_names=["input_ids"],
output_names=["logits"],
dynamic_axes={
"input_ids": {0: "batch", 1: "sequence"},
"logits": {0: "batch", 1: "sequence"},
},
opset_version=17,
)
关键参数:dynamic_axes 声明动态维度(batch 和 sequence),否则模型只能接受固定大小输入。opset_version=17 是当前稳定版本,支持大部分 Transformer 操作。
四、TensorRT:NVIDIA GPU 极致优化
What — TensorRT 是什么?
TensorRT 是 NVIDIA 开发的 GPU 推理优化引擎。它通过算子融合、内核自动调优、量化、内存优化等手段,在 NVIDIA GPU 上达到极致推理性能。
Why — 为什么 TensorRT 比 ONNX Runtime 更快?
TensorRT 针对特定 GPU 架构(Ampere、Hopper 等)做内核自动调优,选择最优的 CUDA kernel 组合。它支持层融合(Conv + BN + ReLU 融合为一个 kernel)、动态 tensor 内存分配、FP16/INT8 量化等优化手段。
import torch_tensorrt
# 加载模型
model = MyModel().eval().cuda()
# 编译为 TensorRT 引擎
trt_model = torch_tensorrt.compile(
model,
inputs=[
torch_tensorrt.Input(
min_shape=[1, 8],
opt_shape=[16, 512],
max_shape=[32, 1024],
dtype=torch.float32,
)
],
enabled_precisions={torch.float16}, # 使用 fp16
)
# 推理
with torch.no_grad():
output = trt_model(input_tensor)
torch_tensorrt 是 PyTorch 官方的 TensorRT 集成。它接受 PyTorch 模型直接编译,省去了手动转换 ONNX 的步骤 。
五、torch.compile:PyTorch 原生图优化
What — torch.compile 是什么?
torch.compile 是 PyTorch 2.0 引入的图编译优化。它在第一次前向传播时捕获计算图,然后通过算子融合、内存优化、并行化等手段加速后续执行。
Why — 为什么 torch.compile 比 eager mode 快?
Eager mode 下每个 PyTorch 操作都立即执行 CUDA kernel,开销巨大。torch.compile 把多个小操作融合为一个 CUDA kernel,大幅减少 kernel launch 开销和内存访问次数。
import torch
# 一行代码启用图编译
model = torch.compile(model, mode="reduce-overhead")
# 推理
with torch.no_grad():
output = model(input)
mode 可选值包括 "default"、"reduce-overhead"、"max-autotune"。后者会做激进的算子调优,第一次编译会显著变慢,但推理时性能最优 。
六、量化:INT8 / INT4 的精度-性能权衡
What — 量化是什么?
量化是把 fp32/fp16 的权重和激活值映射到 INT8 或 INT4 的低精度表示。显存占用减少 2~8 倍,计算加速 2~4 倍,但会引入量化误差。
Why — 为什么不全部用 INT4?
问题一:精度损失
INT4 的表示范围只有 16 个值,对于 LLM 的大权重矩阵,会损失严重精度,导致 perplexity 飙升。
问题二:训练 vs 推理的精度容忍度不同
训练对精度极其敏感,必须 fp32;推理可容忍 1~3% 的精度下降以换取显著性能提升。
问题三:硬件支持
INT8 推理在大多数 GPU 上有原生加速;INT4 需要特定架构(Hopper)和 kernel 支持。
没有量化会发生什么?
- 显存占用高,单卡只能装下小模型。
- 吞吐量受限于显存带宽,而非计算单元。
from transformers import AutoModelForCausalLM
import bitsandbytes as bnb
# INT8 量化
model = AutoModelForCausalLM.from_pretrained(
"facebook/opt-6.7b",
load_in_8bit=True,
device_map="auto",
)
# INT4 量化(QLoRA 训练)
model = AutoModelForCausalLM.from_pretrained(
"facebook/opt-6.7b",
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
device_map="auto",
)
bitsandbytes 提供了 INT8 和 NF4 量化方案。NF4(4-bit NormalFloat)是为正态分布权重设计的特殊数据类型,比普通 INT4 精度更好 。
七、vLLM 与 PagedAttention:高吞吐 LLM 服务
What — vLLM 是什么?
vLLM 是 UC Berkeley 开发的 LLM 推理和服务框架。它的核心创新是 PagedAttention,借鉴操作系统的虚拟内存分页思想,解决了 LLM 推理中的 KV Cache 内存碎片化问题。
Why — 为什么传统推理框架吞吐低?
问题一:KV Cache 的连续分配
传统框架(如 HuggingFace Transformers)为每个请求预分配连续的 KV Cache 空间。不同请求长度差异大,导致严重碎片,浪费显存。
问题二:批处理效率低
传统静态 batching 要等所有请求完成才能开始下一批,GPU 利用率忽高忽低。
问题三:vLLM 的解决方案
PagedAttention 把 KV Cache 切分成固定大小的"页",类似操作系统管理内存。请求完成即释放页,显存可以立即被其他请求复用。Continuous Batching 让完成的请求立即被新请求替换,GPU 始终满载。
没有 PagedAttention 会发生什么?
- 显存浪费严重,单卡并发请求数极少。
- GPU 利用率低,吞吐量仅为 vLLM 的 1/5~1/10。
# 安装:pip install vllm
from vllm import LLM, SamplingParams
# 启动 LLM 服务
llm = LLM(
model="meta-llama/Llama-2-7b-hf",
tensor_parallel_size=1,
gpu_memory_utilization=0.9,
max_num_batched_tokens=8192,
)
# 推理
prompts = ["Hello, my name is", "The capital of France is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95, max_tokens=100)
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(f"Prompt: {output.prompt!r}")
print(f"Generated: {output.outputs[0].text!r}")
vLLM 一行代码即可启动高性能 LLM 服务。它内置了 Continuous Batching、PagedAttention、Tensor Parallel 等所有优化 。
八、部署框架选型指南
| 场景 | 推荐框架 | 理由 |
|---|---|---|
| 在线 LLM 服务(高吞吐) | vLLM | PagedAttention + Continuous Batching |
| NVIDIA GPU 极致优化 | TensorRT | 硬件级内核优化 |
| 跨平台部署(CPU + GPU) | ONNX Runtime | 统一模型格式 |
| PyTorch 快速优化 | torch.compile | 零代码改造 |
| 边缘设备(手机、嵌入式) | ONNX + 量化 | 小体积、低功耗 |
| 大批量离线推理 | DeepSpeed-Inference | 张量并行 + 量化 |
九、常见问题 FAQ(20 组)
FAQ 常见问题解答
Q1. 推理和训练的根本区别是什么?
推理不需要反向传播,专注低延迟和高吞吐。推理只用前向传播,可以关闭梯度、降低精度、量化模型。
Q2. 什么是 KV Cache?
缓存已生成 token 的 Key 和 Value,避免重复计算。它是 LLM 自回归推理的核心优化,可让生成速度提升 10~20 倍。
Q3. ONNX 是什么?
Open Neural Network Exchange,开放的模型交换格式。让模型在不同框架和硬件之间互转,是工业部署的事实标准。
Q4. ONNX 和 TensorRT 有什么区别?
ONNX 是模型格式,TensorRT 是推理引擎。ONNX 提供跨平台的中间表示,TensorRT 在 NVIDIA GPU 上做极致优化。
Q5. 什么是 PagedAttention?
vLLM 提出的 KV Cache 内存管理方案。借鉴操作系统的虚拟内存分页,把 KV Cache 切分成固定大小页,解决碎片化问题 。
Q6. 为什么量化能加速推理?
低精度计算更快、显存占用更少。INT8 比 fp32 快 2~4 倍,显存少 4 倍。GPU 的 Tensor Core 对低精度有原生支持。
Q7. INT8 量化会损失精度吗?
通常有 1~3% 的精度下降。对于分类、生成任务影响较小,但对回归、数值敏感任务影响较大。
Q8. 为什么需要 torch.compile?
减少 CUDA kernel launch 开销。eager mode 每个操作都启动一次 kernel,compile 后多个操作融合为一次 kernel。
Q9. vLLM 比 HuggingFace 快多少?
通常 5~20x 吞吐提升。vLLM 的 PagedAttention 解决显存碎片,Continuous Batching 提升 GPU 利用率。
Q10. 什么是 Continuous Batching?
动态批次管理。完成的请求立即被新请求替换,GPU 始终满载。传统静态 batching 必须等所有请求完成才能开始下一批。
Q11. ONNX 导出的常见错误?
动态 shape、动态控制流、自定义算子。导出时需要声明 dynamic_axes,自定义算子需要用 onnx-script 包装。
Q12. 什么是动态 batching?
按请求动态合并批次。新请求到来时立即加入当前批次,无需等待。Continuous Batching 是动态 batching 的一种。
Q13. 如何选择 batch size?
在延迟预算内尽量大。大 batch 提升吞吐但增加延迟。建议通过 profiling 找到延迟-吞吐的最佳平衡点。
Q14. 什么是 speculative decoding?
用小模型预生成 token,大模型一次性验证。可以在不损失精度的前提下加速 2~3 倍。vLLM、TensorRT-LLM 都支持。
Q15. TensorRT-LLM 是什么?
NVIDIA 针对 LLM 优化的 TensorRT 扩展。提供了针对 Transformer 的高级优化(KV Cache 优化、PagedAttention、量化),比通用 TensorRT 更适合 LLM。
Q16. 推理时为什么要用 eval 模式?
关闭 Dropout 和 BatchNorm 的训练行为。推理需要稳定的输出,eval 模式禁用 Dropout 并固定 BatchNorm 的统计量。
Q17. 什么是 prefill 和 decode 阶段?
LLM 推理的两个阶段。Prefill 处理整个 prompt 一次性计算 K/V,decode 逐 token 生成。两者计算模式不同,常用不同并行策略。
Q18. 模型量化的常见方法?
训练后量化(PTQ)和量化感知训练(QAT)。PTQ 在训练后直接量化,简单但精度损失大;QAT 在训练中模拟量化,精度更好但复杂。
Q19. 为什么 ONNX 模型比 PyTorch 模型小?
因为 ONNX 只保存计算图和权重。PyTorch 模型保留 Python 对象和调试信息,文件通常大几倍。
Q20. 如何部署多模态模型?
分别导出图像、文本编码器,再用 ONNX 拼接。多模态模型的部署更复杂,常需要 Triton Inference Server 等专门的推理服务器。
全篇总纲
- 1 个核心优化:KV Cache 把推理复杂度从 O(n^2) 降到 O(n)
- 1 个跨平台标准:ONNX 是模型交换的事实格式
- 1 个 NVIDIA 极致方案:TensorRT 提供硬件级推理优化
- 1 个 LLM 服务框架:vLLM 用 PagedAttention 解决显存碎片
- 3 个加速手段:torch.compile(编译)/ 量化(精度)/ vLLM(批处理)
十、Roadmap 后续预告
后续预告
- 第 11 篇:深度学习模型评估与基准测试
- 第 12 篇:模型微调与对齐(PEFT / LoRA / RLHF)

浙公网安备 33010602011771号