【AI专栏】图解Transformer - 第03章:从多头注意力到一层完整结构

【AI专栏】图解Transformer - 第03章:从多头注意力到一层完整结构
博主介绍程序喵大人35 - 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章首发gzh见文末记得订阅专栏以防走丢C基础系列专栏C语言基础系列专栏C大佬养成攻略专栏C训练营个人网站1. 图解 Transformer Block前两章已经走完了 attention 的核心计算一个 token 先用 Q 去匹配可见 token 的 K得到分数分数经过缩放、mask、softmax 变成权重权重再去读取并混合 V得到上下文向量。第三章把视角往外拉一层真实的 Transformer 里attention 通常以 Multi-Head Attention 的形式出现。多个 head 会从不同表示子空间、不同位置关系里同时提取信息然后把结果合并回来。attention 子层之后token 还会经过 FFN、Residual、Norm 等模块形成一层完整的 Transformer Block。可以把一层 Block 理解成两次核心动作先交流再加工。Multi-Head Attention 让 token 之间交换上下文信息这一步是横向操作FFN / MLP 对每个 token 的表示做进一步加工这一步是纵向操作Residual 和 Norm 让这个过程在很多层堆叠时保持稳定。原始 Transformer 论文里的 encoder layer 有两个子层Multi-Head Self-Attention 和 position-wise Feed-Forward Network。每个子层周围都有 residual connection 和 layer normalization。而现代 LLM 的具体顺序和归一化方式常有变化比如 pre-norm、RMSNorm、SwiGLU但主线仍然是attention 负责信息交互MLP 负责逐位置加工残差和归一化负责稳定深层网络。一层 Transformer Block 的核心节奏是先交换信息再各自加工。2. 为什么需要 Multi-Head单头 attention 会为每个 token 产生一组注意力权重。这组权重可以表达一种关注分布当前 token 该多看谁少看谁。但是问题在于一句话里的关系常常有很多种相邻词关系、指代关系、修饰关系、语义相关关系都可能同时有用。Multi-Head Attention 的设计目标是让模型在不同表示子空间里并行地做多次 attention。论文里的说法是多头让模型能够同时关注不同位置、不同表示子空间里的信息。用课堂比喻讲就是同一批 token 被分给几个讨论小组每个小组从自己的角度观察同一句话。这里要注意一下某个 head 具体学到什么关系是训练后形成的结果。它可能对局部词更敏感也可能对远距离依赖更敏感还可能呈现更复杂的模式。我们画“局部关系”“语义关系”是在帮助建立直觉真实模型里没有人手工规定 Head 1 必须负责局部、Head 2 必须负责语义。多头带来的价值是把一次注意力拆成多个并行视角。每个视角都能产生自己的上下文结果最后再汇合成一个更丰富的表示。Multi-Head 的核心价值是让同一个 token 同时拥有多个观察上下文的角度。3. Q/K/V 分给多个 head第二章里我们把 Q、K、V 当成单头 attention 的输入。到了 Multi-Head Attention这三组向量还会进入多个 head。每个 head 都有自己的 Q、K、V 子空间然后各自跑一遍 scaled dot-product attention。论文公式通常写成head_iAttention(QW_i^Q,KW_i^K,VW_i^V)MultiHead(Q,K,V)Concat(head_1,...,head_h)W^O这个写法强调第 i 个 head 有自己的一组投影矩阵W_i^Q、W_i^K、W_i^V。工程实现里经常会把所有 head 的投影合在一次大矩阵运算里完成然后把结果 reshape / split 成多个 head。两种视角服务于同一件事让不同 head 拿到自己的 Q/K/V 表示去计算 attention。如果模型维度是d_modelhead 数是h常见设置会让每个 head 的维度大约是d_model / h。这样多个小 head 并行工作最后拼接回来时总宽度仍然能回到模型需要的表示维度。Multi-Head 先把 Q/K/V 放进多个 head 通道每个 head 在自己的子空间里算 attention。4. Head 1看一种关系一个 head 跑 attention 时会像第二章那样完整经历QK 匹配、缩放、mask、softmax、读取 V。区别在于它只在自己的 head 子空间里计算。这样做的结果是每个 head 都会得到一组属于自己的注意力权重。对于同一句话同一个当前 token在 Head 1 里可能更关注相邻词在 Head 2 里可能更关注远处某个名词。注意力权重不同读取到的 V 混合结果也会不同。图里把 Head 1 画成“看一种关系”是一个教学镜头。它想表达的是每个 head 都有机会形成自己的观察模式。这个模式来自训练数据、参数和目标函数共同塑造。从计算上看Head 1 的输出仍然是一个向量。它代表这个 head 从上下文里提取到的信息。后面 concat 时这个向量会和其他 head 的输出并排放在一起。一个 head 会产生一种注意力分布也会产出一份自己的上下文结果。5. Head 2换个角度看Head 2 和 Head 1 的计算流程相同参数和输入子空间不同。因此它可以形成另一组注意力权重也可以读出另一份上下文信息。这就是 Multi-Head 的直觉核心同一个 token 可以同时从多个角度看上下文。一个角度可能偏向近处词一个角度可能偏向远处词一个角度可能更关注某种语义线索。最后这些视角合并起来会比单一视角更有表达力。用“我 喜欢 猫”这种短句做例子某个 head 可能让“我”更多看自己另一个 head 可能让“我”更多看“猫”。这只是一个帮助理解的例子。真实训练里的 head 关注模式会更复杂也会随着层数、任务和模型规模变化。这页的重点是多头提供了并行的观察空间。每个 head 产出的信息都保留下来后面统一拼接和融合。不同 head 可以给同一个 token 提供不同角度的上下文信息。6. 每个 head 自己算 attention每个 head 拿到自己的 Q、K、V 后会独立执行 scaled dot-product attention。它的计算仍然是第二章那条链路Attention(Q_i,K_i,V_i)softmax(Q_iK_i^T/sqrt(d_k))V_i这里的i表示第 i 个 head。每个 head 都会算自己的 score、自己的权重、自己的加权 V最后得到自己的 head output。这些 head 通常可以并行计算。并行是 Multi-Head Attention 在工程上很自然的形态不同 head 的计算互相独立最后再把结果合并。真正实现时框架常用批量矩阵运算一次性完成多个 head 的计算。这一步还有一个重要细节head 数变多以后每个 head 的维度通常会变小。这样总计算量保持在可控范围内同时模型获得多个注意力子空间。多头 attention 的每个 head 都独立完成一次 scaled dot-product attention。7. Concat合并多个 head每个 head 算完 attention 后都会输出一段向量。Concat 做的事很直接把这些 head output 沿着特征维度拼接起来。比如有 3 个 head每个 head 输出一段小向量。Concat 会把它们排成一条更长的向量Concat(head_1,head_2,head_3)这个动作是拼接。它把多个观察结果并排保留下来。它的直觉像把几个讨论小组的记录贴在同一张长纸上每个小组都贡献一段内容长纸上保存了全部小组的观察结果。Concat 之后向量里包含多个 head 的输出。它已经把多种视角汇聚到同一个 token 位置上但这些信息还只是并排放在一起。下一步需要W_O把它们进一步混合和整理。Concat 把多个 head 的输出沿特征维度拼成一个完整表示。8. W_O把多头结果整理好Concat 后的长向量会再乘一个输出投影矩阵W^O。这一步叫 output projection。公式里就是MultiHead(Q,K,V)Concat(head_1,...,head_h)W^OW^O的作用是把拼接后的多头结果线性变换回模型后续需要的表示空间。它会混合不同 head 的信息让多个观察角度能够在同一个输出表示里发生组合。如果只做 concat各个 head 的结果只是简单的揉在了一起。但经过W^O之后模型可以学习怎样综合这些 head哪些信息该加强哪些信息该和其他 head 的信息组合怎样形成下一步子层可以使用的表示。到这里Multi-Head Attention 的主流程就完整了投影得到多组 Q/K/V每个 head 独立跑 attention把 head 输出 concat再经过W^O输出一个 attention 子层结果。后半章会把这个结果接到 FFN、Residual 和 Norm 上形成完整 Transformer Block。W^O负责融合多头结果让多个观察角度变成同一个可继续加工的表示。9. Attention 子层全流程把前面的几页合在一起Multi-Head Attention 子层的主流程就是输入表示 → Q/K/V 投影 → 多个 head 各自算 attention → Concat → W^O → attention output每个 token 进入这一层时都带着当前层的表示。模型先通过线性投影得到 Q、K、V再把它们分到多个 head。每个 head 在自己的子空间里计算注意力权重并按权重混合 V。然后所有 head 的输出被拼接起来经过W^O融合得到这一层 attention 子层的输出。这一步解决的是“token 之间怎么交换信息”。如果当前 token 需要理解上下文它就不能只盯着自己。attention 子层让每个 token 都从可见 token 那里收集信息多头机制让这种收集可以从多个角度同时发生。注意这里说的是 attention 子层。完整 Transformer Block 后面还有 FFN、Residual、Norm 等结构。attention output 只是中间结果后续模块会继续加工它。Attention 子层负责让 token 之间交换上下文信息。10. FFN每个 token 自己加工attention 子层负责让 token 互相看见。FFN 负责让每个 token 对自己的表示做进一步加工。原始 Transformer 论文把它叫 position-wise feed-forward network。position-wise 的意思是它分别作用在每个位置上。每个 token 都会经过同一套 FFN 参数但不同 token 之间在这一步没有互相读取信息。原始论文中的 FFN 由两层线性变换和中间的 ReLU 激活组成FFN(x)max(0,xW_1b_1)W_2b_2现代 LLM 里这个模块常被叫作 MLP也经常使用 SwiGLU、GEGLU 等门控变体。名字和细节会变但主线很稳定attention 先把上下文信息带进来FFN 再对每个位置的表示做非线性加工。Attention 负责交流FFN 负责逐位置加工。11. 激活函数有选择地加工FFN 里需要激活函数因为两层线性变换直接连在一起本质上仍然可以合并成一次线性变换。激活函数引入非线性让模型能表达更复杂的关系。用图里的“加工门”理解就够了向量进来以后有些信号会被保留或放大有些信号会被压低。这样 FFN 就不只是把向量换个坐标系而是在做有选择的特征加工。原始 Transformer 使用 ReLU。很多现代 LLM 使用门控激活例如 SwiGLU。它们的具体公式不同但承担的角色相近让 FFN 的表达能力更强。这里要避免一个误解激活函数不是在读上下文。上下文交换主要发生在 attention 子层。激活函数位于 FFN / MLP 内部作用在每个 token 自己的表示上。激活函数给 FFN 加上非线性让表示加工更有表达力。12. Residual保留原来的自己Residual connection 的核心动作很简单把子层输入加回子层输出。原始 Transformer 论文对每个子层使用的形式是LayerNorm(xSublayer(x))这里的x是子层输入Sublayer(x)是 attention 或 FFN 的输出。相加以后原来的表示有一条直达通道新加工出来的信息也能叠加进去。直觉上残差连接让模型每一层都不用从零开始改写 token。它可以在原表示基础上补充新信息。这样很多层堆起来时信息更容易穿过网络训练也更稳定。现代 Transformer 常见 pre-norm 结构会把 Norm 放在子层前面残差相加的位置也会随架构写法变化。但 residual 的核心不变保留输入路径把子层产生的新信息加回来。Residual 让旧信息有直达通道新信息通过相加叠加进去。13. Norm让表示更稳定Transformer 会堆很多层。每层都在做投影、注意力、FFN 和相加如果表示的数值尺度一路乱跑后面的层就更难稳定工作。Norm 的作用是让每层附近的表示尺度更可控。原始 Transformer 使用 LayerNorm并且放在 residual 相加之后。很多现代 LLM 使用 pre-norm也就是先归一化再进入 attention 或 FFN不少现代模型还使用 RMSNorm。具体实现不同但它们都在解决同一个工程问题让深层网络里的表示保持稳定。图里把 Norm 画成校准台是为了表达这个直觉。它不是把 token 的语义变成统一答案也不是清空信息。它是在数值层面调整表示让后续计算更容易处理。写正文和看模型结构图时要留意两个差异一种是 Norm 类型比如 LayerNorm 或 RMSNorm另一种是 Norm 位置比如 post-norm 或 pre-norm。不同模型会有不同选择。Norm 帮助深层 Transformer 维持更稳定的表示尺度。14. 一层 Transformer Block现在可以把一层 Transformer Block 串起来了。常见现代 decoder-only block 可以用这条主线理解输入表示 → Norm → Multi-Head Attention → Residual Add → Norm → FFN/MLP → Residual Add → 输出表示这个结构里attention 子层让 token 交换上下文信息FFN / MLP 子层对每个 token 的表示做进一步加工Residual 把输入路径保留下来Norm 控制表示尺度。四类模块配合起来构成一层完整的表示更新。原始 Transformer 的论文结构更接近 post-norm子层输出先和输入相加再做 LayerNorm。现代 LLM 大量使用 pre-norm。你现在不用急着记住所有变体先抓住稳定主线attention 负责交流FFN 负责加工Residual 和 Norm 负责让多层堆叠可训练、可运行。Block 的输出仍然是一串 token 表示。序列长度没有变每个位置都有自己的新表示只是这些表示已经吸收了本层带来的上下文信息和非线性加工。一层 Block 完成一次“交流 加工”的表示更新。15. 多层堆叠表示越来越深一个 Transformer 通常会堆很多层 Block。第 1 层输出的表示会作为第 2 层输入第 2 层输出再进入第 3 层。每一层都重复 attention、FFN、Residual、Norm 这套节奏。堆叠的意义是让 token 表示逐层变丰富。浅层可能更多处理局部线索和较直接的模式越往后表示里可能融合更大范围、更抽象的上下文信息。这里的“更深语义”是对表示层级的直觉描述具体每层学到什么由训练和模型结构决定。从第一章到这里整条线咱们已经打通了token 变成向量带上位置进入模型self-attention 让它读取上下文multi-head 让它从多个角度读取FFN 继续加工Residual 和 Norm 让这些模块可以堆很多层。最终模型在最后一层拿到更丰富的 token 表示再进入后续预测下一个 token 的流程。第三章到这里完成了一个关键转折我们已经从“attention 是什么”走到“一层 Transformer 怎么工作”。下一章会把视角切到现代 LLM 生成decoder-only、causal mask、自回归生成、logits 和 sampling。多层 Block 让 token 表示经过多次交流和加工逐步变得更丰富。码字不易欢迎大家点赞关注评论谢谢