深度学习进阶(四)Transformer 整体结构
<p>在上一篇中,我们已经完整展开了 Transformer Block 的内部结构,包括多头注意力、残差连接、LayerNorm 以及 FFN。</p><p>至此,就可以正式进入 Transformer 的整体结构了。<br>
在原论文中,Transformer 本身仍是 <strong>Encoder–Decoder 架构</strong>,其中编码器的内容在 Transformer Block 中已经较为详细地展开了,而解码器也只是在一些细节上有些不同,<strong>本质上仍是对自注意力和前馈网络的综合应用</strong>。</p>
<p>其整体流程如下:</p>
<p></p><div class="math display">\[\text{输入序列} \rightarrow \text{Encoder堆叠} \rightarrow \text{上下文表示} \rightarrow \text{Decoder堆叠} \rightarrow \text{预测序列}
\]</div><p></p><p><img src="https://img2024.cnblogs.com/blog/3708248/202604/3708248-20260406091540617-1317089171.png" alt="image.png" loading="lazy"></p>
<p>下面就来详细展开其具体内容:</p>
<h1 id="1-encoder">1. Encoder</h1>
<p>首先是 Encoder 部分,我们在前面已经提到过,Encoder 并不是一个单层结构,而是<strong>多个 Transformer Block 的堆叠</strong>,就像这样:</p>
<p></p><div class="math display">\[\text{Encoder} = \underbrace{\text{Block} \rightarrow \text{Block} \rightarrow \cdots \rightarrow \text{Block}}_{N\ \text{层}}
\]</div><p></p><p>原论文中设置 <span class="math inline">\(N = 6\)</span>,而实际模型和一些变体中则可以更深。</p>
<p>再简单展开一下数据在 Encoder 中的传播过程:</p>
<ol>
<li>输入处理:</li>
</ol>
<p></p><div class="math display">\[\mathbf{X} = \mathbf{E}_{embedding} + \mathbf{E}_{pos}
\]</div><p></p><ol start="2">
<li>经过多层 Transformer Block:</li>
</ol>
<p></p><div class="math display">\[\mathbf{X} \rightarrow \mathbf{H}_1 \rightarrow \mathbf{H}_2 \rightarrow \cdots \rightarrow \mathbf{H}_N
\]</div><p></p><p><strong>最终得到的<span class="math inline">\(\mathbf{H}_N\)</span> 就是融合了全局上下文信息的序列表示。</strong><br>
Encoder 的具体过程就如在上一篇Transformer Block所演示的,就不再赘述了。<br>
我们把重点放在下面对 Decoder 的细节阐述上。</p>
<h1 id="2-decoder">2. Decoder</h1>
<p>现在,我们已经有了对输入序列的编码表示,那么下面要进行的自然就是解码的过程。<br>
而在上面的网络结构图中,你会发现 Decoder 的结构设计中出现了一种之前没提过的的自注意力机制:<strong>Masked Self-Attention</strong>,中文翻译为<strong>带掩码的自注意力</strong>。<br>
我们先来展开这一部分:</p>
<h2 id="21-masked-self-attention">2.1 Masked Self-Attention</h2>
<p>显然,带掩码的自注意力的重点在这个 <strong>mask</strong> 上,我们直接来看看它的公式:</p>
<p></p><div class="math display">\[\mathrm{Attention}(Q,K,V)=\mathrm{softmax}\left(\frac{QK^T}{\sqrt{d_k}} + M\right)V
\]</div><p></p><p>你会发现,相比普通的自注意力 ,Attention 计算中加入了一个<strong>掩码矩阵 <span class="math inline">\(M\)</span></strong>。<br>
而这个矩阵的设计是这样的:</p>
<p></p><div class="math display">\[M_{ij} = \begin{cases}
0, & \text{if } j \le i \\
-\infty, & \text{if } j > i
\end{cases}
\]</div><p></p><p>这是什么意思?来看一个简单例子:<br>
假设序列长度为 4,则 mask 矩阵如下:</p>
<p></p><div class="math display">\[M =
\begin{bmatrix}
0 & -\infty & -\infty & -\infty \\
0 & 0 & -\infty & -\infty \\
0 & 0 & 0 & -\infty \\
0 & 0 & 0 & 0
\end{bmatrix}
\]</div><p></p><p>现在, 问题来了:</p>
<blockquote>
<p><strong>这个矩阵到底是干什么的?为什么被称为掩码?</strong></p>
</blockquote>
<p>这里要先回顾一下 Softmax 函数:</p>
<p></p><div class="math display">\}}}
\]</div><p></p><p>你会发现,当输入趋向于 <span class="math inline">\(-\infty\)</span> 时,其对应的指数值 <span class="math inline">\(e^{-\infty}\)</span> 趋向于 0,而在注意力计算中,就会使得该位置的<strong>概率权重变为 0</strong>。</p>
<p>以矩阵的<strong>第 1 行</strong>(对应序列的第 1 个位置)为例:这一行的掩码是 <span class="math inline">\(\)</span>。<br>
当模型在生成或处理第 1 个词时,对于第 2、3、4 个位置的词,由于 Softmax 的作用,它们的注意力分数会被强制变为 0,不为最终表示做贡献。<br>
<strong>也就是相当于:第 1 个词只能“看见”第 1 个词本身的信息。</strong></p>
<p>以此类推,第 2 个词只能“看见”第 1、2 个词的信息;第 3 个词只能“看见”第 1、2、3 个词的信息······<strong>每个词都看不到自己之后的信息。</strong></p>
<p>而为什么要这样设计,还是要回到 Transformer 的解码逻辑部分:<br>
<img src="https://img2024.cnblogs.com/blog/3708248/202604/3708248-20260406091549631-724897159.png" alt="image.png" loading="lazy"><br>
<strong>你会发现,这种掩码设计其实也是在放弃 RNN 后的必要措施,这样我们就在拥有了传统RNN 没有的并行能力情况下,确保了正确的训练逻辑。</strong><br>
如果不加限制,在计算“爱”这个位置时模型可以直接看到“你”,那么模型就会学会一种“作弊方式”:<strong>直接复制未来信息,而不是学习生成规律。</strong><br>
这可能会让指标看起来不错,但实际上是绝对无法使用的。</p>
<p>总结来说,这种设计被称为<strong>因果掩码</strong>,它保证了在训练和推理过程中,Decoder 在预测第 <span class="math inline">\(i\)</span> 个位置的输出时,<strong>只能依赖于第 <span class="math inline">\(i\)</span> 个位置之前的已知输出</strong>,而无法“偷看”到未来的信息。</p>
<p>这便是 decoder 的第一个部分,而在这之后,它还有一个细节。</p>
<h2 id="22-cross-attention">2.2 Cross-Attention</h2>
<p>展开标题前,我们先来看看整体网络图中的一个细节:<br>
<img src="https://img2024.cnblogs.com/blog/3708248/202604/3708248-20260406091546219-495032664.png" alt="image.png" loading="lazy"></p>
<p>你会发现,在自注意力中,<span class="math inline">\(Q\)</span> , <span class="math inline">\(K\)</span> , <span class="math inline">\(V\)</span> 通常来自同一个输入序列。<br>
但在解码器的这一步,它们的来源发生了变化:</p>
<ul>
<li><strong><span class="math inline">\(Q\)</span>来自 Decoder 上一层的输出。</strong> 它代表了“Decoder 现在想要关注什么”。</li>
<li><strong><span class="math inline">\(K\)</span> 和 <span class="math inline">\(V\)</span>:</strong> 来自 <strong>Encoder 的最终输出</strong>。它们代表了“输入序列中包含了什么信息”。</li>
</ul>
<p><strong>这种非同源的注意力计算,我们就称之为 Cross-Attention,即跨注意力。</strong><br>
它的计算公式与标准 Attention 一致,但语义不同:</p>
<p></p><div class="math display">\[\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
\]</div><p></p><p>我们以机器翻译为例,从语义角度来理解一下这个逻辑:</p>
<ol>
<li><strong>提问:</strong> Decoder 生成了一个 <span class="math inline">\(Q\)</span> 向量,意思是:“我现在正在翻译第 <span class="math inline">\(i\)</span> 个词,我需要寻找与‘动作’或‘过去时’相关的信息。”</li>
<li><strong>匹配:</strong> 这个 <span class="math inline">\(Q\)</span> 会去与 Encoder 输出的所有 <span class="math inline">\(K\)</span> 向量进行点积计算,计算它们之间的相关性,意思是:“在提供的编码中挨个找相关信息”。</li>
<li><strong>获取:</strong> 根据计算出的相关性权重,对 Encoder 输出的 <span class="math inline">\(V\)</span> 向量进行加权求和,意思是:“根据需要获取信息”。</li>
</ol>
<p><strong>一句话总结这个逻辑就是:用当前位置的预测需求从编码结果中获取信息。</strong></p>
<p>再具体一点,假设我们在做英译中任务,Decoder 正在生成中文的“爱”字。<br>
首先,它的 <span class="math inline">\(Q\)</span> 会去询问 Encoder 中的英文单词,发现英文单词 "Love" 的 <span class="math inline">\(K\)</span> 与它的 <span class="math inline">\(Q\)</span> 最匹配。<br>
于是,它从 "Love" 对应的 <span class="math inline">\(V\)</span> 中提取了语义特征。<br>
最终,Decoder 结合了自身的上下文和从 Encoder 拿到的“爱”的语义特征,成功输出了“爱”。</p>
<p>通过这种机制,Decoder 既保持了生成序列的自回归特性(只能看过去),又能够充分利用 Encoder 编码的完整输入信息,实现了“理解输入,生成输出”的完美闭环。</p>
<h2 id="23-整体解码逻辑">2.3 整体解码逻辑</h2>
<p>在分别理解了 Masked Self-Attention 和 Cross-Attention 之后,我们可以把 Decoder 的一层结构完整串起来。</p>
<p>我们用统一的符号 <span class="math inline">\(\mathbf{Y}_{in}\)</span> 来表示 Decoder 的输入,它在训练中代表右移对齐的标签信息,在推理中则是自回归的历史信息。<br>
同时用 <span class="math inline">\(\mathbf{H}\)</span> 表示 Encoder 的输出。<br>
那么 Decoder 的传播过程可以写为:</p>
<p></p><div class="math display">\[\mathbf{Z}_1 = \mathrm{LayerNorm}\left(\mathbf{Y}_{in} + \mathrm{MaskedMultiHead}(\mathbf{Y}_{in})\right)
\]</div><p></p><p>这一层的作用是: <strong>在不看未来的前提下,对当前已生成序列进行内部建模。</strong><br>
继续下一步:</p>
<p></p><div class="math display">\[\mathbf{Z}_2 = \mathrm{LayerNorm}\left(\mathbf{Z}_1 + \mathrm{MultiHead}(Q, K, V\right))
\]</div><p></p><p>其中:</p>
<p></p><div class="math display">\[Q = \mathbf{Z}_1 W_Q,\quad K = \mathbf{H} W_K,\quad V = \mathbf{H} W_V
\]</div><p></p><p>这一层是<strong>在当前生成状态的基础上,引入输入序列的语义信息</strong>。<br>
最后:</p>
<p></p><div class="math display">\[\mathbf{Y}_{out} = \mathrm{LayerNorm}\left(\mathbf{Z}_2 + \mathrm{FFN}(\mathbf{Z}_2)\right)
\]</div><p></p><p>和 encoder 中的前馈网络同理,这是<strong>对融合后的特征进行非线性变换和聚合</strong>。</p>
<p>最终,和 Encoder 一样,Decoder 也不是单层结构,而是多层堆叠形成更深的网络:</p>
<p></p><div class="math display">\[\text{Decoder} = \underbrace{\text{Block} \rightarrow \text{Block} \rightarrow \cdots \rightarrow \text{Block}}_{N\ \text{层}}
\]</div><p></p><p>这里每一层都会不断强化当前生成序列的上下文信息,从而更精准地对齐输入序列的语义,得到 <span class="math inline">\(\mathbf{Y}_{final}\)</span> 。<br>
经过最后一步映射:</p>
<p></p><div class="math display">\[\mathbf{P} = \mathrm{softmax}(\mathbf{Y}_{final} \mathbf{W} + \mathbf{b})
\]</div><p></p><p>这就是最终的输出,即对预测 token 的概率分布。</p>
<h1 id="3-总结">3. 总结</h1>
<p>到这里,我们已经从内部结构到整体架构,完整地拆解了<strong>原始</strong> Transformer 的设计逻辑。Transformer 的核心作用可以概括为:<strong>提供了一种基于 Attention 的通用序列建模框架</strong>。</p>
<p>相比传统方法,它最关键的突破在于<strong>用注意力替代了递归</strong>,使得任意两个位置之间都可以直接建立联系,不再依赖逐步传递的信息路径,从而能够更加高效地建模长距离依赖。<br>
同时,它<strong>通过 Mask 机制在并行计算的前提下保留了序列的因果约束</strong>,使得原本必须串行处理的序列建模问题可以被改写为可并行的矩阵计算,这也是 Transformer 能够在大规模数据与大模型训练中取得成功的重要原因。</p>
<p>从更抽象的角度来看,Transformer 的本质可以理解为一个“<strong>基于查询的信息检索系统</strong>”:</p>
<ol>
<li><span class="math inline">\(Q\)</span> 表示当前需要的信息。</li>
<li><span class="math inline">\(K\)</span> 表示信息所在的位置。</li>
<li><span class="math inline">\(V\)</span> 则承载具体的信息内容。</li>
</ol>
<p><strong>整个计算过程就是不断地根据当前状态发起查询,在上下文中匹配相关信息并进行加权融合,从而更新表示。</strong> 这种机制使得模型具备了极强的表达能力与灵活性,也使得其不仅局限于自然语言处理任务,而可以推广到更广泛的序列与结构化数据建模问题中。</p>
<p>虽然原始 Transformer 采用的是 Encoder–Decoder 架构,但在后续发展中,<strong>这一结构逐渐被解耦并形成了不同的应用范式。</strong><br>
一类是仅保留 Encoder 的结构,这类模型通常用于<strong>理解任务</strong>,能够同时利用序列的前后信息进行建模。<br>
另一类是仅保留 Decoder 的结构,通过因果掩码实现严格的自回归生成,专注于<strong>序列生成</strong>任务。<br>
当然,仍然存在完整的 Encoder–Decoder 结构,用于处理输入输出结构不同的<strong>序列转换</strong>问题。</p>
<p>总体来看,Transformer 的核心意义在于更在于<strong>它重新定义了序列建模的基本方式</strong>:不再依赖递归路径或局部感受野,而是通过全局注意力机制直接建模任意位置之间的关系。<br>
这种思想上的转变,使得后续几乎所有主流模型都在不同程度上继承或扩展了Transformer 的设计理念。</p><br><br>
来源:https://www.cnblogs.com/Goblinscholar/p/19825358
頁:
[1]