【大模型学习】现代大模型架构(一): 组注意力机制(GQA)和 RMSNorm


前言

✍ 在大模型论文学习中,相信很多读者和笔者一样,一开始都会有一种感觉:“现在大模型架构都差不多,主要是数据和算力在堆积。”当笔者慢慢总结llama、qwen、deepseek这些模型架构的时候发现,在 attention、位置编码、ffn 与归一化 上,其实已经悄悄从经典 transformer 走到了另一套“默认配置”。相较于最初的 transformer,现在的主流大模型在架构上,已经逐渐从:

MQA → GQA(Grouped Query Attention)绝对位置编码 → RoPE(Rotary Positional Embedding)ReLU / GELU 前馈网络 → SwiGLU 前馈网络LayerNorm → RMSNorm + Pre-Norm...

因此,在本文的学习中,我们主要聚焦于目前的大模型”默认配置“的学习,了解现在的”Transformer“!

一、现如今的”Transformer“

读者肯定很疑惑,为什么我要把第一章名字起为现如今的”Transformer“,实际上在以前,不管是科研还是工作,大家都会把Transformer作为一个baseline去进行优化,就像BERT、GPT等等,一直沿用的是Transformer的架构。但到了现在,研究者发现其中模块的更替可以达到更好的的效果。因此,现如今的大模型,已经不再直接将以前的Transformer架构作为baseline,而是将更换了模块的Transformer架构作为baseline。那现如今的baseline模块长什么样子呢,笔者统计了比较经典的模块所采用的注意力机制、位置编码、MLP激活层以及归一化的方式:

模型家族

注意力

位置编码

MLP 激活

归一化

早期 GPT/BERT

MHA

绝对 PE / learned pos

GELU

LayerNorm

LLaMA 1/2/3 系列

GQA(大模型)

RoPE

SwiGLU

RMSNorm

Qwen2 / Qwen2.5

GQA

RoPE

SwiGLU

RMSNorm

Mistral 7B

GQA + sliding window

RoPE

SwiGLU

RMSNorm

DeepSeek-LLM 等

GQA/自研高效注意力

RoPE

SwiGLU

RMSNorm

Granite / Gemma 等

GQA/MQA

RoPE

SwiGLU/GeGLU

RMSNorm/LN

如表格所示, 对比早期 GPT/BERT 模型我们就可以发现了,现如今大模型的各个模块都有所改变:

注意力机制:MQA → GQA(Grouped Query Attention)位置编码: 绝对位置编码 → RoPE(Rotary Positional Embedding)MLP 激活层:ReLU / GELU 前馈网络 → SwiGLU 前馈网络归一化: LayerNorm → RMSNorm + Pre-Norm

所以如果你能把这四件套讲明白,基本就把现代 LLM 架构里 理清,并且可以快速找到文章的贡献点。

二、Attention Serious

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

2.1 Multi-Head Attention (MHA)

首先来回顾一下以前的注意力机制:

\text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d\_k}}\right)V

在标准的自注意力中,我们通过 $QK^T / \sqrt{d_k}$ 来计算不同 token 之间的注意力权重。但作者发现,仅用一个注意力头往往难以同时捕捉多种语义关系(如词法、语义、句法等)。因此,Transformer 提出了多头注意力机制 (Multi-Head Attention, MHA)。

将输入特征通过不同的线性投影矩阵,映射到多个低维子空间中:

\text{head}\_i = \text{Attention}(QW\_i^Q, \, KW\_i^K, \, VW\_i^V)

然后将所有头拼接(concatenate)再线性变换:

\text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}\_1, \dots, \text{head}\_h) W^O

MHA通过多个小头可以从不同角度捕捉语义信息,增强模型的表达能力和稳定性,比单头更鲁棒。

代码手撕
import torchimport torch.nn as nnimport torch.nn.functional as Fclass MultiHeadAttention(nn.Module):    def __init__(self, d_model, num_heads, dropout=0.0):        super().__init__()        assert d_model % num_heads == 0        self.d_model = d_model        self.num_heads = num_heads        self.head_dim = d_model // num_heads        self.w_q = nn.Linear(d_model, d_model)        self.w_k = nn.Linear(d_model, d_model)        self.w_v = nn.Linear(d_model, d_model)        self.w_o = nn.Linear(d_model, d_model)        self.dropout = nn.Dropout(dropout)    def forward(self, x, attn_mask=None):        """        x: [B, L, d_model]        """        B, L, _ = x.size()        # 1. 线性投影        Q = self.w_q(x)  # [B, L, d_model]        K = self.w_k(x)        V = self.w_v(x)        # 2. reshape 为 [B, H, L, Dh]        def reshape_heads(t):            return t.view(B, L, self.num_heads, self.head_dim).transpose(1, 2)        Q = reshape_heads(Q)        K = reshape_heads(K)        V = reshape_heads(V)        # Q,K,V: [B, H, L, Dh]        # 3. 缩放点积注意力        scores = Q @ K.transpose(-2, -1) / (self.head_dim ** 0.5)  # [B, H, L, L]        if attn_mask is not None:            scores = scores.masked_fill(attn_mask == 0, float('-inf'))        attn = F.softmax(scores, dim=-1)        attn = self.dropout(attn)        out = attn @ V  # [B, H, L, Dh]        # 4. 合并头        out = out.transpose(1, 2).contiguous().view(B, L, self.d_model)        return self.w_o(out)

2.2 Multi-Query Attention (MQA)

有了 MHA 之后,大家第一反应是:头越多越好,越能学到多种语义关系。但在大模型、尤其是 Decoder-Only + 长上下文 + 自回归生成 的场景下,MHA 暴露出了一个非常现实的问题:

KV Cache 太贵了。

在自回归生成过程中,每生成一个新 token,都需要用到历史所有位置的K, V

对于标准 MHA:每个注意力头都维护一份自己的 K\_h, V\_h 如果有 h 个头,那么 KV Cache 的内存开销大致是: \mathcal{O}(h \cdot L \cdot d_{\text{head}})

当我们把头数堆到 32、64 甚至更多,再把上下文长度拉到 32K、64K 时,这个开销就会变成显存吞噬怪,直接限制推理速度与可部署性。因此,为了在几乎不损失模型效果的前提下,压缩 KV Cache 和带宽成本,就提出了 Multi-Query Attention(MQA)。

MHA中的每一个头都是独享一份$K, V$,相反的,MQA 提出了所有的头共享同一份$K, V$也就是说,只保留一组 W^K, W^V ,而 W_i^Q 仍然为每个头独立:

Q_i = X W_i^Q,\quad K = X W^K,\quad V = X W^V.

于是每个头的注意力就变成:

\text{head}_i = \text{Attention}(Q_i, K, V) = \text{softmax}\left(\frac{Q_i K^\top}{\sqrt{d_k}}\right) V.

最后依然是拼接再线性变换:

\text{MQA}(X) = \text{Concat}(\text{head}_1, \dots, \text{head}_h) W^O.

? 经验发现“多 KV”并没有带来线性收益, Q 仍然是多头的,多头仍能捕捉多种语义关系。

代码手撕
class MultiQueryAttention(nn.Module):    def __init__(self, d_model, num_heads, dropout=0.0):        super().__init__()        assert d_model % num_heads == 0        self.d_model = d_model        self.num_heads = num_heads        self.head_dim = d_model // num_heads        self.w_q = nn.Linear(d_model, d_model)        # 注意:K/V 只有一组,所以输出维度是 head_dim        self.w_k = nn.Linear(d_model, self.head_dim)        self.w_v = nn.Linear(d_model, self.head_dim)        self.w_o = nn.Linear(d_model, d_model)        self.dropout = nn.Dropout(dropout)    def forward(self, x, attn_mask=None):        """        x: [B, L, d_model]        """        B, L, _ = x.size()        # 1. 多头 Q        Q = self.w_q(x)  # [B, L, d_model]        Q = Q.view(B, L, self.num_heads, self.head_dim).transpose(1, 2)        # Q: [B, H, L, Dh]        # 2. 单头 K/V        K = self.w_k(x)  # [B, L, Dh]        V = self.w_v(x)  # [B, L, Dh]        # 3. 为了和 Q 匹配,将 K/V 在头维上 broadcast        K = K.unsqueeze(1)  # [B, 1, L, Dh]        V = V.unsqueeze(1)  # [B, 1, L, Dh]        K = K.expand(B, self.num_heads, L, self.head_dim)        V = V.expand(B, self.num_heads, L, self.head_dim)        # 4. 缩放点积注意力(与 MHA 相同)        scores = Q @ K.transpose(-2, -1) / (self.head_dim ** 0.5)  # [B, H, L, L]        if attn_mask is not None:            scores = scores.masked_fill(attn_mask == 0, float('-inf'))        attn = F.softmax(scores, dim=-1)        attn = self.dropout(attn)        out = attn @ V  # [B, H, L, Dh]        out = out.transpose(1, 2).contiguous().view(B, L, self.d_model)        return self.w_o(out)

2.3 Grouped Query Attention (GQA)

根据前面两节的分析,我们可以总结出:

MHA:每个头都有独立的 K_h, V_h ,表达能力强,但 KV Cache 成本最高;MQA:所有头共享同一份 K, V ,KV Cache 成本最低,但多头之间视角差异弱,表达能力稍打折

于是就自然出现了一个折中思路:能不能在 “省 KV” 和 “头之间有点差异” 之间找个平衡?这就是 Grouped-Query Attention(GQA)。GQA 的核心思想:Q 仍然是很多头,但 K/V 的头数减少为更少的组(num_kv_heads),每组 KV 服务若干个 Q 头。

代码手撕
class GroupedQueryAttention(nn.Module):    def __init__(self, d_model, num_q_heads, num_kv_heads, dropout=0.0):        super().__init__()        assert d_model % num_q_heads == 0        assert num_q_heads % num_kv_heads == 0        self.d_model = d_model        self.num_q_heads = num_q_heads        self.num_kv_heads = num_kv_heads        self.head_dim = d_model // num_q_heads        self.group_size = num_q_heads // num_kv_heads  # 每组多少个 Q 头共享一个 KV        self.w_q = nn.Linear(d_model, d_model)        self.w_k = nn.Linear(d_model, num_kv_heads * self.head_dim)        self.w_v = nn.Linear(d_model, num_kv_heads * self.head_dim)        self.w_o = nn.Linear(d_model, d_model)        self.dropout = nn.Dropout(dropout)    def forward(self, x, attn_mask=None):        """        x: [B, L, d_model]        """        B, L, _ = x.size()        # 1. Q: 多头; K/V: 少量头        Q = self.w_q(x)  # [B, L, d_model]        K = self.w_k(x)  # [B, L, num_kv_heads * head_dim]        V = self.w_v(x)        Q = Q.view(B, L, self.num_q_heads, self.head_dim).transpose(1, 2)        K = K.view(B, L, self.num_kv_heads, self.head_dim).transpose(1, 2)        V = V.view(B, L, self.num_kv_heads, self.head_dim).transpose(1, 2)        # Q: [B, Hq,  L, Dh]        # K,V: [B, Hkv, L, Dh]        # 2. 将每个 KV 头“扩展”为 group_size 个 Q 头使用        #    例如 Hq=8, Hkv=2 -> group_size=4        K = K.repeat_interleave(self.group_size, dim=1)  # [B, Hq, L, Dh]        V = V.repeat_interleave(self.group_size, dim=1)        # 3. 缩放点积注意力        scores = Q @ K.transpose(-2, -1) / (self.head_dim ** 0.5)  # [B, Hq, L, L]        if attn_mask is not None:            scores = scores.masked_fill(attn_mask == 0, float("-inf"))        attn = F.softmax(scores, dim=-1)        attn = self.dropout(attn)        out = attn @ V  # [B, Hq, L, Dh]        # 4. 合并头        out = out.transpose(1, 2).contiguous().view(B, L, self.d_model)        return self.w_o(out)

三、归一化:LayerNorm → RMSNorm + Pre-Norm

在 Transformer 里,归一化(Normalization)主要解决两个问题:

深层网络训练不稳定:梯度可能爆炸或消失;不同层输出分布漂移,导致学习变慢。

最早的 Transformer 使用的是 LayerNorm + Post-Norm 残差结构(指在全连接层后跟上一个归一化层)

但到了 LLaMA、DeepSeek 等大模型时,大家开始逐渐转向:RMSNorm + Pre-Norm(指在全连接层前跟上一个归一化层)

? Post-Norm(原始 Transformer 用法)

最早的 Transformer 论文(Attention Is All You Need)使用的是 Post-Norm,代码结构类似:

# Post-Norm 结构out = x + sublayer(x)out = layer_norm(out)
? Pre-Norm(现代 LLM 常用)

大多数现代 LLM(如 LLaMA、DeepSeek 系列)改成了 Pre-Norm:代码结构类似:

# Pre-Norm 结构h = layer_norm(x)out = x + sublayer(h)

? 实践上,Pre-Norm 再配合 RMSNorm,只调节尺度不改均值,在 Decoder-only 结构里训练更稳定、实现也更简单。

3.1 LayerNorm

Layer Normalization(LN)是在 Transformer 中使用最广的归一化方式之一。给定一个 token 的隐藏表示 x \in \mathbb{R}^{d} ,LayerNorm 对其 特征维度 进行归一化:

\mu = \frac{1}{d} \sum_{i=1}^{d} x_i,\quad \sigma^2 = \frac{1}{d} \sum_{i=1}^{d} (x_i - \mu)^2
\text{LN}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \cdot \gamma + \beta

其中:

\gamma, \beta \in \mathbb{R}^{d} 是可学习的缩放和平移参数;归一化是在单个样本、单个 token 的通道维度上完成的。

? 直觉理解:

在 PyTorch 中,你平时看到的 nn.LayerNorm 就是这个东西:

import torchimport torch.nn as nnx = torch.randn(2, 4, 8)  # [B, L, d_model]ln = nn.LayerNorm(8)y = ln(x)  # 每个位置的最后一维做 LN
? 1.为什么不用 BatchNorm,而用 LayerNorm / RMSNorm?(面经)

这一问是面试官很喜欢的一个考点,尤其是 Transformer / LLM 岗位。核心区别在于:归一化时用哪些维度来统计均值与方差。

BatchNorm(BN):在 CV 里常用,对 batch 维度 + 空间维度 做统计;对每个通道c,使用整批数据的统计量:mu_c = \mathbb{E}_{N,H,W}x\_{n,c,h,w} LayerNorm(LN):对单个样本、单个 token 的所有特征求均值和方差,不依赖 batch 大小。

在 Transformer / LLM 场景中,BN 存在几个问题:

序列长度不固定:BN 在变长序列上不自然,统计维度不好选;推理阶段 batch 很小甚至为 1:BN 的 running mean/var 与训练时差异大,容易分布漂移;自注意力中不同 token 之间差异大:BN 混合不同 token 的统计量,会引入额外噪声。

因此,大模型里更偏向用 LayerNorm / RMSNorm 这种“不依赖 batch、只看自己”的归一化方式。


3.2 RMSNorm

RMSNorm 是基于“层归一化中主要起作用的是缩放因子,而非平移因子”这个发现而提出的归一化方法。在层归一化中需要减去均值,而模型在训练过程中已经学会通过投影矩阵自动调节均值;而 \gamma 的作用是调整每一维的相对 scale,是表达力的核心。给定 x \in \mathbb{R}^d ,RMSNorm 的公式为:

\text{RMS}(x) = \sqrt{\frac{1}{d} \sum\_{i=1}^{d} x\_i^2 + \epsilon}

\text{RMSNorm}(x) = \frac{x}{\text{RMS}(x)} \cdot \gamma

? 直觉理解:

? 实践上,在 Decoder-only 大模型里:RMSNorm + Pre-Norm 组合在超深层网络(几十层)上表现更稳定,这也是 LLaMA / DeepSeek / Qwen 等系列广泛采用它的原因之一。

代码手撕
class RMSNorm(nn.Module):    def __init__(self, d_model, eps=1e-8):        super().__init__()        self.weight = nn.Parameter(torch.ones(d_model))        self.eps = eps    def forward(self, x):        """        x: [B, L, d_model]        """        # 均方根:sqrt(mean(x^2))        rms = x.pow(2).mean(dim=-1, keepdim=True).add(self.eps).sqrt()        x_norm = x / rms        return self.weight * x_norm

四、总结

本章我们先把现代大模型里的两块“基础设施”打牢:一块是从 MHA → MQA → GQA 的注意力演化,用更少的 KV 头(甚至共享 KV)在不明显掉点的前提下,大幅降低 KV Cache 与长上下文显存开销;另一块是从 LayerNorm → RMSNorm + Pre-Norm 的归一化升级,用“只归一化能量”的 RMSNorm 配合 Pre-Norm 结构,让超深的 Decoder-only 模型在训练和推理中都更加稳定。后面的章节,我们再把 RoPE / SwiGLU / MoE / MLA 这些“进阶武器”一个个拆开,拼成一整套现代 LLM 的“架构面经图谱”。


# win  # bert  # transformer  # var  #   # Token  # 架构  # batch  # deepseek  # 为什么  # 区别  # 大模型  # pytorch  # gpt  # 编码  # qwen  # 显存  # 仍然是  # 是从  # 多个  # 尤其是  # 是在  # 提出了  # 均值  # 现如今  # 的是  # embedding  # llama 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化91478 】 【 技术知识72672 】 【 云计算0 】 【 GEO优化84317 】 【 优选文章0 】 【 营销推广36048 】 【 网络运营41350 】 【 案例网站102563 】 【 AI智能45237


相关推荐: 解密Poppy Playtime怪物:全面解析玩具世界背后的故事  利用 DeepSeek 提高敏捷开发中的 Sprint 规划效率  Zapier MCP:AI赋能工作流,释放Claude强大潜能  豆包 AI 在英语单词高效背诵中的趣味应用  Django与React构建AI音乐推荐:数据库集成实战指南  AI图像生成偏见:克服与优化,打造更真实的数字形象  AI 和 Plagiarism Checker:SEO 内容创作的终极指南  通义千问怎样优化提示词效果_通义千问提示词优化技巧【攻略】  京东旅行AI能否抢返程票_京东AI返程票预约与自动抢购【技巧】  AI驱动的Web应用测试:突破QA挑战,提升用户体验  百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭  AI一键生成原创SEO文章  5分钟教你用AI给黑白老照片上色,让回忆变得鲜活  通义万相做小红书配图怎么用_通义万相做小红书配图使用方法详细指南【教程】  tofai登录入口官网 tofai网页版地址链接  C3.ai深度解析:投资者必知的关键洞察  Jasper AI如何做SEO优化 Jasper AI结合SurferSEO用法【教程】  VHEER AI:免费在线AI图像生成器终极指南  VideoInu AI 动画制作:教程、功能与Pro账户赠送  AI赋能保险销售:提升邮件营销效果的终极指南  快手本地生活AI如何预约景区火车票_快手AI本地生活抢票步骤【步骤】  AI 时代高效开发:版本控制与 AI 协同工作流  AI如何革新心理健康诊断:从症状检查到大脑分析  如何用AI帮你创建自定义表情符号(Emoji)?聊天斗图更有趣  AI Vibe Coding: 快速打造落地页,低代码平台实战教程  寻宝者的发现:古董探测与文物挖掘揭秘  ChatGPT 处理超长 PDF 文件的核心步骤  Google Gemini 处理结构化 XML 数据转换教程  AI Notebooks: 知识工作者的未来?赋能理解与洞察的工具  即梦ai怎样生成插画作品_即梦ai插画生成入口与风格选择【教程】  Microsoft Math Solver:AI数学解题神器深度评测  Codeforces Pair Programming Problem: C 解题思路  钉钉ai划词工具怎么使用划词查词_钉钉ai划词工具查词入口与释义查看【指南】  Xeon E5-2667 V2性能评测:老平台焕发新生,游戏与工作负载表现分析  Avokaado AI:简化合同管理和法律流程的终极指南  使用Go语言构建图像识别系统:完整指南  探索心灵的音乐之旅:Kanwar Garewal的《Ishq Bulleh Nu》  解锁 Gemini Gems 高级用法:打造专属 AI 专家助手  AI一键生成儿童绘本故事  如何用AI根据职位描述(JD)定制你的求职信?  智行ai抢票怎么选优先车次_智行ai抢票车次优先级设置技巧【指南】  AI赋能项目管理:5个实用技巧提升效率  ChatGPT怎样用提示词分步骤提问_ChatGPT分步提问技巧【方法】  网络安全警钟:揭秘“美足”背后隐藏的危机与防范  lovemo手机网页版 lovemo官方入口地址  Removebg怎样快速抠图_Removebg上传图片与自动抠图步骤【教程】  高效赋能:在线健身教练必备的七大工具  2025年度AMD处理器终极评选:年度最佳CPU推荐  Roblox Studio AI 助手:创意构建与无限可能  Notta AI: 提升效率的智能会议纪要工具 

 2025-11-26

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

南京市珐之弘网络技术有限公司


南京市珐之弘网络技术有限公司

南京市珐之弘网络技术有限公司专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 87067657

 13565296790

 87067657@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.