Transformer 是一种完全基于注意力机制(Attention Mechanism)的深度学习架构,由 Vaswani 等人在 2017 年的论文《Attention Is All You Need》中首次提出。其核心设计彻底摒弃了此前 NLP 领域中占主导地位的 RNN 和 CNN 结构,转而采用自注意力(Self-Attention)机制来建模序列中任意两个位置之间的依赖关系。
Transformer 架构经历了三大变体的演进:Encoder-only、Decoder-only 和 Encoder-Decoder。不同的变体适应不同的任务类型,而它们共享的核心模块包括 Embedding Layer、Multi-Head Attention、FFN、残差连接和 LayerNorm。
Encoder-only 架构仅使用 Transformer 的编码器部分,最典型的代表是 BERT(Bidirectional Encoder Representations from Transformers)。编码器由多层堆叠的 Transformer 块组成,每层包含一个双向 Self-Attention 子层和一个 FFN 子层。
双向自注意力
与 Decoder 中的因果注意力不同,Encoder 的 Self-Attention 是双向的:每个 token 可以 attend 到序列中的所有其他 token(包括前后方向)。这允许模型捕捉完整的上下文信息:
Attention(Q, K, V) = softmax(Q K^T / sqrt(d_k)) V这里没有任何因果掩码(causal mask),Attention Score 矩阵是一个完整的 n x n 矩阵,每个位置 i 可以 attend 到所有位置 j ∈ [1, n]。
掩码语言建模(Masked Language Model, MLM)
BERT 的预训练目标是在输入中随机 Mask 掉 15% 的 token,然后让模型预测这些被掩码的原始 token:
输入: [CLS] 我 [MASK] 喜欢 [MASK] 猫 [SEP]
目标: 预测被掩码的位置 → "很", "这"
MLM 的损失函数为:
L_MLM = - sum_{i ∈ M} log P(x_i | x_{masked})其中 M 是被掩码的位置集合。由于每个 token 的预测可以并行计算(不依赖之前位置的输出),Encoder-only 模型的训练效率很高。
架构特性
适用场景
Encoder-only 模型主要用于需要理解而非生成的任务:
| 任务类型 | 具体应用 | 代表模型 |
|---|---|---|
| 文本分类 | 情感分析、垃圾邮件检测 | BERT-base |
| 序列标注 | NER、POS Tagging | BERT-base |
| 语义匹配 | 句子对相似度判断 | RoBERTa |
| 嵌入/检索 | 生成句子/Token 级向量 | BERT/GTE/E5 |
| QA(抽取式) | 从文中定位答案 | BERT-large |
Decoder-only 架构仅使用 Transformer 的解码器部分,是当前大语言模型(GPT、LLaMA、Mistral、DeepSeek)的主流范式。每个 Decoder 块包含一个因果自注意力(Causal Self-Attention)子层和一个 FFN 子层。
因果自注意力
因果自注意力通过因果掩码确保每个位置只能 attend 到自身及之前的 token:
Attention(Q, K, V) = softmax(Q K^T / sqrt(d_k) + M) V其中 M 是下三角掩码矩阵:
M_{i,j} = 0, if j ≤ i
M_{i,j} = -inf, if j > i自回归生成
Decoder-only 模型通过自回归(Autoregressive)方式生成文本:在每一步 t,模型基于已生成的所有 token x_{ 在推理时,KV Cache 机制将之前计算过的 Key 和 Value 缓存起来,使每步 Decode 的计算量从 O(n²) 降至 O(n)。 架构特性 Decoder-only 成为主流的原因P(x) = ∏_{t=1}^T P(x_t | x_{
Encoder-Decoder(也称 Seq2Seq)架构同时包含编码器和解码器,专注于序列到序列的转换任务。一个独立的编码器处理输入序列,产生上下文表示;解码器基于这些表示和之前已生成的 token 自回归地生成输出序列。
交叉注意力(Cross-Attention)
Encoder-Decoder 与 Decoder-only 的核心差异在于交叉注意力。在解码器的每个块中,除了因果自注意力外,还有一个额外的交叉注意力子层,让解码器关注编码器的输出:
CrossAttention(Q_dec, K_enc, V_enc) = softmax(Q_dec K_enc^T / sqrt(d_k)) V_enc完整的 Decoder 块前向流程:
1. x = SelfAttention(CausalMask(x_norm)) + x # 因果自注意力
2. x = CrossAttention(x, EncoderOutput) + x # 交叉注意力
3. x = FFN(x_norm) + x # FFN
架构对比:三种 Attention
| 注意力类型 | Query 来源 | Key/Value 来源 | 掩码 |
|---|---|---|---|
| Encoder Self-Attention | 编码器输入 | 编码器输入 | 无(全双向) |
| Decoder Self-Attention | 解码器输入 | 解码器输入 | 因果掩码 |
| Decoder Cross-Attention | 解码器输入 | 编码器输出 | 无 |
典型模型
| 模型 | 编码器 | 解码器 | 预训练目标 | 发布日期 |
|---|---|---|---|---|
| T5 | Encoder (bi-directional) | Decoder (causal) | Span Corruption | 2019 |
| BART | Encoder (bi-directional) | Decoder (causal) | Denoising AE | 2019 |
| mT5 | Encoder (bi-directional) | Decoder (causal) | Span Corruption | 2020 |
| Flan-T5 | T5 + Instruction Tuning | — | 多任务微调 | 2022 |
T5 的 Span Corruption 目标:随机选择输入中的若干个连续 token 片段,每个片段用一个哨兵 token(如 <extra_id_0>)替代,解码器需要生成这些被掩码的片段。
适用场景
所有 Transformer 变体共享以下四个核心模块:
(1)Embedding Layer
将离散的 token ID 映射到连续向量空间:
Embedding(x) = W_e @ one_hot(x)其中 W_e ∈ R^{V × d_model} 是嵌入矩阵,V 是词汇表大小。Embedding 层的参数占总模型参数的比例随 V 增大而增大,在 V=100K、d_model=4096 时约占 8 亿参数。
Token Embedding + Position Embedding + Segment Embedding(BERT 风格):
input = TokenEmbedding(token_ids)
+ PositionEmbedding(position_ids)
+ SegmentEmbedding(segment_ids) # 可选,仅部分模型使用
Token Embedding + RoPE(LLaMA 风格):位置信息通过 RoPE 注入 Q/K 向量,不作为加法嵌入到输入中。
(2)Multi-Head Attention
将 d_model 维度的输入投影到 h 个独立的"头",每个头在 d_k = d_model / h 维子空间上计算注意力,然后将所有头的结果拼接后投影回 d_model:
head_i = Attention(Q W_i^Q, K W_i^K, V W_i^V)
MultiHead(Q, K, V) = Concat(head_1, ..., head_h) W^O其中 W_i^Q, W_i^K, W_i^V ∈ R^{d_model × d_k}, W^O ∈ R^{h·d_v × d_model}。
vLLM 的 Attention Backend(如 FlashAttention、FlashInfer)在实现中通常将 Q/K/V 的投影融合为单个矩阵乘法以减少内存访问。
(3)Feed-Forward Network(FFN)
FFN 作用于每个位置独立(position-wise),由两个线性变换和一个激活函数组成:
标准 FFN(ReLU/GELU):
FFN(x) = Activation(x W_1 + b_1) W_2 + b_2门控 FFN(SwiGLU/GeGLU):
FFN(x) = [Activation(x W_gate) ⊙ (x W_up)] W_down其中 W_1 ∈ R^{d_model × d_ff}(扩展到 4×),W_2 ∈ R^{d_ff × d_model}(投影回)。门控变体引入第三个权重矩阵 W_gate,通常 d_ff 缩小到约 8/3 × d_model 以保持参数量相近。
(4)残差连接 + LayerNorm
残差连接提供梯度高速公路,使深层网络训练稳定:
Post-Norm: x_{l+1} = LayerNorm(x_l + Sublayer(x_l))
Pre-Norm: x_{l+1} = x_l + Sublayer(LayerNorm(x_l))现代模型几乎全部使用 Pre-Norm 架构。
| 维度 | Encoder-only (BERT) | Decoder-only (GPT) | Encoder-Decoder (T5) |
|---|---|---|---|
| 注意力模式 | 全双向 | 因果(单向) | 双向编码 + 因果解码 |
| 计算复杂度 | O(n²) 训练 | O(n²) 训练 / O(n) 推理 | O(n²) 编码 + O(m²) 解码 |
| 推理方式 | 一次前向 | 自回归逐 token 生成 | 编码一次 + 自回归生成 |
| 预训练目标 | MLM + NSP | Next Token Prediction | Span Corruption / Denoising |
| 训练效率 | 高(可并行预测所有位置) | 中(需要预测每个位置) | 较低(编码器-解码器双组件) |
| 生成能力 | 无(需额外解码头) | 原生支持 | 原生支持 |
| 理解能力 | 极强(双向上下文) | 强 | 很强 |
| 典型参数量 | 110M-340M(BERT) | 7B-671B(GPT/LLaMA) | 220M-11B(T5) |
| 代表模型 | BERT, RoBERTa, DeBERTa | GPT-4, LLaMA-3, DeepSeek-V3, Mistral | T5, BART, mT5, Flan-T5 |
| 在 vLLM 生态角色 | Embedding/Reranker 模型 | 文本生成核心 | 部分翻译/摘要模型 |
| 最佳任务 | 分类、NER、嵌入、检索 | 对话、代码、创作、推理 | 翻译、摘要、格式转换 |
Transformer 的 Self-Attention 具有置换不变性(Permutation Invariance):打乱输入 token 的顺序不会改变注意力输出。然而自然语言是有顺序的,必须向模型中注入位置信息。位置编码的核心目标是让模型知道"token 出现在序列中的哪个位置"。
原始 Transformer(Vaswani et al., 2017)提出使用固定频率的正弦和余弦函数生成位置编码,不需要学习参数:
PE(pos, 2i) = sin(pos / 10000^{2i/d_model})
PE(pos, 2i+1) = cos(pos / 10000^{2i/d_model})其中 pos 是位置索引,i 是维度索引(0 ≤ i < d_model/2)。
核心性质
Sinusoidal 编码直接加到输入 Embedding 上:
input = TokenEmbedding(token_ids) + PositionalEncoding(positions)
BERT 和 GPT 系列使用可学习的 Position Embedding 矩阵 P ∈ R^{max_seq_len × d_model},其中的每一行是一个可训练的参数向量:
input = TokenEmbedding(token_ids) + P[position_ids]
优点:模型可以根据任务数据自动学习最佳的位置表示。缺点:最大序列长度受限于 max_seq_len,超出部分无法处理(需插值或截断)。
RoPE 由 Su 等人在 2021 年提出,被 LLaMA、Mistral、Qwen、DeepSeek 等主流模型采用。与加法式位置编码不同,RoPE 通过旋转 Q/K 向量注入位置信息。
数学推导
对于 d 维度的 Q/K 向量,RoPE 将其分成 d/2 个二维子空间对,每对应用独立的旋转:
R_{Θ,m} = block_diag(R(mθ_1), R(mθ_2), ..., R(mθ_{d/2}))其中每个旋转矩阵为:
R(θ) = [[cos θ, -sin θ],
[sin θ, cos θ]]旋转频率按几何级数递减:
θ_i = 10000^{-2(i-1)/d}, i = 1, 2, ..., d/2对于位置 m 的 Query 向量和位置 n 的 Key 向量:
q_m' = R_{Θ,m} · q_m
k_n' = R_{Θ,n} · k_n相对位置编码的关键性质
旋转后的 Q 和 K 点积只依赖于相对位置差 m - n:
q_m'^T · k_n' = (R_{Θ,m} q_m)^T · (R_{Θ,n} k_n)
= q_m^T · R_{Θ,-m} · R_{Θ,n} · k_n
= q_m^T · R_{Θ,n-m} · k_n由于 R_{Θ,m} 是正交矩阵,R_{Θ,m}^T = R_{Θ,-m},最终结果只与 n - m 有关,绝对位置 m 和 n 被消去。
RoPE 在 Attention 中的融合
在实际实现中,RoPE 在 Q/K 投影之后、Attention Score 计算之前应用:
# 伪代码:RoPE 的核心计算
def apply_rotary(x, cos, sin):
# x: [batch, seq, num_heads, head_dim]
# cos, sin: [seq, head_dim]
x_rotated = x * cos + rotate_half(x) * sin
return x_rotated
# rotate_half: 将 x 的后半部分取负并交换位置
# 即 (x1, x2) → (-x2, x1),等价于旋转 90 度
LLaMA 系列为何使用 RoPE
长上下文扩展技术
| 技术 | 原理 | 效果 |
|---|---|---|
| Position Interpolation (PI) | 位置索引 m 缩放为 m/s | 稳定的 4× 扩展,短距离精度损失 |
| NTK-aware Scaling | 修改 base 频率调整高频分量 | 更好的外推,保持短距离性能 |
| YaRN | 温度缩放 + 频率修改 | 最佳扩展效果,LLaMA-2 已验证 |
| DeepSeek Yarn | 引入 mscale 动态调整温度 | DeepSeek 系列专用 |
ALiBi 由 Press 等人在 2021 年提出,是一种无需学习参数的位置编码方案。与修改 Q/K 向量或添加位置嵌入不同,ALiBi 直接在 Attention Score 上添加一个基于相对距离的线性负偏置:
score(i, j) = (q_i · k_j) / sqrt(d_k) - m_h · |i - j|其中 m_h 是第 h 个注意力头的固定斜率,不经过学习:
m_h = 2^{-h}, h = 1, 2, ..., num_heads不同头使用不同斜率,使不同头关注不同尺度的位置信息(大斜率的头对短距离更敏感)。
与 RoPE 的完整对比
| 特性 | RoPE | ALiBi |
|---|---|---|
| 位置注入方式 | 旋转 Q/K 向量 | 在 Attention Score 上加偏置 |
| 额外参数 | 无 | 无 |
| 外推能力 | 好(需扩展技术) | 极佳(天然支持,可 train short test long) |
| 实现复杂度 | 中等 | 极简(只需加一个偏置矩阵) |
| FlashAttention 集成 | 天然兼容 | 需要在 Kernel 内计算偏置 |
| 短距离建模 | 精细(旋转保留了相对关系) | 粗粒(线性惩罚) |
| 主流采用 | LLaMA, Mistral, Qwen, DeepSeek | BLOOM, MPT |
| 理论优雅性 | 高(旋转正交变换) | 低(启发式偏置) |
| 方法 | 是否可学习 | 是否偏置 | 是否相对 | 外推能力 | 参数量 | 代表模型 |
|---|---|---|---|---|---|---|
| Sinusoidal | 否 | 加性 | 隐含 | 好 | 0 | 原始 Transformer |
| Learned | 是 | 加性 | 否 | 差(需截断) | O(max_seq_len × d) | BERT, GPT-2 |
| RoPE | 否 | 乘性(旋转) | 是 | 好(需扩展) | 0 | LLaMA, Mistral, Qwen |
| ALiBi | 否 | Attention Score | 是 | 极佳 | 0 | BLOOM, MPT |
原始的 Transformer 使用 ReLU 作为 FFN 的激活函数:
ReLU(x) = max(0, x)特性
死亡 ReLU 问题(Dying ReLU)
当某个神经元在训练过程中权重更新后对所有输入都输出负值时,该神经元将永远输出 0,梯度也为 0,从此不再更新。在大模型中,ReLU 的死亡比例可能高达 10-40%,浪费了模型容量。
GELU 是 BERT 等早期 Transformer 模型采用的激活函数,定义为输入与标准正态分布累积分布函数的乘积:
GELU(x) = x · Φ(x)
= x · (1/2) [1 + erf(x / sqrt(2))]其中 Φ(x) 是标准正态分布的 CDF,erf 是误差函数。
实践中的近似计算
由于精确计算 erf 开销较大,使用 tanh 近似:
GELU(x) ≈ 0.5x (1 + tanh[sqrt(2/π) (x + 0.044715x³)])GELU 的优势
Swish / SiLU 定义
Swish(也称 SiLU, Sigmoid Linear Unit)由 Google 在 2017 年提出:
Swish(x) = x · σ(x)其中 σ(x) = 1/(1+e^{-x}) 是 sigmoid 函数。
GLU(Gated Linear Unit)
GLU 由 Dauphin 等在 2017 年提出,核心思想是不再对单一路径应用激活函数,而是通过两个线性投影的逐元素乘法实现门控:
GLU(x) = (x W_1 + b_1) ⊗ σ(x W_2 + b_2)门控路径 σ(x W_2) 控制信息流的通过量。
SwiGLU 的完整定义
SwiGLU 将 GLU 中的 sigmoid 替换为 Swish:
SwiGLU(x) = Swish(x W_gate) ⊗ (x W_up)
= [x W_gate · σ(x W_gate)] ⊗ (x W_up)最终输出再经过下投影:
FFN_swiglu(x) = SwiGLU(x) · W_down其中 W_gate, W_up ∈ R^{d_model × d_ff}, W_down ∈ R^{d_ff × d_model}。
LLaMA 为什么使用 SwiGLU
vLLM 中 SwiGLU 的融合实现:
class SiluAndMul(CustomOp):
"""SwiGLU 的融合实现。
输入 x 被预先拼接为 [gate_proj(x), up_proj(x)],
x[..., :d] 是门控路径,x[..., d:] 是上投影路径。
"""
@staticmethod
def forward_native(x: torch.Tensor) -> torch.Tensor:
d = x.shape[-1] // 2
return F.silu(x[..., :d]) * x[..., d:]
GeGLU 是另一种 GLU 变体,使用 GELU 代替 Swish:
GeGLU(x) = GELU(x W_gate) ⊗ (x W_up)GeGLU 在编码器模型(如 BERT 风格模型)中较为常见,而 SwiGLU 在解码器-only 的 LLM 中更为流行。
ReLU (2017, Transformer)
│
├──→ GELU (2018, BERT/GPT-3)
│ │
│ └──→ GeGLU (2020, T5 v1.1): GELU + 门控
│
└──→ Swish/SiLU (2017)
│
└──→ SwiGLU (2020, LLaMA/PaLM): Swish + 门控
| 属性 | ReLU | GELU | Swish/SiLU | SwiGLU | GeGLU |
|---|---|---|---|---|---|
| 公式 | max(0,x) | x·Φ(x) | x·σ(x) | [x·σ(x)]·up | GELU·up |
| 是否门控 | 否 | 否 | 否 | 是(3 个权重矩阵) | 是(3 个权重矩阵) |
| 计算开销 | O(1) | O(d)(含 erf) | O(d) | O(3d²) | O(3d²) |
| 平滑性 | 非光滑 | 光滑 | 光滑 | 光滑 | 光滑 |
| 负值输出 | 0 | 非零负值 | 非零负值 | 由门控控制 | 由门控控制 |
| 代表模型 | 原始 Transformer | BERT, GPT-3 | — | LLaMA, Mistral, PaLM | T5 v1.1 |
| 训练损失(实验) | 基线 | 低 0.5-1% | 低 0.3-0.5% | 最低 | 与 SwiGLU 接近 |
Layer Normalization(LayerNorm)由 Ba 等人在 2016 年提出,对同一样本的所有特征进行归一化。与 Batch Normalization 对不同样本的同一特征归一化不同,LayerNorm 不受 batch size 影响,特别适合 NLP 中的变长序列。
给定输入 x ∈ R^{d_model},LayerNorm 的计算为:
LayerNorm(x) = γ ⊙ (x - μ) / sqrt(σ² + ε) + β其中:
核心作用
RMSNorm 由 Zhang 和 Sennrich 在 2019 年提出,是 LayerNorm 的简化变体。与 LayerNorm 同时减去均值并除以标准差不同,RMSNorm 仅除以 RMS(均方根),不计算也不减去均值:
RMSNorm(x) = γ ⊙ x / RMS(x)
RMS(x) = sqrt((1/d_model) ∑ x_i² + ε)相比 LayerNorm 的差异
vLLM 中 RMSNorm 的实现:
class RMSNorm(CustomOp):
"""Root mean square normalization."""
def __init__(self, hidden_size: int, eps: float = 1e-6):
self.hidden_size = hidden_size
self.variance_epsilon = eps
self.weight = nn.Parameter(torch.ones(hidden_size))
def forward_native(self, x: torch.Tensor):
return ir.ops.rms_norm(x, self.weight.data, self.variance_epsilon)
Post-norm(后归一化)
原始 Transformer 采用 Post-norm:归一化放在子层之后:
x_{l+1} = LayerNorm(x_l + Attention(x_l))
x_{l+1} = LayerNorm(x_l + FFN(x_l))
问题:训练初期,残差路径 x_l 和子层输出 Attention(x_l) 的尺度可能差异巨大,归一化后的梯度不稳定,需要精心设计的 warmup 策略。
Pre-norm(前归一化)
现代 LLM(LLaMA、GPT-3)普遍采用 Pre-norm:归一化放在子层之前:
x_{l+1} = x_l + Attention(LayerNorm(x_l))
x_{l+1} = x_l + FFN(LayerNorm(x_l))
优势:
潜在缺点:归一化在残差路径之前,深层中各层对最终输出的贡献可能趋于均等,削弱了深层表示的"层次性"。但实践中这一缺点被训练稳定性的大幅提升所抵消。
| 维度 | LayerNorm | RMSNorm | Post-norm | Pre-norm |
|---|---|---|---|---|
| 归一化方式 | (x-μ)/σ | x/RMS(x) | 子层后归一化 | 子层前归一化 |
| 统计量计算 | 均值 + 方差 | 均方根 | 同 LayerNorm/RMSNorm | 同 LayerNorm/RMSNorm |
| 可学习参数 | γ, β(2个) | γ(1个) | 取决于使用 LN 或 RMS | 取决于使用 LN 或 RMS |
| 计算开销 | O(2d) | O(d) | 与归一化方法相同 | 与归一化方法相同 |
| 训练稳定性 | 稳定 | 稳定 | 较差(需 warmup) | 稳定(无需 warmup) |
| 代表模型 | BERT, T5 | LLaMA, Mistral, Qwen | 原始 Transformer | GPT-3, LLaMA, DeepSeek |
| 实现复杂度 | 标准 | 简化 | 标准 | 标准 |
MoE(混合专家模型)是一种神经网络架构范式,核心思想是条件计算(Conditional Computation):不是为每个输入激活全部参数,而是根据输入内容动态选择并激活一部分"专家"子网络。MoE 概念最早由 Jacobs 等人在 1991 年提出,在 LLM 时代由 DeepSeek、Mixtral 等模型发扬光大。
MoE 的核心优势:
在标准 Transformer 中,FFN 层是密集的(所有参数参与计算)。在 Sparse MoE 中,FFN 被替换为 N 个并行的专家网络 E₁, ..., E_N,每个专家是一个小型 FFN。
输入 Token x
│
v
[Router/Gating Network] → 计算每个专家的分数
│
v
[Top-K Selection] ← 选择分数最高的 K 个专家
│
v
[E₁] [E₂] ... [Eₙ] (N 个专家 FFN,大部分不激活)
│ │ │
v v v
[Weighted Sum] = Σ g_i · E_i(x) 对选中的 K 个专家加权求和
│
v
输出
路由网络是 MoE 的核心组件,负责决定每个 token 应该分配给哪些专家:
h(x) = x · W_g + b_g # 线性投影到 N 维
g_i(x) = softmax(h(x))_i # Softmax 归一化其中 W_g ∈ R^{d_model × N}, N 是专家数量。
对于每个 token,选择门控值最高的 K 个专家:
𝒯(x) = TopK({g₁(x), ..., g_N(x)}, K)对选中的专家门控值重新归一化:
g'_i(x) = g_i(x) / Σ_{j∈𝒯(x)} g_j(x), for i ∈ 𝒯(x)最终输出为选中专家输出的加权和:
y = Σ_{i∈𝒯(x)} g'_i(x) · E_i(x)Top-1 vs Top-K 对比:
| 属性 | Top-1 (K=1) | Top-K (K=2/4) |
|---|---|---|
| 实现复杂度 | 简单 | 中等 |
| 表达力 | 受限(仅一个专家) | 强(多专家融合) |
| 负载均衡 | 困难(专家竞争激烈) | 更容易 |
| 通信开销 | 低 | 高(K 越大越高) |
| 典型使用 | 早期 MoE | Mixtral 8x7B (K=2), DeepSeek-V3 (K=8) |
负载不均衡问题
如果没有约束,路由网络倾向于将所有 token 分配给少数"受欢迎"的专家,导致:
辅助损失函数
Importance Loss(重要性损失):鼓励每个专家接收相似的总门控值:
L_importance = N · Σ_{i=1}^N (1/B · Σ_{x∈batch} g_i(x))²Load Loss(负载损失):鼓励每个专家处理相似数量的 token:
L_load = N · Σ_{i=1}^N (1/B · Σ_{x∈batch} 𝟙[i ∈ TopK(x)])²总损失:L_total = L_task + α · L_aux,α 通常取 0.01。
核心思想
由 Google 在 2022 年提出,反转路由方向:让专家选择 token,而非 token 选择专家。
数学描述
对于专家 i,从 batch 中选择 token 集合:
𝒮_i = TopC({g_i(x₁), ..., g_i(x_B)}, C)其中 C 是每个专家的容量(capacity)。
优缺点
| 属性 | Token-Choice | Expert-Choice |
|---|---|---|
| 负载均衡 | 需辅助损失 + Capacity Factor | 天然完美均衡 |
| Token Dropping | 可能(超容量时丢弃) | 可能(未被任何专家选中时) |
| 实现复杂度 | 较低 | 较高 |
| 通信模式 | 不可预测 | 可预测(固定大小) |
| 典型使用 | Mixtral, DeepSeek | 部分 Google 研究模型 |
共享专家 + 路由专家的混合设计
DeepSeek-V3(671B 总参数,37B 活跃参数)采用了创新的 MoE 设计:
这种设计保证了基础语言能力的稳定性(共享专家),同时保留了多样化的语义模式学习(路由专家)。
无辅助损失的负载均衡
DeepSeek-V3 提出了无需辅助损失的动态负载均衡方法:
MLA(Multi-Head Latent Attention)+ MoE 组合
DeepSeek 的另一创新是将 MLA 与 MoE 结合。MLA 通过低秩压缩降低 KV Cache 存储量:
c_t^KV = W_DKV · h_t # 压缩到低维潜在空间
k_t^h = W_UK_h · c_t^KV, v_t^h = W_UV_h · c_t^KV # 解压缩到每个头推理时只缓存 c_t^KV(低维),而非完整的 K 和 V,大幅减少显存占用。
| 挑战 | 原因 | vLLM 解决方案 |
|---|---|---|
| 显存占用增加 | 需要加载所有专家参数 | Expert Parallelism(EP)将专家分布到不同 GPU |
| 通信开销 | All-to-all 通信传输中间激活 | Fused MoE Kernel 减少通信次数 |
| 负载不均衡 | 某些 GPU 上专家过载 | EPLB(Expert Parallel Load Balancing) |
| Kernel 效率低 | 稀疏激活模式利用率低于密集 GEMM | Fused MoE CUDA Kernel,Monolithic/Modular 实现 |
在 vLLM 中,MoE 通过 vllm/model_executor/layers/fused_moe/ 目录下的融合 Kernel 实现,支持 Monolithic 和 Modular 两种执行策略。
| 模型 | 架构 | 总参数量 | 活跃参数量 | 推理 FLOPs/token |
|---|---|---|---|---|
| LLaMA-2 70B | Dense | 70B | 70B | ~140B |
| Mixtral 8x7B | MoE (8 experts, Top-2) | 47B | ~13B | ~26B |
| Mixtral 8x22B | MoE (8 experts, Top-2) | 141B | ~39B | ~78B |
| DeepSeek-V2 | MoE | 236B | 21B | ~42B |
| DeepSeek-V3 | MoE (256 experts, Top-8) | 671B | 37B | ~74B |
MoE 以与密集模型相当的推理 FLOPs 实现了更大的总参数量,这意味着更高的知识容量和更强的模型能力。
State Space Model(SSM,状态空间模型)源于控制工程,用于描述动态系统。在深度学习领域,SSM 被重新引入作为 Transformer 的替代架构,解决 O(n²) 计算复杂度在超长序列上的瓶颈问题。
Mamba 由 Gu 和 Dao 在 2023 年提出,通过选择性状态空间(Selective State Space)在保持线性 O(n) 复杂度的同时实现与 Transformer 相媲美的建模能力。Mamba-2(2024)通过状态空间对偶性(SSD)统一了 SSM 和 Attention 的理论框架。
连续时间状态空间模型
经典的连续 SSM 由两个方程定义:
h'(t) = A · h(t) + B · x(t) # 状态方程
y(t) = C · h(t) + D · x(t) # 输出方程其中:
离散化(Zero-Order Hold)
使用零阶保持(ZOH)将连续 SSM 离散化:
h_k = bar_A · h_{k-1} + bar_B · x_k
y_k = C · h_k
bar_A = exp(Δ · A)
bar_B = (ΔA)^{-1}(exp(ΔA) - I) · ΔBHiPPO 初始化
S4 使用 HiPPO(High-order Polynomial Projection Operators)理论初始化 A 矩阵,使隐藏状态编码输入历史的压缩表示。HiPPO 矩阵是特定下三角矩阵,其特征值具有负实部,确保系统稳定性。
S4 的三种等价计算模式
| 模式 | 公式 | 复杂度 | 用途 |
|---|---|---|---|
| 循环模式(Recurrent) | h_k = bar_A h_{k-1} + bar_B x_k | O(nN) | 推理(高效,固定状态) |
| 卷积模式(Convolutional) | y = K * x, K = (C·B, C·Ā·B, ...) | O(n log n) | 训练(并行) |
| 连续模式(Continuous) | 保持连续参数,按需离散化 | — | 非均匀采样 |
这种三模式等价性是 S4 的理论基石:训练用卷积(并行),推理用循环(高效)。
LTI 的局限
S4 是线性时不变(LTI)系统:A, B, C 对所有时间步固定。这导致 SSM 无法根据内容选择性记忆或遗忘——在"选择性复制"和"归纳头"等合成任务上,LTI SSM 表现远逊于 Transformer。
选择性机制(S6)
Mamba 的核心创新:让参数 B, C 和步长 Δ 依赖于输入 x:
Δ_k = softplus(Linear_Δ(x_k))
B_k = Linear_B(x_k)
C_k = Linear_C(x_k)然后使用动态参数离散化和状态更新:
bar_A_k = exp(Δ_k · A)
bar_B_k = Δ_k · B_k
h_k = bar_A_k ⊙ h_{k-1} + bar_B_k · x_k
y_k = C_k · h_k关键变化:
硬件感知的并行扫描
选择性 SSM 打破了 LTI 假设(无法使用卷积模式),Mamba 的第二个贡献是硬件感知的并行扫描算法:
核心发现
Mamba-2 发现:SSM 和 Attention 之间存在深刻的数学对偶性。
对于标量结构化 SSM(A_t 是标量),序列变换等价于:
SSM 形式(循环):
h_t = a_t h_{t-1} + b_t x_t, y_t = c_t · h_tAttention 形式(矩阵乘法):
y = (L ⊙ C · B^T) · x其中 L 是下三角矩阵(元素为衰减因子的累积乘积)。这种形式与因果线性注意力几乎相同:
Y = (L ⊙ Q · K^T) · V将 (C, B, X) 映射为 (Q, K, V),两者完全等价。
Mamba-1 vs Mamba-2
| 特性 | Mamba-1 (S6) | Mamba-2 (SSD) |
|---|---|---|
| A 结构 | 对角矩阵(每维度独立) | 标量乘单位阵(所有维度共享) |
| 头维度 | P=1(每通道独立 SSM) | P>1(类似 MHA,如 64/128) |
| 状态维度 N | 较小(通常 16) | 较大(64-256) |
| 训练方式 | 并行扫描 | 块分解(混合 SSM + Attention) |
| 训练速度 | 较慢(非 GEMM 友好) | 快(大量矩阵乘法) |
| 推理速度 | 快 | 快 |
SSD 块分解算法
Mamba-2 的 SSD 算法结合 SSM 和 Attention 的优点:
| 维度 | Transformer Attention | Mamba/SSM |
|---|---|---|
| 训练时间复杂度 | O(n²d) | O(ndN) |
| 推理时间复杂度(每步) | O(nd)(KV Cache) | O(dN)(固定) |
| 训练空间复杂度 | O(n²)(注意力矩阵) | O(nN) |
| 推理空间复杂度 | O(nd)(线性增长) | O(Nd)(固定) |
| 序列长度扩展性 | 二次增长,受限 | 线性增长,可扩展 |
| 短序列(n<2K)效率 | 高(高度优化) | 中 |
| 超长序列(n>128K) | 不可行 | 可行 |
| 生态成熟度 | 极高 | 发展中 |
| 本质属性 | Attention | SSM (Mamba) |
|---|---|---|
| 建模方式 | 内容寻址(content-based addressing) | 状态压缩(state compression) |
| 记忆机制 | 显式存储所有历史(KV Cache 线性增长) | 隐式压缩到固定状态(状态大小恒定) |
| 信息检索 | 精确匹配(softmax 后权重显式) | 压缩重建(从状态中提取) |
| 上下文窗口 | 理论上无限制,但受内存限制 | 理论上无限制,状态固定 |
| 信息损失 | 无(保留全部历史) | 有(压缩到有限状态有信息损失) |
| 硬件友好性 | 低(内存带宽瓶颈在长序列时严重) | 高(状态小,读带宽需求低) |
| 并行度 | 序列维度完全并行 | 序列维度需扫描(但可并行化) |
本质差异的核心是:Attention 不压缩任何信息(使用所有历史 token 的精确表示),而 SSM 将历史压缩到固定大小的状态中。这使 SSM 具有线性的时间和空间复杂度,但代价是信息压缩带来的表达精度损失。选择性机制(S6)通过让模型自行决定压缩哪些信息来弥补这一缺陷。
Tokenization 是将原始文本转换为模型可处理的数值表示(token IDs)的过程。它是 LLM 流水线的第一步,直接影响模型的词汇表大小、序列长度、多语言能力和上下文窗口利用率。
训练算法
BPE 从字符/字节级开始,迭代合并最频繁的相邻 token 对,逐步构建子词词汇表:
编码(推理时)
按合并规则优先级(先学到的优先级高)从字节序列自底向上合并:
def encode(self, text):
tokens = list(bytearray(text, "utf-8"))
symbols = [self.vocab[id_num] for id_num in tokens]
while True:
pairs = zip(symbols, symbols[1:])
# 找到优先级最高的 pair
bigram = min(pairs, key=lambda p: self.bpe_ranks.get(p, inf))
if bigram not in self.bpe_ranks:
break
# 合并所有出现
symbols = merge(symbols, bigram)
return [self.inverse_vocab[sym] for sym in symbols]
特点
SentencePiece 是 Google 开发的分词库,将空格视为普通字符(用 ▁ U+2581 表示),因此:
Unigram Language Model 模式
Unigram 算法的核心思路:从大型初始子词集合出发,迭代删除对似然贡献最小的子词。
训练(EM 算法):
编码:使用维特比算法(Viterbi)找到概率最高的分割路径。
BBPE 从字节级而非字符级开始。由于 UTF-8 中任何字符最多由 4 个字节表示,初始词汇表固定为 256 个字节值,完全与语言无关。
英文 "hello" → UTF-8 字节: [104, 101, 108, 108, 111]
中文 "你" → UTF-8 字节: [228, 189, 160]
优势与劣势
| 特性 | 标准 BPE(字符级) | BBPE(字节级) |
|---|---|---|
| 初始词汇表 | 语言相关(数万 Unicode 字符) | 固定 256 字节 |
| 语言无关性 | 否 | 是 |
| OOV(词表外) | 有 | 无(任何 UTF-8 文本可编码) |
| 序列长度 | 较短 | 对非拉丁语言较长 |
| 代表模型 | 早期 NMT 模型 | GPT-2/3/4, LLaMA-3 |
tiktoken 是 OpenAI 开发的高性能 BPE tokenizer,使用 Rust 实现核心算法:
import tiktoken
encoding = tiktoken.get_encoding("cl100k_base") # GPT-4 tokenizer
tokens = encoding.encode("Hello world!")
# tokens: [9906, 1917, 0]
核心优化:Rust 的快速哈希表 + 正则表达式预处理将文本分成可合并的块,实现高效批量编码。
| 特殊 Token | 作用 | 使用模型 |
|---|---|---|
<s> / [BOS] | 标记序列开始 | LLaMA, BERT |
</s> / [EOS] | 标记序列结束,触发停止生成 | LLaMA, GPT |
| [PAD] | 填充变长序列到固定长度 | BERT, T5 |
| [MASK] | 掩码语言建模中的被预测位置 | BERT 系列 |
| [UNK] | 未知字符(BBPE 中不需要) | 传统 tokenizer |
<|im_start|> / <|im_end|> | 对话角色标记 | Qwen |
| [INST] / [/INST] | 指令标记 | LLaMA-2 Chat |
<|endoftext|> | 序列分隔 | GPT 系列 |
| 词汇表大小 | 嵌入参数量(d=4096) | 序列长度效率 | 多语言公平性 | 代表模型 |
|---|---|---|---|---|
| 32,000 | ~2.6 亿 | 较短 | 差(非拉丁语言 token 数多) | LLaMA-2 |
| 50,257 | ~4.1 亿 | 中等 | 中等 | GPT-2, GPT-3 |
| 100,256 | ~8.2 亿 | 较高效 | 较好 | GPT-4 (cl100k_base) |
| 128,256 | ~10.5 亿 | 高效 | 较好 | LLaMA-3 |
| 151,936 | ~12.4 亿 | 高效 | 中文优化 | Qwen-2 |
| 199,997 | ~16.4 亿 | 最高效 | 优秀 | GPT-4o (o200k_base) |
趋势:新一代模型倾向于更大的词汇表(100K+),以支持更多语言和更高效的编码(减少每个词的 token 数)。
| 维度 | BPE | Unigram | BBPE |
|---|---|---|---|
| 训练方向 | 从小到大(合并) | 从大到小(删除) | 同 BPE |
| 编码方式 | 贪婪合并 | Viterbi 最优路径 | 同 BPE |
| 基础单元 | 字符 | 字符 | 字节 |
| 空格处理 | 需预处理 | 原生支持 | 需预处理 |
| 语言无关性 | 差 | 中等 | 极好 |
| 多语言性能 | 差 | 好 | 好 |
| 典型模型 | GPT 系列 (via tiktoken) | T5, LLaMA-2 | GPT-2/3/4, LLaMA-3 |
定位:高吞吐 LLM 推理引擎,行业事实标准。
核心创新:
优势:社区最活跃(GitHub 50K+ stars)、支持模型最广泛(HuggingFace 生态)、多 GPU 扩展性好(TP/PP/EP)、支持量化(FP8/INT4/AWQ/GPTQ)、V1 架构重构后性能大幅提升。
定位:HuggingFace 生态的 LLM 推理服务器。
核心特性:
与 vLLM 对比:
| 维度 | TGI | vLLM |
|---|---|---|
| 核心创新 | HuggingFace 生态集成 | PagedAttention |
| 易用性 | 高(HF 生态无缝) | 中等 |
| 吞吐量 | 高 | 更高 |
| 多模态 | 较好 | 中等 |
| 部署方式 | Docker 为主 | Python 库 / 服务 |
定位:NVIDIA 官方 LLM 推理优化框架,在 NVIDIA GPU 上榨取最大性能。
核心优化:
优势与局限:
| 优势 | 局限 |
|---|---|
| 极致性能(NVIDIA GPU 最高吞吐) | 仅支持 NVIDIA GPU |
| 生产级稳定性 | 编译时间长(数分钟到数小时) |
| Triton Inference Server 无缝集成 | 灵活性低(新模型需写 Plugin) |
| Hopper FP8 Transformer Engine 原生支持 | 部分组件闭源 |
定位:结构化 LLM 推理框架,引入编程语言概念控制生成过程。
核心创新:
与 vLLM 对比:
| 维度 | SGLang | vLLM |
|---|---|---|
| 核心创新 | RadixAttention + Structured Generation DSL | PagedAttention |
| 编程模型 | 结构化编程语言 | 传统 API |
| 前缀复用 | 自动、高效(Radix Tree) | 需显式开启 |
| 多轮对话 | 原生优化 | 支持 |
| 结构化输出 | 原生支持 | 通过外部工具 |
| 社区规模 | 较小(增长迅速) | 行业最大 |
定位:纯 C/C++ LLM 推理实现,不依赖 PyTorch/CUDA。
核心特性:
常用 GGUF 量化级别:
| 量化类型 | 每权重位数 | 7B 模型大小 | 质量损失 |
|---|---|---|---|
| F16 | 16 | 13 GB | 无 |
| Q8_0 | 8 | 6.7 GB | 极小 |
| Q5_K_M | 5.5 | 4.5 GB | 小 |
| Q4_K_M | 4.5 | 3.8 GB | 中等 |
| Q3_K_M | 3.5 | 3.0 GB | 明显 |
| Q2_K | 2.5 | 2.2 GB | 显著 |
| 引擎 | 最佳场景 | 吞吐量 | 延迟 | 易用性 | 硬件支持 | 社区活跃度 | 是否开源 |
|---|---|---|---|---|---|---|---|
| vLLM | 高吞吐生产服务、多租户 | 极高 | 低 | 中 | NVIDIA/AMD/Intel/XPU | 最活跃 (50K+ ⭐) | 完全开源 |
| TGI | HuggingFace 生态集成 | 高 | 低 | 高 | NVIDIA/Intel | 活跃 | 开源 |
| TensorRT-LLM | NVIDIA GPU 极致性能 | 最高 | 最低 | 低 | NVIDIA only | 高 (NVIDIA 维护) | 部分开源 |
| SGLang | 多轮对话、结构化生成 | 高 | 低 | 中 | NVIDIA/AMD | 增长迅速 | 开源 |
| llama.cpp | 本地/边缘推理、CPU | 低 | 高 | 高 | CPU/GPU/Metal/Vulkan | 极活跃 | 开源 |
| 需求场景 | 推荐引擎 | 理由 |
|---|---|---|
| 生产环境高吞吐 API 服务 | vLLM | 社区最活跃,PagedAttention 内存效率最高,支持模型最广 |
| NVIDIA GPU 极致性能 | TensorRT-LLM | Kernel Fusion + FP8 + Inflight Batching 组合性能最优 |
| 快速原型、HF 生态 | TGI | 一键 docker 部署,与 HF Hub 无缝集成 |
| 多轮对话 / Agent 系统 | SGLang | RadixAttention 自动前缀复用,结构化生成原生支持 |
| 本地隐私推理 / 边缘设备 | llama.cpp | CPU/手机均可运行,GGUF 量化灵活,数据不出本地 |
| AMD / Intel / 国产 GPU | vLLM | 硬件支持最广泛,社区驱动适配 |
| 需要 JSON / 结构化输出 | SGLang / vLLM+Outlines | SGLang 原生支持,vLLM 通过 Guidance/Outlines 实现 |
| 学术研究 / 快速实验 | vLLM / llama.cpp | vLLM Python API 灵活,llama.cpp 无需 GPU |
graph TD
T[Transformer 架构] --> PE[位置编码: RoPE/ALiBi]
T --> AF[激活函数: GELU/SwiGLU]
T --> NM[归一化: LayerNorm/RMSNorm]
NM --> PN[Pre-norm/Post-norm]
MoE[MoE 混合专家模型] --> T
MoE --> NM
MoE --> AF
MoE --> TK[Tokenization]
SSM[SSM/Mamba] --> T
TK --> ALL[所有模型的前置条件]
IE[推理引擎] --> T
IE --> PE
IE --> AF
IE --> NM
IE --> MoE
IE --> SSM
IE --> TK
本模块共覆盖 8 个大节、40+ 个核心概念,与 vLLM 推理优化相关的底层 AI 基础知识至此全部接入。