Distributed Training & Inference Deployment
LLM 大规模训练
与部署
分布式训练并行 · 推理服务化 · 量化压缩

六大章节 | 训练并行策略 + 推理工程实践

DDP · FSDP · Tensor/Pipeline 并行 · ZeRO · vLLM · 量化 · 服务化

系统与工程
目 录
第一章   数据并行:DP / DDP / FSDP
1.1   引言:为什么需要并行
1.2   DataParallel 的局限
1.3   DistributedDataParallel 与 AllReduce
1.4   梯度桶与通信计算重叠
1.5   FSDP:参数、梯度、优化器状态全分片
1.6   梯度累积与有效批大小
第二章   模型并行:Tensor 与 Pipeline
2.1   张量并行的基本切分(Megatron-LM)
2.2   Column-Parallel 与 Row-Parallel
2.3   Attention 与 MLP 的并行化
2.4   流水线并行 GPipe / 1F1B
2.5   流水线气泡与 Interleaved 调度
2.6   序列并行(Sequence Parallelism)
第三章   ZeRO 与 3D 并行
3.1   显存占用拆解
3.2   ZeRO Stage 1 / 2 / 3
3.3   ZeRO-Offload 与 ZeRO-Infinity
3.4   3D 并行的组合与拓扑
3.5   DeepSpeed vs Megatron-LM
3.6   训练 GPU 数估算公式
第四章   推理服务架构与批处理
4.1   推理工作流:Prefill 与 Decode
4.2   PagedAttention 与 KV Cache 分页
4.3   连续批处理(Continuous Batching)
4.4   投机解码(Speculative Decoding / EAGLE)
4.5   Prefill / Decode 分离部署
4.6   主流框架对比:vLLM / TGI / SGLang / TensorRT-LLM
第五章   量化与模型压缩
5.1   量化基础:对称 / 非对称 / 静态 / 动态
5.2   GPTQ:基于二阶信息的逐层量化
5.3   AWQ:激活感知权重量化
5.4   SmoothQuant:激活迁移到权重
5.5   KV Cache 量化(INT8 / FP8)
5.6   蒸馏、剪枝与结构化稀疏
第六章   生产部署与服务化
6.1   关键指标:TTFT / TPOT / Throughput
6.2   SLO 设计与吞吐-延迟权衡
6.3   弹性扩缩容与冷启动
6.4   LLM Gateway 与多模型路由
6.5   监控、灰度发布与回滚
6.6   成本估算与优化
第 一 章
数据并行:DP / DDP / FSDP

1.1 引言:为什么需要并行

单卡训练大模型的瓶颈是显存与吞吐。当模型参数量超过单 GPU 显存上限,或单卡训练时间无法接受时,必须把工作切到多卡甚至多机。并行策略主要分三类:数据并行(不同 GPU 看不同样本,参数副本相同)、模型并行(不同 GPU 持有模型不同部分)、流水线并行(不同 GPU 负责不同层)。三者可以正交组合,构成所谓 3D 并行。

数据并行是最常用、最简单、扩展性最好的策略,本章系统讲清三代实现:PyTorch DataParallel(DP,单机多卡,已过时)、DistributedDataParallel(DDP,事实标准)、FullyShardedDataParallel(FSDP,ZeRO-3 的 PyTorch 原生版本)。

1.2 DataParallel 的局限

PyTorch 早期的 nn.DataParallel 将一个 batch 切分到多卡前向,主卡(rank 0)负责聚合损失、反传梯度、广播参数。它的核心问题有四个:

结论:生产中不要再用 DP,统一用 DDP。

1.3 DistributedDataParallel 与 AllReduce

DDP 是 多进程架构,每张 GPU 对应一个独立进程,每个进程持有完整模型副本,绕开 GIL。前向各算各的,反向时通过 AllReduce 把所有进程的梯度求和并平均,保证参数更新一致。

1.3.1 Ring-AllReduce 的通信代价

设总参数量 $P$、GPU 数 $N$、每个 float 占 $b$ 字节,Ring-AllReduce 的总通信量约为:

$$\text{Comm}_{\text{AllReduce}} \approx 2 \cdot \frac{N-1}{N} \cdot P \cdot b \approx 2 P b \quad (N \to \infty)$$

因为 AllReduce = ReduceScatter + AllGather,两阶段各传 $\tfrac{N-1}{N} P b$。一个关键事实:通信量与 GPU 数 $N$ 无关,所以 Ring-AllReduce 在带宽足够时是线性扩展的。但这只是 带宽 维度的好消息——延迟 仍随 $N$ 线性增长,因为环路一圈要走 $2(N-1)$ 步。

1.4 梯度桶与通信计算重叠

朴素 DDP 每个参数的梯度都触发一次小 AllReduce,开销巨大。PyTorch 用 gradient bucket(默认 25 MB)合并相邻反向算出的梯度,凑满一桶后一次性 AllReduce。这一桶 AllReduce 在后台 NCCL stream 上进行,与上游层的反向计算并行执行,理想情况下完全隐藏通信时间。

import torch
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP

dist.init_process_group(backend="nccl")
torch.cuda.set_device(local_rank)
model = MyModel().to(local_rank)
model = DDP(
    model,
    device_ids=[local_rank],
    bucket_cap_mb=25,                  # 桶大小
    gradient_as_bucket_view=True,      # 梯度直接用 bucket 视图,省一次拷贝
    find_unused_parameters=False,      # 关闭可加速;开启会增加一次反向遍历
)

关键调优点:

1.5 FSDP:参数、梯度、优化器状态全分片

DDP 把参数完整复制到每张卡,显存浪费严重。FSDP(Fully Sharded Data Parallel,对应 DeepSpeed 的 ZeRO-3)把参数梯度优化器状态都按 GPU 分片,只在前向/反向需要某层时临时 AllGather 整层参数。

显存对比,模型参数量 $P$,混合精度训练(FP16 参数+FP32 优化器主权重):

策略参数梯度优化器状态合计(fp16/fp32 Adam)
DDP$2P$ (fp16)$2P$ (fp16)$12P$ (master+m+v, fp32)$16P$ 字节/卡
FSDP / ZeRO-3$2P / N$$2P / N$$12P / N$$16P / N$ 字节/卡

FSDP 的代价是多了两次通信:前向前 AllGather、反向后 ReduceScatter,总通信量约 $3Pb$(DDP 是 $2Pb$)。即 1.5× 通信换 $N$× 显存。在显存受限时是绝对值得的。

from torch.distributed.fsdp import FullyShardedDataParallel as FSDP
from torch.distributed.fsdp import MixedPrecision, ShardingStrategy
from torch.distributed.fsdp.wrap import transformer_auto_wrap_policy
from functools import partial

mp_policy = MixedPrecision(
    param_dtype=torch.bfloat16,        # 参数与计算用 bf16
    reduce_dtype=torch.float32,        # 梯度规约用 fp32 防溢出
    buffer_dtype=torch.bfloat16,
)

wrap_policy = partial(
    transformer_auto_wrap_policy,
    transformer_layer_cls={TransformerBlock},  # 每个 Transformer 层作为一个分片单元
)

model = FSDP(
    model,
    sharding_strategy=ShardingStrategy.FULL_SHARD,   # ZeRO-3
    mixed_precision=mp_policy,
    auto_wrap_policy=wrap_policy,
    device_id=local_rank,
    limit_all_gathers=True,            # 限制 AllGather 队列深度,省显存
)

FSDP 的 ShardingStrategy 三档:

1.6 梯度累积与有效批大小

当单步显存放不下目标 batch size,可以用梯度累积把一个大 batch 拆成 $K$ 个 micro-batch,每个 micro-batch 反向出来的梯度累加在 .grad 上但不立即 optimizer.step(),累加 $K$ 次后再统一更新。等效于:

$$\text{Effective Batch} = \text{micro\_batch} \times \text{DP\_world\_size} \times \text{grad\_accum\_steps}$$

for step, batch in enumerate(loader):
    with model.no_sync() if (step + 1) % K != 0 else nullcontext():
        loss = model(batch) / K        # 缩放避免梯度爆炸
        loss.backward()                # 累加到 .grad
    if (step + 1) % K == 0:
        optimizer.step()
        optimizer.zero_grad()

关键技巧 model.no_sync():在累积期间禁用 DDP/FSDP 的梯度同步,只在最后一次反向才触发 AllReduce/ReduceScatter,可以省 $K-1$ 次通信。Hugging Face Trainer 默认就是这种模式。

第 二 章
模型并行:Tensor 与 Pipeline

2.1 张量并行的基本切分(Megatron-LM)

当单层参数大到放不进单卡时,必须做层内切分,即张量并行(Tensor Parallelism, TP)。最经典的方案来自 NVIDIA Megatron-LM (Shoeybi et al., 2019),针对 Transformer 的两个核心子层——MLP 和多头注意力——给出了精心设计的切分方式。

设 TP 度为 $t$(即把一层在 $t$ 张卡上切),切分准则是:同一前向中只在子层结尾做一次 AllReduce,把中间激活的切分代价压到最低。

2.2 Column-Parallel 与 Row-Parallel

线性层 $Y = X A$,矩阵 $A \in \mathbb{R}^{d_{\text{in}} \times d_{\text{out}}}$ 有两种切法:

2.2.1 列并行(Column-Parallel)

把 $A$ 按列切:$A = [A_1, A_2, \ldots, A_t]$,每张卡持有 $A_i \in \mathbb{R}^{d_{\text{in}} \times d_{\text{out}}/t}$。每张卡独立计算 $Y_i = X A_i$,得到 $Y = [Y_1, \ldots, Y_t]$ 的拼接。前向无通信,但输出是切分的。

2.2.2 行并行(Row-Parallel)

把 $A$ 按行切:$A = [A_1; A_2; \ldots; A_t]$,输入也必须切分 $X = [X_1, \ldots, X_t]$。每张卡算 $Y_i = X_i A_i$,最后AllReduce 求和得到完整 $Y = \sum_i X_i A_i$。前向需要一次 AllReduce。

2.2.3 组合:先列后行

Megatron 的关键 trick:MLP 的第一个线性层用列并行(输出切分),紧接的 GeLU 是逐元素的可以直接在切分上算,第二个线性层用行并行(输入是切分的,正好对接)。整个 MLP 只在最后一次 AllReduce

$$X \xrightarrow{\text{Col}} [Y_1, \ldots, Y_t] \xrightarrow{\text{GeLU}} [Z_1, \ldots, Z_t] \xrightarrow{\text{Row}} \sum_i Z_i B_i \xrightarrow{\text{AllReduce}} \text{Output}$$

2.3 Attention 与 MLP 的并行化

多头注意力天然适合按 head 维度切:把 $h$ 个 head 平均分到 $t$ 张卡,每卡负责 $h/t$ 个头。$Q, K, V$ 的投影矩阵列并行切,每个头独立算 attention,输出投影行并行汇总。同样只在子层结尾一次 AllReduce。

反向时同样需要一次 AllReduce(梯度对应),所以一层 Transformer 前+反共 4 次 AllReduce(MLP 一次正一次反,Attention 一次正一次反)。设隐藏维 $h$、序列长 $s$、micro-batch 大小 $b$,单次 AllReduce 通信量 $\sim 2bsh$(输出激活),总通信量约:

$$\text{Comm}_{\text{TP,1 layer}} \approx 4 \cdot \frac{t-1}{t} \cdot 2bsh \cdot \text{bytes}$$

关键:TP 通信量与激活成正比,与参数量无关。这与 DDP 的 AllReduce(与参数成正比)正交,互补。

2.4 流水线并行 GPipe / 1F1B

当层数远超 TP 切分能力时,把不同放到不同 GPU 上,构成流水线并行(Pipeline Parallelism, PP)。挑战是:原始的串行训练会让 GPU 大部分时间在等上游/下游,利用率极低。

2.4.1 GPipe(朴素流水线)

把一个 mini-batch 拆成 $m$ 个 micro-batch,前向阶段连续把 $m$ 个 micro-batch 灌入流水线,等所有前向完成再统一反向。设 PP 度 $p$(即流水线深度)、单 stage 时间 $t$:

$$T_{\text{GPipe}} = (m + p - 1) \cdot t \cdot 2 \quad\text{(前向+反向)}$$

气泡(GPU 空闲)比例:

$$\text{Bubble Fraction} = \frac{p - 1}{m + p - 1}$$

典型实践 $m = 4p \sim 8p$,气泡率约 11%~20%。

2.4.2 1F1B(PipeDream / Megatron)

GPipe 的问题是反向阶段所有 stage 的前向激活必须存满,显存占用 $O(m)$。1F1B 调度让每个 stage 在前向后立刻反向(One-Forward-One-Backward),最多只需要保留 $p$ 个 micro-batch 的激活:

$$\text{Activation Mem} = O(p) \cdot \text{per micro-batch}$$

气泡率与 GPipe 相同,但显存大幅降低。Megatron-LM 默认就是 1F1B。

2.5 流水线气泡与 Interleaved 调度

Interleaved 1F1B(Megatron, Narayanan et al., 2021)把每张 GPU 的层数再分成 $v$ 个虚拟 stage,让 GPU 在多个虚拟 stage 间交替执行。气泡率降至:

$$\text{Bubble} = \frac{1}{v} \cdot \frac{p - 1}{m + p - 1}$$

$v = 2$ 即可把气泡减半。代价是通信次数从 $p$ 增至 $p \cdot v$,需要更低延迟的链路(NVLink/NVSwitch 上很值,跨节点 InfiniBand 上得权衡)。

[ Architecture Diagram ]
graph LR
    subgraph "1F1B Pipeline (p=4 stages, m=8 microbatches)"
        direction LR
        S1["Stage 1
F1 F2 F3 F4 B1 F5 B2 F6 B3 ..."] S2["Stage 2
... F1 F2 F3 B1 F4 B2 ..."] S3["Stage 3
... ... F1 F2 B1 F3 ..."] S4["Stage 4
... ... ... F1 B1 F2 ..."] S1 --> S2 --> S3 --> S4 end

2.6 序列并行(Sequence Parallelism)

TP 把激活按特征维 $h$ 切了,但 LayerNorm 和 Dropout 仍持有完整激活(因为 LN 涉及 $h$ 维统计,不能在 $h$ 切的副本上算)。激活显存占比可达 25%。序列并行(Korthikanti et al., 2022)把这些层的激活沿序列维 $s$ 切,与 TP 的特征切互补,整层激活全切:

$$\text{Act Mem per GPU} = \text{Layer Acts} \cdot \frac{1}{t} \quad \text{(seq + tensor)} $$

代价是 TP 的 AllReduce 换成 ReduceScatter+AllGather(通信量相同),不增加通信量但需要额外同步点。Megatron-LM 的现代版本默认开启。

第 三 章
ZeRO 与 3D 并行

3.1 显存占用拆解

分析任何并行策略,第一步要算清楚单卡显存账。混合精度训练(Adam,主流)下,参数量 $P$ 个的模型,每个参数占用:

精度字节/参数
FP16 / BF16 参数fp162
FP16 梯度fp162
FP32 主权重(Adam 更新用)fp324
Adam $m$(一阶动量)fp324
Adam $v$(二阶动量)fp324
合计16

所以 7B 模型纯训练态显存约 $7 \times 10^9 \times 16 = 112 \text{ GB}$,再加激活、临时 buffer,单 80GB H100 也放不下。

激活显存的估算(前向中所有层中间结果):

$$M_{\text{act}} \approx s \cdot b \cdot L \cdot (34 h + 5 a s) \text{ bytes}$$

其中 $s$ 序列长、$b$ batch、$L$ 层数、$h$ 隐藏维、$a$ 注意力头数(Korthikanti 2022 公式)。激活检查点(gradient checkpointing)可以把这项降到 $\sqrt{L}$ 量级,代价是反向多算 33%。

3.2 ZeRO Stage 1 / 2 / 3

ZeRO(Rajbhandari et al., 2020)的核心思想:DDP 让每张卡持有相同的 16P 字节是冗余的,可以按 GPU 数 $N$ 分片。三个 stage 分别分片不同部分:

Stage分片对象单卡显存(混合精度 Adam)额外通信
0 (DDP)$16P$$2P$ AllReduce
1优化器状态($m, v$, master weights)$4P + 12P/N$$2P$
2+ 梯度$2P + 14P/N$$2P$
3+ 参数(FSDP)$16P/N$$3P$(AllGather+ReduceScatter+AllGather)

Stage 1/2 的关键好处是通信量不增加(仍是 $2P$,只是把 AllReduce 改成 ReduceScatter),但显存大幅下降。Stage 3 需要额外的 AllGather 来重组参数做前向,所以通信量从 $2P$ 涨到 $3P$,1.5× 代价换 $N$× 显存。

3.3 ZeRO-Offload 与 ZeRO-Infinity

当 GPU 还是放不下,ZeRO-Offload(Ren et al., 2021)把优化器状态和梯度卸载到 CPU 内存,CPU 做 Adam 更新(CPU 慢但够用,因为 step 频率低)。GPU 显存进一步降到 $\sim 2P$(仅参数)。

ZeRO-Infinity(Rajbhandari et al., 2021)更进一步,把参数也卸载到 CPU 甚至 NVMe SSD,配合 PCIe/NVMe 带宽预取。可以在 8 张 V100 上训练万亿参数模型,但训练吞吐显著下降(IO 成为瓶颈),主要用在无 H100 集群的场景。

{
    "zero_optimization": {
        "stage": 3,
        "offload_optimizer": {"device": "cpu", "pin_memory": true},
        "offload_param":     {"device": "cpu", "pin_memory": true},
        "overlap_comm": true,
        "contiguous_gradients": true,
        "reduce_bucket_size": 1e8,
        "stage3_prefetch_bucket_size": 5e7,
        "stage3_param_persistence_threshold": 1e6
    },
    "bf16": {"enabled": true},
    "gradient_accumulation_steps": 8,
    "train_micro_batch_size_per_gpu": 1
}

3.4 3D 并行的组合与拓扑

三种并行可以正交组合:$N_{\text{GPU}} = \text{DP} \times \text{TP} \times \text{PP}$。一个典型 1024 卡 训练 175B 模型的配置:

选型经验法则:

3.5 DeepSpeed vs Megatron-LM

维度DeepSpeedMegatron-LM
主要创新ZeRO 系列(显存分片)张量并行 + 1F1B 流水线
易用性JSON 配置,Hugging Face Trainer 集成需要改模型代码(替换为并行版 layer)
极限规模用 Offload 可推到万亿需要 3D 组合,需手工调拓扑
典型场景10B 以下、显存受限100B+、需 TP/PP

实践中常见的Megatron-DeepSpeed 组合:用 Megatron 的 TP+PP,用 DeepSpeed 的 ZeRO-1 做 DP,取两者之长。

3.6 训练 GPU 数估算公式

训练总计算量(前向+反向 ≈ 3 倍前向):

$$C = 6 \cdot P \cdot D \quad \text{FLOPs}$$

$P$ 参数量,$D$ 训练 token 数。一张 H100 的 BF16 算力 989 TFLOPS,实际利用率(MFU, Model FLOPs Utilization)通常 30%~50%。训练时间:

$$T_{\text{days}} = \frac{6 P D}{N \cdot \text{MFU} \cdot 989 \times 10^{12} \cdot 86400}$$

例:70B 模型,2T token,MFU = 45%,512 张 H100:

$$T = \frac{6 \times 7 \times 10^{10} \times 2 \times 10^{12}}{512 \times 0.45 \times 989 \times 10^{12} \times 86400} \approx 42 \text{ 天}$$

这个公式是 BD/采购对话的硬通货,记住。

第 四 章
推理服务架构与批处理

4.1 推理工作流:Prefill 与 Decode

LLM 推理可清晰地分为两个阶段,二者的计算特性完全不同:

这个不对称是后续所有调度优化的根因:prefill 想攒大 batch 跑满算力,decode 想最小化 KV Cache 读取。

4.2 PagedAttention 与 KV Cache 分页

传统实现给每个序列预分配一块连续 KV Cache(按最大长度 $S_{\max}$),导致严重的内部碎片(实际生成长度往往远短于 $S_{\max}$)和外部碎片(不同序列长度差异大)。vLLM (Kwon et al., 2023) 提出 PagedAttention,把 KV Cache 切成固定大小的 block(典型 16 token),用一张页表(block table)映射逻辑块到物理块,效仿操作系统虚拟内存:

$$\text{Mem Utilization}_{\text{naive}} \approx 30\%, \quad \text{Mem Utilization}_{\text{paged}} \approx 96\%$$

关键收益:

4.3 连续批处理(Continuous Batching)

静态批处理(static batching)等所有序列生成完再返回——长序列拖死整批,GPU 利用率惨。连续批处理(也叫 in-flight batching,Yu et al., 2022 / Orca)让每一步 decode 都可以替换已完成的序列:

[ Architecture Diagram ]
sequenceDiagram
    participant S as Scheduler
    participant Q as Pending Queue
    participant E as Execution Batch
    loop Each iteration
        S->>Q: pull new requests
        S->>E: evict completed sequences
        S->>E: add new prefill / continue decode
        E->>E: one forward step
        E->>S: emit tokens, mark finished
    end

实际工程要点:

4.4 投机解码(Speculative Decoding / EAGLE)

核心观察:decode 是 memory-bound,每步从 HBM 读完整模型权重生成 1 token,计算单元闲置。若能用小 draft 模型预测出 $k$ 个候选 token,再让大模型一次 forward 同时验证这 $k$ 个,就可以一次步进出多个 token,分摊 HBM 读取。

Leviathan et al. (2022) 证明:只要 draft 模型的接受率 $\alpha$ 不为零,每步期望生成 token 数

$$\mathbb{E}[\text{tokens per step}] = \frac{1 - \alpha^{k+1}}{1 - \alpha}$$

输出分布与原模型严格等价(拒绝采样保证)。典型加速 2~3×。

新一代方案:

4.5 Prefill / Decode 分离部署

把 prefill 和 decode 调度到不同的 GPU 池,因为两阶段的最优配置不同:

阶段瓶颈最优 TP最优 batch典型卡型
Prefillcompute高(TP=4-8)小(甚至 1)H100/H200(强算力)
Decodememory bandwidth低(TP=1-2)大(128+)L40S/A10(性价比 HBM)

代表系统:DistServe(Zhong et al., 2024)、Mooncake(Moonshot 2024)、SplitWise(Patel et al., 2024)。代价是 KV Cache 必须从 prefill GPU 转给 decode GPU(RDMA 传输),约 100 μs/MB,大模型场景值得。

4.6 主流框架对比

框架厂商核心特性适用场景
vLLMUC BerkeleyPagedAttention,开源生态最完整开源模型自托管,研究/创业
TGIHugging FaceHF 模型零配置接入HF 模型快速 demo
SGLangUC Berkeley / xAIRadixAttention(prefix tree 共享),结构化输出多 turn、共享 prompt 场景
TensorRT-LLMNVIDIA编译优化最深,与 Triton 集成纯 NVIDIA 栈、极致性能
LMDeployInternLMTurboMind 内核,AWQ 量化优秀低显存部署、中文模型

2024-2025 的快速参考:研究/原型 选 vLLM;生产高吞吐 + NVIDIA 栈选 TensorRT-LLM;多 turn 重共享 prompt 选 SGLang。

第 五 章
量化与模型压缩

5.1 量化基础:对称 / 非对称 / 静态 / 动态

量化的目的是用低精度整数表示原本的 FP16/BF16 张量,省显存、加快矩阵乘(Tensor Core 对 INT8/INT4 吞吐是 FP16 的 2×/4×)。基本映射:

$$q = \text{round}\!\left(\frac{x}{s}\right) + z, \qquad x \approx s(q - z)$$

其中 $s$ 是 scale,$z$ 是 zero-point。$z=0$ 称对称量化,适合分布零中心化的权重;$z\neq 0$ 是非对称量化,适合像 ReLU 后激活那样偏向一侧的分布。

按 scale 来源又分:

粒度(granularity):

5.2 GPTQ:基于二阶信息的逐层量化

GPTQ (Frantar et al., 2022) 借鉴 Optimal Brain Surgeon 思想:把量化每一列权重视作一次"删除",用 Hessian 信息补偿剩余列。对线性层 $Y = XW$,目标是最小化输出误差:

$$\min_{\hat W} \| X W - X \hat W \|_F^2$$

$\hat W$ 是量化后权重。逐列贪心求解,量化第 $i$ 列时把误差按 $H^{-1}$($H = 2 X^\top X$)补偿到后续未量化列:

$$\delta W_{j} = -\frac{w_i - \text{quant}(w_i)}{[H^{-1}]_{ii}} \cdot [H^{-1}]_{ij}, \quad j > i$$

关键工程优化:使用 Cholesky 分解一次性算出 $H^{-1}$ 的上三角,避免数值不稳定;group_size=128 配合 act-order,可以把 4-bit 量化 perplexity 损失压到 0.1 以内。Llama-2-70B GPTQ 4-bit 显存从 140 GB 降到 35 GB,单 A100 可推。

5.3 AWQ:激活感知权重量化

AWQ (Lin et al., 2023) 的关键观察:权重 outlier 不重要,激活 outlier 才重要。某些通道(约 1%)的激活幅度极大,量化其对应的权重时引入的误差被激活放大。解决方案:在量化前给这些通道的权重乘一个缩放 $s_i$,对应激活除以 $s_i$,数学上等价,但缩放后的权重更易量化:

$$Y = (X \cdot \text{diag}(s)^{-1}) \cdot (\text{diag}(s) \cdot W) = X W$$

缩放因子 $s_i$ 通过对每通道激活幅值的统计搜索得到,典型 $s_i = (|\bar x_i|)^\alpha$,$\alpha$ 在 [0.5, 1.0] 网格搜索。AWQ 对指令微调模型友好,量化损失常优于 GPTQ。

5.4 SmoothQuant:激活迁移到权重

SmoothQuant (Xiao et al., 2022) 同样针对激活 outlier 问题,但目标是W8A8(权重和激活都 INT8)。它在每个 LayerNorm 后插入一个对角缩放,把激活的难量化"迁移"给权重:

$$\hat X = X \cdot \text{diag}(s)^{-1}, \quad \hat W = \text{diag}(s) \cdot W$$

$s$ 同样按激活通道幅值搜索。代价是这些缩放可以折叠进前一个 LayerNorm 的 $\gamma$ 参数(数学等价),运行时零开销。这一性质让 SmoothQuant 成为 INT8 服务端推理的事实标准。

5.5 KV Cache 量化(INT8 / FP8)

长上下文场景下 KV Cache 显存占比超过权重。Llama-2-70B 在 32K 上下文、batch=8 时,KV Cache 显存:

$$\text{KV Mem} = 2 \cdot L \cdot s \cdot h \cdot 2 \cdot b = 2 \times 80 \times 32768 \times 8192 \times 2 \times 8 / 10^9 \approx 686 \text{ GB}$$

显然要量化。INT8 KV Cache(per-token + per-head scale)几乎零精度损失;INT4 需要更精心的 group 设计,长上下文可能掉 1-2 分。H100 起原生支持 FP8,是性价比最好的选择(Hopper 架构 FP8 算力比 BF16 快 2×,且无需 zero-point)。

实现要点:

5.6 蒸馏、剪枝与结构化稀疏

5.6.1 蒸馏

知识蒸馏:让小学生模型 $S$ 模仿大教师 $T$ 的输出分布。最经典的 KD loss:

$$\mathcal{L} = \alpha \cdot \text{CE}(y, p_S) + (1 - \alpha) \cdot T^2 \cdot \text{KL}(p_T^{/T} \,\|\, p_S^{/T})$$

$T$ 是温度。LLM 蒸馏的现代变体(MiniLLM, GKD)改用反向 KL 或 on-policy 数据避免 mode-covering 问题。

5.6.2 剪枝

5.6.3 量化-蒸馏-剪枝组合

生产流水线:预训练 → 剪枝(结构化)→ 蒸馏恢复 → INT4 量化 → 部署。Llama-3-8B 经此组合可压到 2.5 GB,跑在手机端。代表项目:Llama.cpp 生态的 Q4_K_M 量化、Apple MLX 框架。

第 六 章
生产部署与服务化

6.1 关键指标:TTFT / TPOT / Throughput

LLM 服务的指标体系:

指标含义影响
TTFT (Time To First Token)从请求到达至吐出第一个 token 的时间用户感知"系统是否还活着",prefill 决定
TPOT (Time Per Output Token)之后每个 token 的平均生成时间用户感知"打字流畅度",decode 决定
ITL (Inter-Token Latency)相邻 token 之间的间隔(含波动)用户感知"卡顿",体现尾延迟
Throughput单位时间处理的 token / 请求数成本与并发能力
Goodput满足 SLO 的 throughput真实可用容量

用户体验阈值经验值:TTFT < 1 秒 体感即时,TPOT 对应阅读速度 > 30 token/s 即流畅(中文每 token 约 1-2 字)。Code / agent 类应用对 TTFT 更敏感。

6.2 SLO 设计与吞吐-延迟权衡

SLO(Service Level Objective)通常以 P95 / P99 表达,比如"P95 TTFT < 500 ms"。在固定硬件下,批大小 (batch size) 是延迟与吞吐的旋钮

$$\text{Throughput} \uparrow, \quad \text{Latency} \uparrow \quad \text{as batch size} \uparrow$$

每张 GPU 找一个最大 batch 使得 P95 TTFT 仍满足 SLO,然后通过加机器扩并发。一个实用的断点估算:当 KV Cache 占据全部可用显存的 90% 时,加 batch 不再提升 throughput(开始抢占重计算),此时即"满 batch"。

常见反模式:

6.3 弹性扩缩容与冷启动

LLM 服务扩缩容比一般 web 服务难得多,原因:

常用模式:

6.4 LLM Gateway 与多模型路由

真实业务通常同时跑十几个模型(不同尺寸、不同微调版本、不同语言),需要一层网关统一接入。核心能力:

代表系统:LiteLLM、Portkey、Anyscale Endpoint。自建可基于 Envoy + 自定义 filter。

6.5 监控、灰度发布与回滚

LLM 服务需要监控的指标远多于传统服务:

类别指标
性能TTFT / TPOT / ITL(P50/P95/P99),throughput, goodput, GPU util, HBM util, KV Cache 占用
容量每个 worker 的 batch size、active sequences、waiting queue depth
错误超时率、OOM、抢占重计算次数、连接重置
业务平均回答 token 数、stop reason 分布、token 成本
质量refusal 率、JSON 格式合规率、A/B 模型 head-to-head 评分

灰度发布的工程模式:

  1. 影子流量(shadow):新模型只读取请求、不返回,对比输出
  2. 按租户灰度:1% 用户 → 5% → 20% → 50% → 100%
  3. 关键样本回放:维护一组 golden prompt(含 jailbreak、边界 case),每次发布前自动跑
  4. 自动回滚触发器:业务错误率、refusal 率、P95 延迟任一指标恶化超 X% 即自动回滚

6.6 成本估算与优化

以 H100(约 $4/小时云租)跑 Llama-3-70B BF16 为例:

$$\text{Cost per 1M tokens} = \frac{N_{\text{GPU}} \cdot \$/\text{hr}}{3600 \cdot \text{throughput}_{\text{tok/s}}} \cdot 10^6$$

4 张 H100 TP=4 部署,throughput ~3000 token/s(混合 prefill/decode),则:

$$\frac{4 \times 4}{3600 \times 3000} \times 10^6 \approx \$1.48 \text{ / 1M tokens}$$

降本的杠杆(按 ROI 从高到低):

  1. INT8/FP8 量化:throughput 1.8~2.5×,几乎无质量损失
  2. continuous batching:相对静态 batch 提升 5-10×(基础设施级,必须做)
  3. Prefix Cache / Prompt Cache:长系统 prompt 跨请求共享,节省 prefill 算力
  4. 投机解码:decode 阶段 2-3×
  5. Prefill/Decode 分离:长 prompt 业务可省 30-50% 成本
  6. 小模型路由:80% 简单请求路给 8B,整体均摊成本下降一个量级
  7. 蒸馏一个专用小模型:业务收敛后训自家小模型,比开源大模型 + prompt 便宜 10×

2024-2025 的趋势:从"上 GPT-4"过渡到"自家蒸馏小模型 + 路由到大模型 fallback"。一个好的 LLM 系统工程师的核心价值,是把每 1000 token 的成本压到业务能承受的水平。