
自然语言处理(九):大语言模型架构深度解析
拆解现代 LLM 的内部结构:Pre-norm + RMSNorm + SwiGLU + RoPE + GQA、KV Cache 机制、FlashAttention 的 IO 调度、稀疏 MoE,以及 INT8/INT4 量化。
2017 年的 Transformer 论文提出了一种模块,如今所有生产环境中的大语言模型(LLM)依然沿用其整体框架,但内部几乎所有组件都经历了彻底替换:后置归一化(post-norm)被前置归一化(pre-norm)取代,LayerNorm 被 RMSNorm 替换,GELU 激活函数变成了 SwiGLU,正弦位置编码也被旋转位置编码(RoPE)所替代。多头注意力机制(Multi-head Attention)演进为分组查询注意力(Grouped-Query Attention, GQA),稠密前馈网络(FFN)在某些模型中甚至被稀疏专家混合模型(Mixture of Experts, MoE)所取代;更重要的是,推理过程中最核心的数据结构——KV 缓存(KV Cache)——在原始论文中完全没有提及。
本文将按照这些改动在模型实现、训练和部署时的实际重要性顺序展开讲解:从现代解码器模块入手,介绍支撑长上下文的关键数据结构——KV 缓存;探讨位置信息编码(如 RoPE 和 ALiBi),以及通过注意力布局优化(如 GQA 和 MQA)来降低缓存开销;分析使注意力计算更快的 IO 优化内核(FlashAttention);最后讨论如何在不增加每 token 计算量的情况下扩展模型规模(MoE),或在不损失精度的前提下压缩模型(量化)。

你将学到什么#

- 现代模块设计:为什么 pre-norm、RMSNorm、SwiGLU、RoPE 和 GQA 成为主流选择,每一项改进背后的原因是什么。
- KV Cache 工作原理:如何通过优化将注意力计算的复杂度从 $O(n^2)$ 降低到 $O(n)$ 的摊销成本,以及这种优化对内存占用的具体影响。
- 位置编码方法: sinusoidal、RoPE 和 ALiBi 这三种技术如何分别回答“当前 token 的位置在哪里”这个问题。
- 注意力机制的变体: MHA、MQA 和 GQA 在头部多样性与缓存大小之间的权衡,结合一个 70B 参数量级的模型,用实际数据说明它们的差异。
- FlashAttention 算法:一种高效的注意力实现方式,通过 IO 感知调度策略,将数据块驻留在 SRAM 中,从而避免显式生成 $n \times n$ 的分数矩阵。
- MoE (混合专家模型):利用稀疏 top-$k$ 路由,在不增加每个 token 计算量(FLOPs)的情况下扩展模型的总参数规模。
- 量化技术:从 FP16 到 INT8 再到 INT4,使用 GPTQ 和 AWQ 方法进行模型压缩时,精度和显存的实际表现如何。
前置知识#
- 对基础的 Transformer 模块有一定了解(具体可参考 第四篇 — 注意力机制与 Transformer )。
- 熟悉预训练模型的核心概念(更多内容见 第五篇 — BERT 与预训练模型 )。
- 能够流畅阅读 PyTorch 代码,并具备基本的线性代数知识。
三大家族: encoder-only、 decoder-only、 encoder-decoder#
在深入探讨现代架构之前,不妨先思考一下,为什么几乎所有通用的大语言模型(LLM)最终都选择了仅解码器的架构。其实,这三种架构的核心区别就在于注意力掩码的设计:
| 家族 | 掩码类型 | 预训练目标 | 擅长领域 | 示例 |
|---|---|---|---|---|
| 仅编码器 | 双向 | 掩码语言模型(MLM) | 语义理解 | BERT、 RoBERTa、 DeBERTa |
| 仅解码器 | 因果(下三角) | 下一词预测(LM) | 文本生成、上下文学习 | GPT、 LLaMA、 Qwen、 Mistral |
| 编码器-解码器 | 双向编码器 + 因果解码器 + 跨注意力 | 去噪 / Span Corruption | 序列到序列任务 | T5、 BART、 FLAN-T5 |
| |
仅解码器架构之所以能在规模化竞赛中脱颖而出,主要有两个原因:几乎所有任务都可以转化为“预测下一个词”的问题,这种单一的目标和统一的数据格式让扩展变得非常高效且清晰;其次,因果掩码使得前缀缓存(KV Cache)的实现成本极低——相比之下,编码器-解码器架构还需要额外缓存跨注意力机制,而仅编码器架构则完全无法独立完成生成任务。如今,提到“LLM”,几乎默认指的就是后面会提到改进版的仅解码器模型。
现代 decoder block#

LLaMA 风格的模块(如 LLaMA、LLaMA-2、Mistral、Qwen、Yi、DeepSeek 等)与 2017 年的经典 Transformer 模块相比,主要在五个方面进行了改进。虽然每个改动单独来看影响有限,但它们共同作用,使得模型在训练时更加稳定,无需学习率预热(warmup)调参,能够更好地扩展到更长的上下文,并且推理速度更快。
1. 前置归一化(Pre-norm)取代后置归一化(Post-norm)。
原始设计是先进行残差加和,再对结果进行归一化(x + Sublayer(x) 后 norm),而现代设计则是在进入子层之前先进行归一化(x + Sublayer(Norm(x)))。前置归一化保留了残差路径的恒等映射特性,这在深层网络中能有效保持梯度尺度的稳定性,同时避免了 Transformer 中常见的学习率 warmup 需求。
这种简化不仅每层减少了一次归约操作和一组参数,而且在实际效果上几乎没有损失。
$$\mathrm{SwiGLU}(x) = \big(\mathrm{Swish}(W_1 x) \odot (W_3 x)\big) W_2.$$逐元素乘法为 FFN 引入了乘性交互机制,在相同参数量下,困惑度通常能降低 1–2%。为了控制参数预算,隐藏层维度被压缩了 $2/3$ 。
4. RoPE 取代可学习绝对位置编码。
不再将位置信息直接加到嵌入向量中,而是在注意力计算时通过对 Q 和 K 向量进行旋转来注入位置信息,具体细节将在下一节展开。
5. GQA / MQA 取代 MHA。
部分 query 头共享同一个 KV 头,具体内容将在注意力变体部分详细讨论。
| |
KV Cache:为长上下文买单的数据结构#

在自回归解码中,每次生成一个新 token。如果直接计算注意力,新位置需要依赖之前所有 token 的 K 和 V 值。如果每次都重新计算这些投影,每一步的复杂度是 $O(n)$ ,总的复杂度会达到 $O(n^2)$ 。而 KV Cache 的设计巧妙地解决了这个问题:既然这些投影是由过去的 token 决定的确定性函数,那只需要算一次并保存下来即可。
KV Cache 能够奏效的关键在于两点:
- 模型是因果的,这意味着已经写入 cache 的内容不会因为后续 token 的到来而改变。
- K 和 V 的投影是对输入的线性变换,因此缓存投影后的张量与重新计算的结果在数学上是完全等价的。
| |
对于长度为 32K 的上下文,仅 KV Cache 就需要占用 84 GB 显存——甚至超过了模型权重本身的大小。正是这一巨大的压力催生了 GQA、 MQA 以及 PagedAttention (vLLM)等优化方案。
位置编码: sinusoidal、 RoPE、 ALiBi#

自注意力机制天生对顺序没有感知能力:输入的顺序打乱,输出也会随之改变。为了解决这个问题,目前主流的三种方法分别在不同的环节注入位置信息。
Sinusoidal 绝对位置编码(Vaswani 等, 2017)。 在输入层将一个固定的 $\sin/\cos$ 向量直接叠加到 token 的 embedding 上。由于位置信息需要通过每一层的线性变换传递,这种方法在训练分布内的表现尚可,但一旦超出训练长度,外推能力就显得捉襟见肘。
$$\langle R_m q,\; R_n k \rangle = \langle q,\; R_{n-m} k \rangle,$$这表明点积结果仅依赖于相对偏移 $n - m$ 。正因如此, RoPE 能够处理比训练长度更长的上下文,也因此成为所有现代模型(如 LLaMA、 Qwen、 Mistral、 Yi、 DeepSeek、 GPT-NeoX)的首选方案。
| |
ALiBi — 带线性偏置的注意力机制(Press 等, 2021)。 完全摒弃了传统的位置编码方式,而是在 softmax 前的分数上添加一个按头不同的线性惩罚项 $-m_h \cdot |i - j|$ 。其中,$m_h$ 较小的头倾向于关注全局信息,而 $m_h$ 较大的头则聚焦于局部信息。在原论文中, ALiBi 的外推能力优于 RoPE,但由于缺乏相对相位信息,在知识密集型的长上下文任务中通常表现不如 RoPE。 BLOOM 和 MPT 是采用该方法的典型代表。
在实际工程中, RoPE 结合 NTK-aware scaling、 YaRN 和 position interpolation 等技术手段,可以让训练长度为 4K 的模型通过少量微调扩展到 32K–128K,这已经成为当前处理长上下文任务的主流方法。
注意力变种: MHA → GQA → MQA#

标准多头注意力(MHA)为每个查询头(query head)分别维护独立的键(K)和值(V)投影。 KV 缓存的开销与 KV 头的数量直接相关,这也是前面提到的 84 GB 内存占用的主要来源,尤其是在处理长上下文时。为了优化内存使用,研究者提出了两种折中方案:
- MQA — 多查询注意力(Shazeer, 2019): 所有查询头共享一个键值头(KV head)。这种方式让 KV 缓存的大小缩小了 $H$ 倍,但由于键值投影失去了多样性,在复杂任务上的性能会有明显下降。
- GQA — 分组查询注意力(Ainslie 等, 2023): 这是 LLaMA-2-70B、 Mistral 以及大多数最新模型采用的折中方案。它将 $H_q$ 个查询头分成 $G$ 组,每组共享一个键值头。以 LLaMA-2-70B 为例,当 $H_q = 64$ 且 $G = 8$ 时, KV 缓存缩小了 8 倍,但性能几乎与 MHA 持平。
| |
LLaMA-2-70B 参数下的具体数据(fp16,每 token):
- MHA, 64 个 KV 头 → 每 token 占用 2.56 MB → 在 32K 上下文时需要 80 GB;
- GQA-8, 8 个 KV 头 → 每 token 占用 0.32 MB → 在 32K 上下文时需要 10 GB;
- MQA, 1 个 KV 头 → 每 token 占用 0.04 MB → 在 32K 上下文时需要 1.25 GB。
GQA-8 几乎实现了 MQA 的全部内存节省优势,同时性能几乎没有损失。正因如此,近期的开源权重模型几乎都默认采用了这一方案。
FlashAttention:数学不变,调度优化#

传统的注意力核函数会先计算 $S = QK^\top$ ,然后将完整的 $n \times n$ 分数矩阵存储到 HBM (GPU 主显存)中,在 HBM 上执行 softmax 操作,最后再与 $V$ 相乘。以 $n=8192$ 、 fp16 精度为例,单是 $S$ 矩阵每个注意力头每层就占用 128 MB 显存,而这些数据在计算过程中会被反复读写,导致大量带宽被浪费。
FlashAttention (Dao 等, 2022)采用相同的数学公式,但通过优化调度方式显著提升了效率:
- 将 $Q$ 、$K$ 、$V$ 切分为适合片上 SRAM 的小块(tile),确保它们能装入 A100/H100 每个 SM 中约 192 KB 的 SRAM。
- 每次只在 SRAM 中计算一个 $S$ 小块。
- 使用在线 softmax 技巧:动态维护最大值 $m$ 和分母 $\ell$ ,使得每个小块可以直接更新部分输出,而无需加载整行数据。
- 最终结果 $O$ 直接写回 HBM,完整的 $S$ 始终不会出现在显存中。
最终效果是数学上完全一致的注意力计算(仅浮点运算顺序可能略有不同),但 HBM 数据流量从 $O(n^2)$ 降至 $O(n)$ 。当 $n \geq 2048$ 时,实际运行速度提升 2–4 倍,显存占用最多减少 8 倍。 FlashAttention-2 进一步优化了 warp 级别的任务分配,性能达到 A100 FP16 峰值的约 70%。
| |
总结一下, FlashAttention 并未改变模型的计算内容,只是调整了 GPU 上的操作顺序。对于序列长度超过 1K 的场景,务必启用它以获得最佳性能。
混合专家:容量提升,计算量不增#

每 token 的计算复杂度与 $k$ 成正比(通常 $k=2$ ),而不是与专家总数 $N$ 相关。因此,一个包含 8 个专家的模型,其 FFN 参数量大约是稠密模型的 8 倍,但计算量仅增加到原来的 2 倍。以 Mixtral 8×7B 为例,该模型总参数量为 47B,但每 token 只激活约 13B 参数,推理成本接近 13B 模型,却能实现接近 70B 模型的质量。
然而,这种设计并非没有代价,主要体现在以下几个方面:
- 显存占用: 尽管每次只运行 $k$ 个专家,但所有专家都需要常驻显存。例如, Mixtral 8×7B 在 fp16 精度下需要约 94 GB 显存,甚至超过了稠密 70B 模型;不过,通过 INT4 量化,显存占用可以降至 24 GB 以下。
- 负载均衡: 如果不加以干预,路由器可能会倾向于选择少数几个“热门”专家,导致负载分布不均。为了解决这一问题,实际训练中通常会引入辅助的负载均衡损失(Shazeer 2017、 Switch Transformer),并在路由决策中加入少量噪声,以鼓励探索更多专家。
- 全互联通信: 在多 GPU 训练场景中,每个 token 需要被发送到目标专家所在的设备并返回结果,因此 MoE 对网络拓扑结构的性能非常敏感。
| |
(在生产环境中, MoE 的实现通常会利用 grouped GEMM 和容量限制的分桶机制,并行调度 token 到对应的专家。上述代码中的循环只是为了清晰展示逻辑,并未考虑性能优化。)
量化:每个权重少几比特#

现代大语言模型(LLM)的权重通常使用 BF16 格式训练,每参数占用 2 字节。一个 70B 参数的模型需要 140 GB 显存,这远远超出了单张 A100 80GB 或 H100 80GB 的显存容量。量化技术通过将每个权重替换为低比特整数,并结合每个块的缩放因子(scale),在精度损失极小的情况下显著减少了模型的显存占用。
对称 INT8 量化: 首先为每个张量(或通道)选择一个缩放因子 $s = \max|w| / 127$ ,然后将权重存储为 $\hat w = \mathrm{round}(w / s) \in [-127, 127]$ 。在计算时,通过 $w \approx s \cdot \hat w$ 恢复原始权重。这种方法不仅让显存需求减半,还能在支持 INT8 的 Tensor Core 上实现约两倍的吞吐量提升。
| |
INT4 + GPTQ (Frantar 等, 2022)。 如果直接将每个权重独立量化到 4 比特,模型精度会大幅下降。 GPTQ 提出了一种更聪明的方法:按列逐步量化,并在每次量化完一列后,利用从小批量校准数据中估计的 Hessian 矩阵调整剩余未量化的列,以补偿当前列的舍入误差。最终结果是,对于 7B 参数以上的模型,量化到 4 比特后困惑度(perplexity)的损失不到 1%。
INT4 + AWQ (Lin 等, 2023)。 AWQ 的研究发现,权重通道中仅有约 1% 是“显著”的——这些通道由较大的激活值驱动。通过仅保护这些显著通道(使用 per-channel scaling,而非保留为 fp16),可以恢复绝大部分模型精度。相比 GPTQ, AWQ 的计算速度更快,因此已经成为许多量化开源 checkpoint 的默认选择。
| 精度 | 字节/参数 | LLaMA-2-7B 权重 | LLaMA-2-70B 权重 | 典型 PPL 增量 |
|---|---|---|---|---|
| FP16 / BF16 | 2.0 | 13.5 GB | 140 GB | 参考基准 |
| INT8 (RTN) | 1.0 | 6.7 GB | 70 GB | <0.5% |
| INT4 (GPTQ / AWQ) | 0.5 | 3.4 GB | 35 GB | <2% |
| INT3 (高级算法) | 0.375 | 2.5 GB | 26 GB | 3–6% |
| |
激活值通常仍保留为 FP16/BF16 格式,因为它们的分布具有重尾特性(LLM.int8(), Dettmers 2022 指出,少量“离群特征”承载了大部分激活能量,必须保持高精度)。仅对权重进行 INT4 量化,目前被认为是推理场景下的最佳平衡点。
组合起来:高吞吐推理#
这些技术模块可以很好地协同工作。以 vLLM 为代表的现代推理服务框架整合了以下关键特性:
- 类似 LLaMA 的解码器模块(pre-norm + RMSNorm + SwiGLU + RoPE + GQA),兼顾性能与效果。
- 每层的 KV 缓存采用固定大小的分页机制(PagedAttention),动态调整上下文长度时不会引发内存碎片问题。
- 使用 FlashAttention 内核优化预填充和解码阶段的计算效率。
- 权重通过 INT4 量化(AWQ / GPTQ)显著降低显存占用。
- 支持连续批处理:当某个请求完成后,其占用的资源会立即被下一个请求接管,而无需等待整个批次中最慢的序列完成。
| |
在实际应用中,单张 A100 80GB 显卡运行 7B AWQ 模型时,总吞吐量可以达到 3000–5000 tokens/s;而单张 H100 运行 Mixtral 8×7B AWQ 模型时,吞吐量更是超过 1000 tokens/s。如果按照 2017 年的技术水平来实现,这样的性能表现简直是天方夜谭。
常见问题#
为什么选择 decoder-only 而不是 encoder-decoder?#
一个训练用来预测下一个 token 的因果 decoder-only 模型,只需调整提示词,就可以轻松转换为分类器、翻译工具或聊天机器人。而 encoder-decoder 模型则需要额外的交叉注意力参数,并且训练流程更复杂,生成时也无法利用前缀缓存来节省计算开销。此外, decoder-only 的扩展性更强,因为语料中的每个 token 都能直接作为有效的训练信号。
RoPE 和 ALiBi,哪个在实际中更有优势?#
绝大多数情况下, RoPE 是更好的选择:它能够为模型提供真实的相对相位信息,并且通过 NTK/YaRN 缩放技术可以无缝扩展上下文长度(从 4K 扩展到 32K–128K)。 ALiBi 的优点在于无需微调即可实现外推,但其分布内性能会稍逊一筹。目前所有主流开源大语言模型(LLM)都采用了 RoPE。
FlashAttention 是否会影响模型输出?#
不会。 FlashAttention 实现的是精确的注意力计算,只是浮点数归约顺序略有不同。与朴素实现相比,数值差异远低于训练噪声,完全可以忽略不计。
MoE 是否一定比稠密模型更高效?#
计算效率更高,但显存占用更多。如果显存是瓶颈(例如在单张 24GB 显卡上推理),量化的稠密模型通常表现更好。如果显存充足,但在解码阶段受限于 FLOPs, MoE 则更具优势。
对于 7B 参数规模的模型, INT4 量化会损失多少精度?#
使用 GPTQ 或 AWQ 在约 128 条样本的校准集上进行量化后,困惑度(perplexity)通常只会增加不到 2%,大多数下游任务的质量几乎察觉不到变化。对于 70B 参数规模的模型,精度损失一般小于 1%。但如果模型规模小于 7B,量化带来的负面影响会更加显著。
为什么长上下文场景下 KV Cache 成为瓶颈?#
KV Cache 的大小公式为 $2 \cdot L \cdot H_{kv} \cdot d_h \cdot T \cdot \text{字节数}$ 。以 70B 规模的模型为例,在 32K 上下文长度下使用 MHA, KV Cache 占用约 80GB,甚至超过了模型权重本身的大小。 GQA 将其降至约 10GB,而 PagedAttention 则将内存碎片率控制在 5% 以内,两者结合才使得普通硬件也能支持长上下文推理。
NLP 技术前沿 12 篇
- 01 自然语言处理(一):NLP 入门与文本预处理
- 02 自然语言处理(二):词向量与语言模型
- 03 自然语言处理(三):RNN 与序列建模
- 04 自然语言处理(四):注意力机制与 Transformer
- 05 自然语言处理(五):BERT 与预训练模型
- 06 自然语言处理(六):GPT 与生成式语言模型
- 07 自然语言处理(七):提示工程与 In-Context Learning
- 08 自然语言处理(八):模型微调与 PEFT
- 09 自然语言处理(九):大语言模型架构深度解析 当前
- 10 自然语言处理(十):RAG 与知识增强系统
- 11 自然语言处理(十一):多模态大模型
- 12 自然语言处理(十二):前沿技术与实战应用