QK-Norm
QK-Norm
来自 Sebastian Raschka 的 The Big LLM Architecture Comparison。
一句话
QK-Norm = 在 attention 模块内,对 q、k 各自加一层 RMSNorm,在 RoPE 之前 应用。起源是 2023 年的 Scaling Vision Transformers 论文。
代码示例
class GroupedQueryAttention(nn.Module):
def __init__(self, d_in, num_heads, num_kv_groups,
head_dim=None, qk_norm=False, dtype=None):
# ...
if qk_norm:
self.q_norm = RMSNorm(head_dim, eps=1e-6)
self.k_norm = RMSNorm(head_dim, eps=1e-6)
else:
self.q_norm = self.k_norm = None
def forward(self, x, mask, cos, sin):
b, num_tokens, _ = x.shape
queries = self.W_query(x)
keys = self.W_key(x)
values = self.W_value(x)
# ...
if self.q_norm:
queries = self.q_norm(queries)
if self.k_norm:
keys = self.k_norm(keys)
# apply RoPE
queries = apply_rope(queries, cos, sin)
keys = apply_rope(keys, cos, sin)
# ...作用
- 与 [[Post-Norm vs Pre-Norm|Post-Norm]] 一起 → 稳定训练
- QK 的尺度被显式控制 → 防止 attention logits 爆炸
谁在用
- OLMo 2(首次出现在主流 LLM)
- Gemma 2 / Gemma 3
- MiniMax M2(Per-Layer QK-Norm——见下)
- Arcee Trinity Large
- GLM-4.5
Per-Layer QK-Norm(M2 变体)
普通 QK-Norm 是一组 q_norm / k_norm
在每层共享。M2 的实现更”细”:
self.q_norm = MiniMaxText01RMSNormTP(self.head_dim * self.total_num_heads, eps=...)
self.k_norm = MiniMaxText01RMSNormTP(self.head_dim * self.total_num_kv_heads, eps=...)- hidden_size = num_heads × head_dim
- scale 向量对每个 head 的每个 head_dim 都有独立参数——不是 head 间共享
相关笔记
- [[Post-Norm vs Pre-Norm]]
- [[OLMo 2]]
- [[Gemma 系列]]
- [[MiniMax M2]]
- [[Arcee Trinity Large]]
来源
The Big LLM Architecture Comparison, section 2.2 链接:https://magazine.sebastianraschka.com/p/the-big-llm-architecture-comparison