Transformer拆解13:现代大模型改了什么,RoPE、RMSNorm、SwiGLU与GQA

Transformer拆解13:现代大模型改了什么,RoPE、RMSNorm、SwiGLU与GQA

我是老计。走到这里,经典Transformer的主要零件已经拆完。可你打开现代大模型配置,会看到一批原论文里没有的名字:RoPE、RMSNorm、SwiGLU、MQA、GQA。

容易出现两个极端。一种认为现代大模型和2017年Transformer完全一样,只是参数更多;另一种认为零件换了这么多,它已经不是Transformer。两种说法都过于简单。

现代大模型保留了Transformer的主干分工:注意力负责位置间信息交换,前馈网络逐位置加工,残差连接组织深层路径。变化主要发生在位置表示、归一化、激活门控和键值头共享方式上。

本篇不把这些缩写罗列成名词表,而是逐项回答:原来怎么做、现在改了什么、它试图解决什么、代价和边界是什么。

一,先立一条历史边界

2017年原始Transformer的代表性配置包括:

  • Encoder-Decoder整体结构;
  • 固定正弦位置编码与Embedding相加;
  • 多头注意力中Q、K、V头数相同;
  • Position-wise FFN使用ReLU;
  • 子层后残差相加再LayerNorm,也就是Post-Norm。

许多现代Decoder-only大模型常见:

  • RoPE作用于Q和K;
  • Pre-Norm路径;
  • RMSNorm;
  • SwiGLU门控前馈网络;
  • MQA或GQA减少KV头数量。

"常见"不等于"全部"。不同模型家族会选择不同组合,甚至同一家族不同代也会调整。写文章或读配置时,必须以具体模型技术报告和代码为准。

二,位置表示,从输入相加到QK旋转

经典正弦位置编码生成 [S,d_model] 的位置向量,与Token Embedding逐元素相加。位置和内容从模型入口就混在同一主干表示里。

RoPE不准备一张位置向量与输入相加。它把Q、K的维度两两配对,根据位置施加旋转。旋转后点积显式包含相对位置差。

RoPE试图带来什么

  • 位置直接影响QK兼容度;
  • 旋转保持每对向量的范数;
  • 相同相对位移在理想二维推导中形成相同旋转差;
  • 不需要可学习绝对位置表。

它没有自动解决什么

RoPE不自动保证模型能可靠处理任意长上下文。训练长度、频率基数、位置缩放、注意力分布和KV Cache容量都会限制有效长度。

现代模型还使用各种RoPE缩放和插值方案。它们不是原始RoPE定义的一部分,兼容预训练权重需要遵循模型配置。只把上下文长度字段改大,通常不能得到同等质量的长上下文能力。

三,归一化,从LayerNorm到RMSNorm

LayerNorm对每个Token隐藏向量减均值、按标准差缩放,再使用可训练增益和偏移。RMSNorm不减均值,只按均方根缩放,常见实现保留可训练增益而没有偏移。

RMSNorm改变了什么

它省去重新居中步骤,计算结构更简单。RMSNorm论文的核心观点是保留重新缩放不变性,而认为重新居中并非所有场景都必需。

不能怎样表述

  • 不能说RMSNorm等于没有均值的LayerNorm后输出仍是零均值;
  • 不能说RMSNorm在任何模型上都必然更快某个固定比例;
  • 不能把已训练LayerNorm模型直接换成RMSNorm并期待无损;
  • 不能忽略epsilon、可训练权重和低精度统计实现。

现代大模型常把RMSNorm放在注意力或FFN之前,形成Pre-Norm主干。但RMSNorm与Pre-Norm是两个维度:一个回答用什么归一化,一个回答归一化放在子层前还是后,不能混成同义词。

四,前馈网络,从ReLU到SwiGLU

经典FFN是两次线性投影,中间使用ReLU:

text 复制代码
FFN(x) = ReLU(xW_1 + b_1)W_2 + b_2

SwiGLU使用两条输入投影,一条经过SiLU作为门,另一条提供内容,然后逐元素相乘,再投影回主干:

text 复制代码
hidden = SiLU(xW_g) elementwise_multiply (xW_v)
output = hidden W_o

门控的直觉

内容分支回答"有哪些候选特征",门控分支回答"当前输入应让哪些特征通过多少"。两条分支都由输入动态计算,因此不是一个固定开关表。

公平比较为什么要调中间宽度

普通FFN主要有两组大矩阵,SwiGLU通常有三组。若保持相同中间宽度,SwiGLU参数和计算更多。现代模型常缩小门控FFN的中间宽度,使总参数预算接近。

所以比较ReLU与SwiGLU,至少要说明是否对齐:

  • 主干隐藏维度;
  • 中间维度;
  • 总参数量;
  • 训练Token和数据;
  • 优化器与学习率;
  • 推理内核与硬件。

把激活函数名字换掉不等于完成公平实验。SwiGLU的两条输入投影改变了参数结构,必须连同中间宽度一起比较。

五,注意力头,从MHA到MQA与GQA

标准MHA中,查询头数、键头数和值头数相同。假设有8个查询头,就有8组K和8组V。

MQA保留多个查询头,但所有查询头共享一组K和V。GQA位于两者之间,多个查询头被分成若干组,每组共享一组K/V。

例如8个查询头、2个KV头时,可以让前4个查询头使用KV头0,后4个使用KV头1。

严格定义三者

text 复制代码
MHA:H_q = H_kv
GQA:1 < H_kv < H_q
MQA:H_kv = 1

常见高效实现要求 H_q 能被 H_kv 整除,以便每组拥有相同数量查询头。数学上也可以设计不等分映射,但不能直接套标准reshape和广播逻辑。

为什么减少KV头能帮助推理

自回归解码每一步都要读取历史K/V。KV头越少:

  • 缓存元素数越少;
  • 每步从显存读取历史K/V的数据量下降;
  • 内存带宽压力可能减轻;
  • 同样显存可能容纳更长上下文或更大批次。

它主要针对增量解码的缓存和带宽,不意味着训练算力、模型质量或端到端延迟一定按KV头比例变化。

六,用NumPy计算KV头映射和缓存元素数

设批次2、历史长度128、查询头8、每头维64,只比较单层K/V元素数:

python 复制代码
import numpy as np

B, L, H_q, head_dim = 2, 128, 8, 64

for name, H_kv in [("MHA", 8), ("GQA", 2), ("MQA", 1)]:
    elements = 2 * B * L * H_kv * head_dim
    q_to_kv = np.arange(H_q) // (H_q // H_kv)
    print(
        name,
        "kv_heads=", H_kv,
        "elements=", elements,
        "q_to_kv=", q_to_kv.tolist(),
    )

运行环境:Python 3,NumPy 1.26.4,CPU。实际输出:

text 复制代码
MHA kv_heads= 8 elements= 262144 q_to_kv= [0, 1, 2, 3, 4, 5, 6, 7]
GQA kv_heads= 2 elements= 65536 q_to_kv= [0, 0, 0, 0, 1, 1, 1, 1]
MQA kv_heads= 1 elements= 32768 q_to_kv= [0, 0, 0, 0, 0, 0, 0, 0]

公式中的第一个2表示K和V两份,不是批次。总元素数为:

text 复制代码
2乘B乘L乘H_kv乘head_dim

在这组配置中,GQA缓存元素数是MHA的四分之一,MQA是八分之一。这只是理想元素数量比例,不能直接写成推理速度提升4倍或8倍。真实速度还受Q投影、注意力计算、FFN、内核、批次、并行通信和调度影响。

完整模型还要乘层数和字节数

若有 N_layers 层、每元素 bytes 字节,总缓存近似:

text 复制代码
KV bytes = 2乘B乘L乘N_layers乘H_kv乘head_dim乘bytes

有的系统按请求分别管理,有的做分页缓存、块共享或量化;内存分配还会有元数据和碎片。公式是核心张量体积,不是进程完整显存账单。

七,用代码验证RMSNorm和SwiGLU形状

下面把输入先做无仿射RMSNorm,再通过简化SwiGLU。这里不含注意力和残差,只验证两个零件的统计与形状。

python 复制代码
import numpy as np

rng = np.random.default_rng(131)
x = rng.normal(size=(2, 3, 8))
epsilon = 1e-6
rms = x / np.sqrt(np.mean(x * x, axis=-1, keepdims=True) + epsilon)
wg = rng.normal(size=(8, 12))
wv = rng.normal(size=(8, 12))
wo = rng.normal(size=(12, 8))

def silu(z):
    return z / (1 + np.exp(-z))

y = (silu(rms @ wg) * (rms @ wv)) @ wo
print("input:", x.shape, "rms:", rms.shape, "swiglu output:", y.shape)
print("rms values:", np.round(
    np.sqrt(np.mean(rms * rms, axis=-1)), 6
))

实际输出:

text 复制代码
input: (2, 3, 8) rms: (2, 3, 8) swiglu output: (2, 3, 8)
rms values: [[0.999999 1.       1.      ]
 [1.       0.999999 0.999999]]

RMSNorm不改变形状,SwiGLU先扩到12维再投影回8维。均方根接近1,因为epsilon让结果不是数学上绝对等于1。

八,这些改造不是一条因果链

RoPE、RMSNorm、SwiGLU和GQA解决的是不同问题:

  • RoPE改变位置如何进入QK关系;
  • RMSNorm简化归一化统计;
  • SwiGLU改变逐Token非线性加工;
  • GQA减少KV头共享以降低推理缓存和带宽。

它们可以组合,但不是"用了RoPE就必须用RMSNorm""用了SwiGLU就必须用GQA"。每项都要与训练配方和内核共同验证。

现代模型质量来自数据、规模、优化、架构和训练稳定性共同作用。不能把模型提升归因给某一个零件,也不能从不同论文的独立结果拼出一个保证更强的配方。

架构改造不是积木排行榜。每个零件改变一条计算路径,也引入新的参数、数值和部署约束,组合效果必须靠完整训练与评测证明。

九,工程选型怎样避免只看配置表

阅读模型配置时,建议按四层检查:

  1. 数学结构:位置、归一化、FFN、头共享分别是什么;
  2. 张量形状:查询头、KV头、每头维度和中间宽度是否匹配;
  3. 训练事实:模型权重是否按这套结构训练,不能随意替换;
  4. 运行实现:推理框架是否支持对应内核、量化、并行和缓存布局。

例如某模型使用GQA,但推理框架若把KV重复展开成查询头数量再计算,缓存或带宽优势可能被部分抵消。某模型使用SwiGLU,但硬件没有高效融合内核,延迟收益也不能只看公式预测。

十,GQA在张量上怎样广播

设查询头数 H_q=8、KV头数 H_kv=2、每组4个查询头。投影后形状可以是:

text 复制代码
Q:[B,8,T,head_dim]
K、V:[B,2,S,head_dim]

计算注意力前,要建立查询头到KV头的映射。概念上,查询头0至3使用KV头0,查询头4至7使用KV头1。

一种简单实现会把每个KV头重复4次,临时得到8头K/V再调用MHA内核;这种做法计算正确,却可能物化重复数据,削弱内存优势。更高效内核可以在计算中按组广播,不真的复制缓存。

缓存减少与投影参数减少要分开

GQA不仅可能减少缓存,也会减少K/V投影输出宽度和相应参数。若Q投影仍输出 H_q×head_dim,K/V只输出 H_kv×head_dim:

text 复制代码
W_Q:[d_model, H_q乘head_dim]
W_K:[d_model, H_kv乘head_dim]
W_V:[d_model, H_kv乘head_dim]

但具体模型可能让Q头维、KV头维或总隐藏宽度采用其他约定。计算参数量必须读配置,不能只看"用了GQA"四个字。

从MHA检查点转为GQA不是直接改数字

GQA论文给出了从已有MHA检查点上训练转换的方法。一般需要把多组K/V参数按策略聚合或初始化,再继续训练适配。直接把配置中的KV头数从8改成2,会导致权重形状不匹配;粗暴重复或平均虽然能构造参数,也不保证质量。

GQA是一种需要模型参数配套训练的架构,不是推理时随手打开的无损开关。

十一,以LLaMA为例怎样描述才准确

LLaMA技术报告是现代组合的代表之一:它在Transformer主干上使用Pre-Norm、RMSNorm、SwiGLU和RoPE。不过不同LLaMA代际和规模的注意力头组织并不应只靠家族名概括,具体是否使用GQA、头数和上下文策略要查对应版本配置。

这给写技术文章一个重要提醒:

  • 可以用具体技术报告说明某代模型采用了哪些改造;
  • 不要把整个模型家族所有版本写成完全相同;
  • 不要从一个模型使用某组合,推导这套组合是现代大模型标准答案;
  • 不要把训练数据、规模带来的能力提升全部归因于架构零件。

现代模型配置是多目标权衡:训练稳定、质量、参数预算、推理显存、硬件内核和分布式策略共同决定结果。

十二,为什么不能在现有权重上直接换零件

这些结构会改变前向计算,预训练权重已经与原结构共同适配:

  • 正弦相加改RoPE,会改变位置进入注意力的方式;
  • LayerNorm改RMSNorm,会改变每层激活统计;
  • ReLU FFN改SwiGLU,会改变矩阵数量和权重形状;
  • MHA改GQA,会改变K/V投影与缓存头映射。

因此"配置文件改一行"通常不够。至少需要权重转换、继续训练、蒸馏或从头训练,并在质量与性能上验证。某些近似初始化方法可以降低转换成本,但不能预先保证无损。

即使两个模型参数总量接近,也可能因为计算图不同无法直接互换权重。模型格式转换应比较固定输入下的逐层激活和最终Logits,而不是只看权重文件成功加载。

现代改造是训练架构的一部分,不是推理阶段随意替换的插件。权重与计算图必须配套。

十三,常见误区

误区一:现代大模型只是把Transformer做大

主干仍是Transformer,但位置、归一化、FFN和注意力头组织已有多种改造。

误区二:RoPE加在输入Embedding上

标准RoPE通常旋转Q和K,不是输入位置向量相加。

误区三:RMSNorm会把均值归一到0

它不减均值,只按均方根缩放。

误区四:SwiGLU只替换一个激活函数

它通常多一条输入投影和逐元素门控,参数结构发生变化。

误区五:GQA减少查询头

GQA通常保留多个查询头,减少并共享KV头。查询头与KV头数量不能混称。

误区六:KV缓存缩小几倍,速度就提升几倍

缓存体积和读取量只是端到端性能的一部分,实际收益要在真实硬件和请求上测量。

小结

现代大模型常在经典Transformer主干上采用RoPE、Pre-RMSNorm、SwiGLU和MQA/GQA。RoPE把位置注入QK旋转,RMSNorm不做均值居中,SwiGLU使用门控与内容两条投影,GQA让多个查询头分组共享更少KV头。

这些改造各解决不同问题,不是绑定套餐,也不保证简单拼装就更好。尤其GQA的KV缓存元素数下降,不能直接当作端到端加速比例。

下一篇收官,集中拆KV Cache与FlashAttention:一个减少重复计算和历史读取,一个减少注意力在内存层级间搬运,它们到底优化了什么、没有优化什么。

延伸阅读

(本文为技术学习与经验分享,代码用于理解机制。框架与实现可能随版本变化,具体用法请以官方最新文档为准。)

版权声明:本文版权归作者老计个人所有。欢迎个人学习阅读,未经授权,禁止转载、摘编、搬运或用于任何商业用途,违者将追究责任。转载请联系作者Jich。

相关推荐
飞猫的边缘AI3 天前
边缘AI芯片的规则变了:从跑CNN到跑LLM和VLM
人工智能·语言模型·cnn·transformer·边缘ai
DevOps老兵3 天前
Transformer拆解06:Self-Attention,一句话里的词怎样互相看见
大模型·transformer·自注意力·self-attention·注意力矩阵
秋秋小事4 天前
transformer基础 RNN + LSTM
rnn·lstm·transformer
Eloudy4 天前
全文 - LLaMA v2 - Llama 2: Open Foundation and Fine-Tuned Chat Models
llm·transformer·gpu
明天会有多晴朗4 天前
从零手写 Transformer!一个 Python 文件跑通英译中(PyTorch 附完整源码)
人工智能·pytorch·python·深度学习·transformer
高洁014 天前
端侧大模型的应用场景与工程实践
人工智能·深度学习·机器学习·transformer·tornado
AI-Frontiers5 天前
Attention 演进路线:5 大阶段,11 篇奠基论文
transformer
zx_741484815 天前
BERT自然语言处理框架深度解析:从Transformer到双向预训练模型
自然语言处理·bert·transformer
布吉岛的石头6 天前
Java 程序员第 50 阶段13:对齐税 alignment tax 是什么
人工智能·深度学习·transformer