<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Attention Is All You Need on 一知半解</title>
        <link>https://oi8io.cn/tags/attention-is-all-you-need/</link>
        <description>Recent content in Attention Is All You Need on 一知半解</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <copyright>CC BY-NC-SA 4.0</copyright>
        <lastBuildDate>Thu, 29 Oct 2026 00:42:00 +0800</lastBuildDate><atom:link href="https://oi8io.cn/tags/attention-is-all-you-need/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Attention Is All You Need 论文解读</title>
            <link>https://oi8io.cn/ai/transformer-paper-guide/</link>
            <pubDate>Thu, 29 Oct 2026 00:42:00 +0800</pubDate>
            <guid>https://oi8io.cn/ai/transformer-paper-guide/</guid>
            <description>&lt;img src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/cover.jpg&#34; alt=&#34;Featured image of post Attention Is All You Need 论文解读&#34; /&gt;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;今天你用到的几乎所有大语言模型——GPT、Claude、Llama、通义、豆包、DeepSeek——都站在同一篇 2017 年的论文上。这篇文章不堆公式，而是沿着一条主线，把 Transformer 从“为什么需要它”一路讲到“它内部每一块在干什么”。&lt;/p&gt;&#xA;&lt;p&gt;读完你应该能回答一个问题：&lt;strong&gt;为什么 2017 年之前，我们没有迎来大模型时代？&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;写在前面&#34;&gt;写在前面&#xA;&lt;/h2&gt;&lt;p&gt;全文会反复用到视频里的一个例子：把中文 &lt;strong&gt;“我爱水课”&lt;/strong&gt; 翻译成英文 &lt;strong&gt;“I love easy courses”&lt;/strong&gt;。“水课”是大学生的黑话，意思是轻松好过的课。这个例子有个坑：“水”单独看是 water，只有结合后面的“课”，才知道它在这里是 easy。机器能不能跳过这个坑，正好检验它是不是真的“读懂了上下文”。&lt;/p&gt;&#xA;&lt;p&gt;论文本身的结构是：先讲以前的模型有什么问题（第 1、2 节），再讲 Transformer 的结构（第 3 节），然后回答“为什么用自注意力”（第 4 节），最后是训练和实验结果。我们也按这个顺序走，只是在读论文之前，先把它默认你懂的那些背景补上——论文总是默认你什么都懂。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;从 FNN 到 Transformer 的演进路线&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;750px&#34; data-flex-grow=&#34;312&#34; height=&#34;640&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/01-roadmap.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/01-roadmap_hu_8b51fdb7b38bbbfa.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/01-roadmap_hu_d3a941558926ddeb.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/01-roadmap.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;上面这张图就是前半篇的地图。每一代模型都解决了上一代的一些问题，又留下新的问题。Transformer 的出现，就是为了填上最后那个坑。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;1-transformer-出现之前&#34;&gt;1 Transformer 出现之前&#xA;&lt;/h2&gt;&lt;h3 id=&#34;11-先搞清楚任务什么是序列转导&#34;&gt;1.1 先搞清楚任务：什么是“序列转导”&#xA;&lt;/h3&gt;&lt;p&gt;论文摘要的第一句话是：&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;The dominant sequence transduction models are based on complex recurrent or convolutional neural networks that include an encoder and a decoder.&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;“序列转导模型”（sequence transduction model）听起来很玄，其实就是&lt;strong&gt;把一个序列变成另一个序列的模型&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;什么是序列？就是&lt;strong&gt;顺序有意义&lt;/strong&gt;的数据。最典型的就是语言：“水是有毒的”和“有毒的是水”用的是同样几个字，意思却完全不同。机器翻译（中文序列 → 英文序列）、对话（问题序列 → 回答序列）、文本摘要（长序列 → 短序列），都是序列转导任务。&lt;/p&gt;&#xA;&lt;p&gt;所以这句话的意思是：在这篇论文之前，主流的序列转导模型有三个特点——&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;基于循环神经网络（RNN）或卷积神经网络（CNN），其中绝大多数是 RNN；&lt;/li&gt;&#xA;&lt;li&gt;采用“编码器-解码器”结构；&lt;/li&gt;&#xA;&lt;li&gt;表现最好的那些，还会用“注意力机制”把编码器和解码器连起来。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;而这篇论文提出的 Transformer，&lt;strong&gt;完全扔掉了 RNN 和 CNN，只靠注意力机制&lt;/strong&gt;（仍然保留了编码器-解码器的大框架）。&lt;/p&gt;&#xA;&lt;p&gt;要理解这为什么是革命性的，我们得先看看 RNN、编码器-解码器、注意力机制分别是什么，它们各自解决了什么问题，又卡在了哪里。&lt;/p&gt;&#xA;&lt;h3 id=&#34;12-机器怎么看文字分词与词嵌入&#34;&gt;1.2 机器怎么“看”文字：分词与词嵌入&#xA;&lt;/h3&gt;&lt;p&gt;在讲任何神经网络之前，有个绕不开的前置步骤：计算机只认数字，文字得先变成数字。&lt;/p&gt;&#xA;&lt;p&gt;第一步叫&lt;strong&gt;分词&lt;/strong&gt;（tokenization），把句子切成一个个小单元，叫 &lt;strong&gt;token&lt;/strong&gt;。初学时你可以把 token 简单理解成“词”。比如“水是有毒的”切成 &lt;code&gt;[&amp;quot;水&amp;quot;, &amp;quot;是&amp;quot;, &amp;quot;有毒&amp;quot;, &amp;quot;的&amp;quot;]&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;第二步叫&lt;strong&gt;词嵌入&lt;/strong&gt;（embedding），给每个 token 分配一个向量，也就是一串数字。在 Transformer 里，这个向量有 512 个数，我们说它是“512 维”的。&lt;/p&gt;&#xA;&lt;p&gt;为什么要用这么长的向量，而不是给每个词编个号（水=1，是=2……）？因为向量可以表达“意思上的远近”。你可以把 512 维空间想象成一张巨大的地图，每个词是地图上的一个点：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;词嵌入：意思相近的词在空间里挨得近&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;398px&#34; data-flex-grow=&#34;165&#34; height=&#34;940&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/02-embedding.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/02-embedding_hu_3c635903375c583c.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/02-embedding.png 1560w&#34; width=&#34;1560&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;“水”“河流”“瀑布”会聚在一块，“大学生”“论文”“作业”聚在另一块。两个词的向量方向越接近，意思通常也越接近。机器就是靠这种几何关系，来“感知”词语之间的相似性。&lt;/p&gt;&#xA;&lt;p&gt;这些向量不是人手工写的，而是在训练中学出来的。早期常用别人训练好的词向量直接拿来用；而在 Transformer 这类模型里，词嵌入表通常和整个模型一起训练、一起调整，效果更好。&lt;/p&gt;&#xA;&lt;p&gt;好，有了词向量，我们可以开始往神经网络里喂东西了。&lt;/p&gt;&#xA;&lt;h3 id=&#34;13-第一站前馈神经网络一口吞不下句子&#34;&gt;1.3 第一站：前馈神经网络，一口吞不下句子&#xA;&lt;/h3&gt;&lt;p&gt;学机器学习时最先接触的网络，叫&lt;strong&gt;前馈神经网络&lt;/strong&gt;（Feedforward Neural Network，FNN）。结构非常简单：输入层 → 隐藏层 → 输出层，数据从左往右流一遍就结束。中间每一层都是“乘一个权重矩阵、再过一个非线性函数”。&lt;/p&gt;&#xA;&lt;p&gt;问题在于，FNN 的输入层大小是&lt;strong&gt;固定&lt;/strong&gt;的。它像一个形状固定的插槽，只能插进固定长度的向量。可句子有长有短，怎么塞进去？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;前馈网络处理不了句子的两个原因&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;558px&#34; data-flex-grow=&#34;232&#34; height=&#34;860&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/03-fnn.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/03-fnn_hu_8a0989590e86a558.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/03-fnn_hu_a0c2e1acfd371ffc.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/03-fnn.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;最直接的办法有两个，但都不太行：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;取平均&lt;/strong&gt;：把所有词向量逐位平均成一个向量。长度倒是固定了，但顺序信息全丢了——“水是有毒的”和“有毒的是水”算出来一模一样。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;首尾拼接&lt;/strong&gt;：把 4 个 4 维向量拼成一个 16 维的。可句子一变长，输入层就得跟着变；你总不能为了可能出现的最长句子，准备一个巨大无比的输入层。更要命的是，拼接后整句仍然是“一次性整块”塞进去的，网络并不理解谁先谁后。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所以 FNN 在序列任务面前有两个硬伤：&lt;strong&gt;不支持不定长的输入，也建模不了词序&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;14-第二站rnn一个词一个词地读&#34;&gt;1.4 第二站：RNN，一个词一个词地读&#xA;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;循环神经网络&lt;/strong&gt;（Recurrent Neural Network，RNN）的想法很像人读句子：不是一眼吞下整句，而是一个词一个词地读，边读边记。&lt;/p&gt;&#xA;&lt;p&gt;它的结构相对 FNN 改动很小，只是在隐藏层上加了一个“圈”：这一步算出的结果，会作为下一步输入的一部分。把这个圈按时间展开，就是下面这样：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;RNN 按时间展开&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;512px&#34; data-flex-grow=&#34;213&#34; height=&#34;900&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/04-rnn.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/04-rnn_hu_e0c4263d040d8a2e.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/04-rnn_hu_d40c2f0c72cedcac.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/04-rnn.png 1920w&#34; width=&#34;1920&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;拿“我爱水课”来走一遍：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;第 1 步，输入“我”的向量 $x_1$，和一个初始记忆 $h_0$ 一起算出新的记忆 $h_1$，再由 $h_1$ 算出这一步的输出 “I”。&lt;/li&gt;&#xA;&lt;li&gt;第 2 步，输入“爱”，和上一步的记忆 $h_1$ 一起算出 $h_2$，再输出 “love”。&lt;/li&gt;&#xA;&lt;li&gt;以此类推。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;写成公式就是：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;h_t = g(W x_t + U h_{t-1}), \qquad y_t = g(V h_t)&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;$x_t$ 是第 $t$ 步的输入，$h_t$ 是第 $t$ 步的“记忆”（论文里叫隐藏状态 hidden state），$y_t$ 是输出；$W$、$U$、$V$ 是三个权重矩阵，&lt;strong&gt;每一步用的都是同一套&lt;/strong&gt;；$g$ 是激活函数，给网络引入非线性。&lt;/p&gt;&#xA;&lt;p&gt;所以每一步其实有两个产出：一个是给下一步用的记忆 $h_t$，负责把前面读过的信息往后带；一个是这一步实际的输出 $y_t$。&lt;/p&gt;&#xA;&lt;p&gt;RNN 一口气解决了 FNN 的三个问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;能建模词序&lt;/strong&gt;：词是按顺序一个个进来的，顺序不同，算出的结果就不同；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;能建模上下文依赖&lt;/strong&gt;：有 $h_t$ 这条“记忆链”，读到后面时还记得前面；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;支持不定长输入&lt;/strong&gt;：句子多长都行，多读几步而已。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;但你应该已经发现一个问题了：输入 4 个词，就输出 4 个词。可翻译哪有这么整齐？“我爱水课”是 4 个字，换个说法翻成 “I really enjoy easy courses” 就是 5 个词。&lt;strong&gt;输入和输出不等长时怎么办？&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;15-第三站编码器-解码器先读完再写&#34;&gt;1.5 第三站：编码器-解码器，先读完再写&#xA;&lt;/h3&gt;&lt;p&gt;2014 年的 Seq2Seq（Sutskever 等人）给出的答案是：把 RNN 拆成两半。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;编码器-解码器结构&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;510px&#34; data-flex-grow=&#34;212&#34; height=&#34;940&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/05-seq2seq.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/05-seq2seq_hu_9150f368662d4a78.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/05-seq2seq_hu_58f8113e954cbdd7.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/05-seq2seq.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;编码器&lt;/strong&gt;（Encoder）只管读：它就是一个去掉了输出 $y$ 的 RNN，从头到尾把原文读一遍，最后得到一个&lt;strong&gt;上下文向量&lt;/strong&gt; $C$。最简单的做法就是直接拿最后一步的记忆当 $C$，即 $C = h_4$。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;解码器&lt;/strong&gt;（Decoder）只管写：它是另一个 RNN，拿着 $C$ 作为起点，一个词一个词地生成译文。每生成一个词，就把它当作下一步的输入，直到生成“结束”符号为止。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;为什么 $C$ 能代表整句话？因为编码器是按顺序一步步读下来的，每一步的记忆都融合了之前所有词的信息，最后的 $h_4$ 自然就包含了整句的语义，也隐含了词序。&lt;/p&gt;&#xA;&lt;p&gt;这样一来，读和写彻底分开，&lt;strong&gt;输入和输出可以不一样长&lt;/strong&gt;了。&lt;/p&gt;&#xA;&lt;p&gt;但新问题又来了，而且有两个。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;第一个问题：遗忘。&lt;/strong&gt; 整句话无论多长，都得挤进一个固定长度的向量 $C$ 里。而 $C = h_4$ 显然受离它近的词影响更大：“水”和“课”刚读完，印象深刻；“我”要经过好几步传递才到达 $h_4$，每传一步都被稀释一点。句子越长，开头的信息丢得越多。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;第二个问题：不分轻重。&lt;/strong&gt; 解码器写每一个词时，看的都是同一个 $C$。可写 “I” 的时候最该关注“我”，写 “easy” 的时候最该关注“水”和“课”。所有词被一视同仁，模型就很容易犯错——比如把“水课”翻成 water courses。&lt;/p&gt;&#xA;&lt;h3 id=&#34;16-第四站注意力机制写每个词时回头看重点&#34;&gt;1.6 第四站：注意力机制，写每个词时回头看重点&#xA;&lt;/h3&gt;&lt;p&gt;2014 年，Bahdanau 等人提出了&lt;strong&gt;注意力机制&lt;/strong&gt;（Attention）。要注意，注意力机制在 Transformer 之前就已经存在了；Transformer 的创新是“自注意力”，这个后面会讲。&lt;/p&gt;&#xA;&lt;p&gt;注意力的想法很朴素：既然解码器每一步关心的重点不同，&lt;strong&gt;那就别给它同一个 $C$ 了，每一步单独配一个&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;具体做法是，保留编码器每一步的记忆 $h_1, h_2, h_3, h_4$，解码器每写一个词时，都重新给这几个记忆分配一组权重，再加权求和，得到这一步专属的上下文：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;注意力机制：生成 easy 时的权重分配&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;461px&#34; data-flex-grow=&#34;192&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/06-attention.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/06-attention_hu_16eebd15f1d541e9.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/06-attention_hu_c021c397495e774.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/06-attention.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;比如生成 “easy” 这一步，我们希望模型同时注意到“水”和“课”，别把“水”孤立地译成 water，于是给它们都分配较大的权重：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;C_2 = 0.1,h_1 + 0.1,h_2 + 0.4,h_3 + 0.4,h_4&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;一般地，第 $i$ 步的上下文是 $C_i = \sum_j \alpha_{ij} h_j$，其中权重 $\alpha_{ij}$ 都是非负数，加起来等于 1。这些权重不是人定的，而是模型根据“当前要写什么”和“原文每个位置是什么”自己算出来的。&lt;/p&gt;&#xA;&lt;p&gt;这一招一次解决了两个问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;遗忘问题缓解了&lt;/strong&gt;：哪怕是句子开头的词，只要它重要，就能直接分到大权重，不用再经历层层传递的稀释；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;轻重问题解决了&lt;/strong&gt;：每一步都有自己的关注重点。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;到这里，我们已经把论文摘要里“以前的模型”的三个特点全讲完了：基于 RNN，采用编码器-解码器结构，用注意力机制连接编码器和解码器。&lt;/p&gt;&#xA;&lt;h3 id=&#34;17-还剩最后一个坑串行计算&#34;&gt;1.7 还剩最后一个坑：串行计算&#xA;&lt;/h3&gt;&lt;p&gt;注意力机制让翻译质量提升了一大截，但它是“装”在 RNN 上的，RNN 的一个根本缺陷还在：&lt;strong&gt;它必须排队计算&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;RNN 必须排队，Transformer 训练时可以同时开工&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;510px&#34; data-flex-grow=&#34;212&#34; height=&#34;940&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/07-serial-vs-parallel.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/07-serial-vs-parallel_hu_d55ce88b3ac62d65.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/07-serial-vs-parallel_hu_82c9b636e2fb1b56.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/07-serial-vs-parallel.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;想得到 $h_4$，必须先有 $h_3$；想得到 $h_3$，必须先有 $h_2$……每一步都依赖上一步的结果。解码也一样，要生成 “easy”，必须等 “I love” 先生成完。&lt;/p&gt;&#xA;&lt;p&gt;这在计算上意味着什么？GPU 的强项是“同时做大量相同的运算”，几千个计算核心一起开工。可 RNN 的计算是一条单行道，再多的核心也只能一个接一个地等。句子越长，等得越久；训练数据越多，这个瓶颈就越致命。&lt;/p&gt;&#xA;&lt;p&gt;论文第 1 节说的正是这一点：&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;This inherently sequential nature precludes parallelization within training examples, which becomes critical at longer sequence lengths.&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;（这种固有的顺序性，使得单个训练样本内部无法并行；序列越长，问题越严重。）&lt;/p&gt;&#xA;&lt;p&gt;现在回头看那张路线图，我们可以把前面所有的问题列成一张清单：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;问题&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th style=&#34;text-align: center&#34;&gt;FNN&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th style=&#34;text-align: center&#34;&gt;RNN&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th style=&#34;text-align: center&#34;&gt;+编码器-解码器&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th style=&#34;text-align: center&#34;&gt;+注意力&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;建模词序&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;建模上下文依赖&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;支持不定长输入&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;输入输出可以不等长&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;长序列不“遗忘”&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;分得清不同位置的重要性&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✓&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;strong&gt;能并行计算&lt;/strong&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td style=&#34;text-align: center&#34;&gt;✗&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;最后一行，就是 Transformer 要解决的问题。&lt;/p&gt;&#xA;&lt;h3 id=&#34;18-回到论文introduction-与-background-在说什么&#34;&gt;1.8 回到论文：Introduction 与 Background 在说什么&#xA;&lt;/h3&gt;&lt;p&gt;有了上面的铺垫，论文前两节就很好读了。它的逻辑是这样的：&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt; 先说 RNN 及其变体（LSTM、GRU，都属于 RNN 家族）是序列任务的主流方法；然后指出它们的根本局限是“递归计算导致训练无法并行”；接着说注意力机制已经成了好模型的标配，能不管距离远近地捕捉依赖关系——&lt;strong&gt;但在几乎所有情况下，注意力都是和 RNN 一起用的&lt;/strong&gt;，只是一个增强件，没有动摇“顺序计算”这个地基。最后亮出本文的方案：Transformer 完全抛弃循环结构，只靠注意力来建立输入和输出之间的全局依赖。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt; 补充了一些相关尝试。为了解决顺序计算的问题，有人用 CNN 替代 RNN（比如 ConvS2S、ByteNet），CNN 可以并行算所有位置。但 CNN 每次只看一个小窗口，两个离得远的词要建立联系，需要叠很多层才能“传”过去，所需的操作数随距离增长（ConvS2S 是线性增长，ByteNet 是对数增长）。结果是——&lt;strong&gt;远距离依赖又难学了&lt;/strong&gt;，好不容易解决的问题又被捞了回来。Transformer 则把任意两个位置之间的操作数降到了常数。&lt;/p&gt;&#xA;&lt;p&gt;这一节还提到了“自注意力”（self-attention，让一个序列内部的各个位置互相关注）和端到端记忆网络（一种递归式的注意力机制）。最后一句是全文的定位：&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;To the best of our knowledge, however, the Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence-aligned RNNs or convolution.&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;Transformer 是第一个&lt;strong&gt;完全&lt;/strong&gt;依靠自注意力、不使用 RNN 或卷积的序列转导模型。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;2-transformer-是怎么做到的&#34;&gt;2 Transformer 是怎么做到的&#xA;&lt;/h2&gt;&lt;h3 id=&#34;21-核心思路训练时答案本来就在手上&#34;&gt;2.1 核心思路：训练时，答案本来就在手上&#xA;&lt;/h3&gt;&lt;p&gt;在看那张让人“有点绝望”的架构图之前，先想清楚一件事：&lt;strong&gt;RNN 为什么非要排队？&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;因为它假设“后面的东西还不知道”。可在&lt;strong&gt;训练&lt;/strong&gt;的时候，事情并不是这样的。训练数据是成对的：“我爱水课”是输入，“I love easy courses”是标准答案，两者从一开始就&lt;strong&gt;完整地&lt;/strong&gt;摆在我们面前。原文的每个词都在，答案的每个词也都在，谁也没必要等谁。&lt;/p&gt;&#xA;&lt;p&gt;既然如此，Transformer 换了一种做法：&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;编码时&lt;/strong&gt;，不再一个个读。每个词都直接“环顾”整句话，把其他所有词的信息吸收到自己身上，形成一个“带上下文的新向量”。四个词同时做这件事，互不等待。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;解码时&lt;/strong&gt;，同样把整句答案一次性给模型。要预测 “easy” 时，让它看到 “I love” 和原文的编码结果，但&lt;strong&gt;把 “easy” 及后面的词遮住&lt;/strong&gt;，不许偷看。每个位置都这样设置，就能让所有位置的预测同时进行。&lt;/p&gt;&#xA;&lt;p&gt;这里要强调：这种“同时进行”说的是&lt;strong&gt;训练&lt;/strong&gt;。等模型训练好、真正拿来翻译一句新话时，答案是不知道的，还是只能一个词一个词地生成（第 2.9 节会细讲）。但训练恰恰是最耗算力的环节——大模型要在海量文本上训练，训练能并行，才让“堆数据、堆算力”这条路走得通。&lt;/p&gt;&#xA;&lt;p&gt;还有一个代价：不再按顺序读，词序信息就没了，所以需要额外把“位置”编码进去。&lt;/p&gt;&#xA;&lt;p&gt;于是，Transformer 要给每个词编码三样东西：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;这个词本身的意思&lt;/strong&gt;——词嵌入；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;这个词在句子里的位置&lt;/strong&gt;——位置编码；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;这个词在当前上下文里的含义&lt;/strong&gt;——自注意力。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;带着这个思路，我们来看全景图。&lt;/p&gt;&#xA;&lt;h3 id=&#34;22-全景图&#34;&gt;2.2 全景图&#xA;&lt;/h3&gt;&lt;p&gt;&lt;img alt=&#34;Transformer 全景图&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;258px&#34; data-flex-grow=&#34;107&#34; height=&#34;1860&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/08-architecture.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/08-architecture_hu_4e1bf15f89e21fb.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/08-architecture_hu_b74cf5a17235d32.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/08-architecture.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;（这是按论文 Figure 1 重画的中文版。）&lt;/p&gt;&#xA;&lt;p&gt;左边是&lt;strong&gt;编码器&lt;/strong&gt;，读原文“我爱水课”；右边是&lt;strong&gt;解码器&lt;/strong&gt;，读右移一位的答案“&lt;code&gt;&amp;lt;s&amp;gt;&lt;/code&gt; I love easy”（&lt;code&gt;&amp;lt;s&amp;gt;&lt;/code&gt; 是“开始”标记），输出下一个词的概率。&lt;/p&gt;&#xA;&lt;p&gt;图看着复杂，其实新东西只有几块：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;橙色&lt;/strong&gt;：注意力模块，重中之重。编码器里有一个“多头自注意力”；解码器里有两个，一个“带掩码的多头自注意力”，一个“编码器-解码器注意力”。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;紫色&lt;/strong&gt;：前馈网络，就是第 1.3 节那个最朴素的 FNN。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;黄色&lt;/strong&gt;：残差连接 + 层归一化，深度学习的常规操作，让深层网络好训练。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;粉色和青色&lt;/strong&gt;：词嵌入和位置编码，是数据的入口。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;框旁边的 “× N” 表示这一整块会&lt;strong&gt;重复堆叠 N 次&lt;/strong&gt;，论文里 N = 6。为什么能随便叠？因为每一块的输入和输出形状完全一样（每个词都是 512 维），上一块的输出可以原封不动地当下一块的输入，想叠几层都行。&lt;/p&gt;&#xA;&lt;p&gt;接下来，我们跟着“我爱水课”走一遍完整的训练流程。&lt;/p&gt;&#xA;&lt;h3 id=&#34;23-第一步词嵌入&#34;&gt;2.3 第一步：词嵌入&#xA;&lt;/h3&gt;&lt;p&gt;“我爱水课”先经过词嵌入，每个词变成一个 512 维向量。四个词摞在一起，就是一个 4 × 512 的矩阵（4 行，每行一个词）。&lt;/p&gt;&#xA;&lt;p&gt;这一步第 1.2 节已经讲过，不再重复。只补一个论文里的细节：Transformer 会把词嵌入向量乘以 $\sqrt{d_{model}} = \sqrt{512}$，而且编码器输入、解码器输入、以及最后输出层的线性变换，三者共享同一份权重矩阵。&lt;/p&gt;&#xA;&lt;h3 id=&#34;24-第二步位置编码&#34;&gt;2.4 第二步：位置编码&#xA;&lt;/h3&gt;&lt;p&gt;自注意力是“所有词同时看所有词”，这对计算来说是好事，但有一个副作用：&lt;strong&gt;它对顺序完全不敏感&lt;/strong&gt;。如果你把“我爱水课”打乱成“课水爱我”，在没有位置信息的情况下，每个词算出来的结果和原来一模一样（只是换了个排列）。所以必须把位置信息显式地加进去。&lt;/p&gt;&#xA;&lt;h4 id=&#34;241-为什么不直接写-123&#34;&gt;2.4.1 为什么不直接写 1、2、3？&#xA;&lt;/h4&gt;&lt;p&gt;最自然的想法是给每个词附一个编号：第 1 个、第 2 个、第 3 个……但单独一个数字有几个麻烦：数值会随句子变长而无限增大，和词向量里那些量级很小的数字混在一起很不协调；模型训练时没见过的长度（比如第 1000 个位置），它就不知道该怎么处理；而且一个孤零零的标量，很难让模型通过向量运算去理解“第 3 个词和第 7 个词隔了多远”。&lt;/p&gt;&#xA;&lt;p&gt;所以论文的做法是：&lt;strong&gt;给每个位置也生成一个 512 维的向量&lt;/strong&gt;，然后直接加到词向量上。&lt;/p&gt;&#xA;&lt;h4 id=&#34;242-正弦余弦编码&#34;&gt;2.4.2 正弦余弦编码&#xA;&lt;/h4&gt;&lt;p&gt;这个位置向量是用正弦、余弦函数算出来的：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;PE_{(pos,,2i)} = \sin!\left(\frac{pos}{10000^{2i/d_{model}}}\right), \qquad&#xA;PE_{(pos,,2i+1)} = \cos!\left(\frac{pos}{10000^{2i/d_{model}}}\right)&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;$pos$ 是位置（第几个词），$i$ 是维度编号。偶数维用 sin，奇数维用 cos，不同维度的波长不同：从最短的 $2\pi$ 一路增长到最长约 $10000 \cdot 2\pi$。&lt;/p&gt;&#xA;&lt;p&gt;公式看着吓人，画出来就直观了：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;位置编码热力图&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;407px&#34; data-flex-grow=&#34;169&#34; height=&#34;1140&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/09-positional-encoding.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/09-positional-encoding_hu_fe238439faa7ec54.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/09-positional-encoding_hu_98801fd1f35094c3.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/09-positional-encoding.png 1936w&#34; width=&#34;1936&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;每一行是一个位置的编码。靠左的维度频率高，相邻位置之间变化剧烈，像钟表的&lt;strong&gt;秒针&lt;/strong&gt;；靠右的维度频率低，要隔很多个位置才变一点，像&lt;strong&gt;时针&lt;/strong&gt;。把所有指针的读数合在一起，就能唯一确定“现在几点”——也就是唯一确定这个位置。这其实和二进制计数很像：最低位每次都翻转，越高的位翻转得越慢。&lt;/p&gt;&#xA;&lt;p&gt;举几个具体的数字（只看前 4 维）：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;位置&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;第 0 维 (sin)&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;第 1 维 (cos)&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;第 2 维 (sin)&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;第 3 维 (cos)&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0（我）&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.000&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1.000&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.000&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1.000&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1（爱）&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.841&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.540&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.822&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.570&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;2（水）&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.909&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;−0.416&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.936&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;−0.351&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;3（课）&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.141&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;−0.990&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.245&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;−0.970&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;所有数都在 −1 到 1 之间，不会随句子变长而爆炸。论文还给出了选择它的一个理由：对任意固定的偏移 $k$，$PE_{pos+k}$ 都可以表示成 $PE_{pos}$ 的线性函数（这是三角函数和角公式的性质），作者推测这能让模型更容易学会按“相对位置”去关注。论文同时说明，他们也试过让模型自己学一组位置向量（后来 BERT 就是这么做的），效果几乎一样；选正弦版本，是因为它也许能推广到比训练时更长的句子。&lt;/p&gt;&#xA;&lt;p&gt;最后，位置编码和词嵌入&lt;strong&gt;直接相加&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;x_{\text{水}} = \text{Embedding}(\text{水}) + PE_{(2)}&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;就像给每个词贴了一个位置标签。现在，每个词的向量里既有“我是谁”，也有“我在哪”。还差最后一样：“我在这句话里是什么意思”。&lt;/p&gt;&#xA;&lt;h3 id=&#34;25-第三步自注意力全文的重中之重&#34;&gt;2.5 第三步：自注意力，全文的重中之重&#xA;&lt;/h3&gt;&lt;h4 id=&#34;251-它要解决什么问题&#34;&gt;2.5.1 它要解决什么问题&#xA;&lt;/h4&gt;&lt;p&gt;回到词嵌入的那张地图。在词嵌入表里，“水”只有一个固定的位置——不管出现在哪句话里，查表得到的都是同一个向量。这显然不合理：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;“这西瓜水真多”里的“水”，应该往“水果”“水分”那边偏一点；&lt;/li&gt;&#xA;&lt;li&gt;“我爱水课”里的“水”，应该往“简单”“课程”那边偏一点。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;自注意力要做的事：让同一个“水”在不同句子里变成不同的向量&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;459px&#34; data-flex-grow=&#34;191&#34; height=&#34;940&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/10-context-shift.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/10-context-shift_hu_66f55f30f2b6c7dc.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/10-context-shift_hu_11703b6d050ef348.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/10-context-shift.png 1800w&#34; width=&#34;1800&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;自注意力的任务，就是根据上下文给每个词的向量“挪个位置”&lt;/strong&gt;。挪向哪里、挪多远，由句子里的其他词决定。挪完之后，两个“水”就不再是同一个向量，机器才算真正区分开了它们。&lt;/p&gt;&#xA;&lt;p&gt;那具体怎么挪？答案是 Query、Key、Value 这一套。&lt;/p&gt;&#xA;&lt;h4 id=&#34;252-每个词变出三个分身&#34;&gt;2.5.2 每个词变出三个分身&#xA;&lt;/h4&gt;&lt;p&gt;&lt;img alt=&#34;每个词变出 Query、Key、Value 三个分身&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;626px&#34; data-flex-grow=&#34;261&#34; height=&#34;720&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/11-qkv.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/11-qkv_hu_3cacf135e79ef522.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/11-qkv_hu_ccec734ebb6c23a.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/11-qkv.png 1880w&#34; width=&#34;1880&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;把“水”的向量 $x_{\text{水}}$（已经加过位置编码）分别乘以三个不同的权重矩阵 $W^Q$、$W^K$、$W^V$，得到三个新向量：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Query（查询）&lt;/strong&gt; $q_{\text{水}}$：可以理解成“水”发出的一个问题，比如“附近有名词吗？有和学习相关的词吗？”&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Key（键）&lt;/strong&gt; $k_{\text{水}}$：可以理解成“水”挂在身上的标签，供别人的问题来匹配，比如“我是名词”。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Value（值）&lt;/strong&gt; $v_{\text{水}}$：“水”真正携带的内容，被别人选中时交出去的就是它。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;一个好用的类比是图书馆检索：Query 是你在搜索框里输入的关键词，Key 是每本书的标签，Value 是书的内容。你用关键词和所有标签比对，越匹配的书，你读得越多。&lt;/p&gt;&#xA;&lt;p&gt;当然，“附近有名词吗”只是帮助理解的拟人化说法。真实模型里，$W^Q$、$W^K$、$W^V$ 是训练出来的参数，每个维度具体在“问”什么，人类往往说不清。但效果上，它们确实学会了提出有用的问题、贴上有用的标签。&lt;/p&gt;&#xA;&lt;p&gt;不只是“水”，句子里每个词都会得到自己的 q、k、v。而且这一步不用一个个算：把整句的 4 × 512 矩阵 $X$ 乘一次 $W^Q$，就同时得到了所有词的 Query，K 和 V 同理。这就是“并行”二字落到实处的样子——就是几次大矩阵乘法。&lt;/p&gt;&#xA;&lt;h4 id=&#34;253-注意力公式&#34;&gt;2.5.3 注意力公式&#xA;&lt;/h4&gt;&lt;p&gt;拿到 Q、K、V 之后，计算就是论文里最有名的那个公式，&lt;strong&gt;缩放点积注意力&lt;/strong&gt;（Scaled Dot-Product Attention）：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;\text{Attention}(Q, K, V) = \text{softmax}!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;拆开来只有四步：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;打分&lt;/strong&gt;：用每个词的 Query 和所有词的 Key 做点积。点积越大，说明“问题”和“标签”越匹配；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缩放&lt;/strong&gt;：除以 $\sqrt{d_k}$（$d_k$ 是 Key 向量的维度），原因稍后讲；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;归一化&lt;/strong&gt;：过一个 softmax，把分数变成一组&lt;strong&gt;非负、加起来等于 1&lt;/strong&gt; 的权重；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;加权求和&lt;/strong&gt;：用这组权重给所有词的 Value 做加权平均，得到这个词的新向量。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4 id=&#34;254-手算一遍&#34;&gt;2.5.4 手算一遍&#xA;&lt;/h4&gt;&lt;p&gt;光看公式不够直观，我们拿“水”来手算一遍。为了能用手算，把向量缩到只有 4 维（所以 $d_k = 4$，$\sqrt{d_k} = 2$），数字都是为了演示编出来的：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;手算一遍：“水”是怎么吸收上下文的&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;392px&#34; data-flex-grow=&#34;163&#34; height=&#34;1200&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/12-attention-steps.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/12-attention-steps_hu_7c53dab5a1ce9b85.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/12-attention-steps_hu_cf516c0c6dbfff55.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/12-attention-steps.png 1960w&#34; width=&#34;1960&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;“水”的 Query 是 $q_{\text{水}} = [1, 0, 1, 0]$，四个词的 Key 分别是：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;我&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;爱&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;水&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;课&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Key&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;[1, 0, 0, 2]&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;[0, 2, 1, 0]&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;[2, 0, 2, 0]&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;[1, 0, 3, 0]&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;strong&gt;① 打分&lt;/strong&gt;。点积就是对应位置相乘再相加，比如 $q_{\text{水}} \cdot k_{\text{课}} = 1\times1 + 0\times0 + 1\times3 + 0\times0 = 4$。四个分数是 $[1, 1, 4, 4]$。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;② 缩放&lt;/strong&gt;。都除以 2，得到 $[0.5, 0.5, 2, 2]$。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;③ softmax&lt;/strong&gt;。softmax 的做法是：先对每个数取指数 $e^x$，再除以它们的总和。&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;e^{0.5} \approx 1.649,\quad e^{2} \approx 7.389,\quad \text{总和} = 2\times1.649 + 2\times7.389 = 18.076&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;\text{权重} = \left[\tfrac{1.649}{18.076},\ \tfrac{1.649}{18.076},\ \tfrac{7.389}{18.076},\ \tfrac{7.389}{18.076}\right] \approx [0.09,\ 0.09,\ 0.41,\ 0.41]&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;取指数有两个好处：结果一定是正数；原来大的分数会被拉得更大，差距更明显。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;④ 加权求和&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;\text{新的“水”} = 0.09,v_{\text{我}} + 0.09,v_{\text{爱}} + 0.41,v_{\text{水}} + 0.41,v_{\text{课}}&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;新的“水”向量里，有四成多的信息来自“课”。它已经不是孤零零的 water，而是带着“课”的语境的那个“水”。这和第 1.6 节注意力机制的加权平均是同一个思想，只不过这次是&lt;strong&gt;句子内部的词互相关注&lt;/strong&gt;，所以叫“自”注意力（self-attention）：Q、K、V 全都来自同一个句子自己。&lt;/p&gt;&#xA;&lt;h4 id=&#34;255-整句一起算&#34;&gt;2.5.5 整句一起算&#xA;&lt;/h4&gt;&lt;p&gt;上面只算了“水”这一行。实际计算中，四个词是同时算的：$QK^\top$ 一次就得到一张 4 × 4 的分数表，softmax 按行归一化，再乘以 $V$，所有词的新向量一起出炉。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;一张 4×4 的注意力权重表&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;295px&#34; data-flex-grow=&#34;123&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/13-attention-matrix.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/13-attention-matrix_hu_843720c2eb0fadf1.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/13-attention-matrix.png 1280w&#34; width=&#34;1280&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;每一行是一个词“看”所有词的比例。比如“我”这一行，最关注“爱”（0.61），可以理解为“我”在找它的动作；“课”这一行，最关注“水”（0.39），可以理解为“课”在找修饰它的词。这张表还有一个额外的好处：它可以直接画出来看，帮助人理解模型“在想什么”，论文第 4 节专门提到了这一点。&lt;/p&gt;&#xA;&lt;h4 id=&#34;256-为什么要除以-dₖ&#34;&gt;2.5.6 为什么要除以 √dₖ&#xA;&lt;/h4&gt;&lt;p&gt;这是论文里专门解释的一个细节，也是面试常考题。&lt;/p&gt;&#xA;&lt;p&gt;假设 q 和 k 的每个分量都是均值 0、方差 1 的随机数，那么它们的点积 $q \cdot k = \sum_{i=1}^{d_k} q_i k_i$ 是 $d_k$ 个随机数之和，均值为 0，&lt;strong&gt;方差为 $d_k$&lt;/strong&gt;。$d_k$ 越大，点积的数值就越“野”。在 64 维时，点积的标准差约为 8；在 512 维时约为 22.6。&lt;/p&gt;&#xA;&lt;p&gt;数值太大，softmax 就会“饱和”。举个例子，三个分数 $[22, 11, 5]$ 过 softmax，结果约是 $[0.99998,\ 0.00002,\ 0.0]$：几乎所有权重都压在第一个上，其他位置几乎被无视。更糟的是，这时 softmax 的梯度极小，模型很难通过训练去调整它——像是一个开关卡死在一端。&lt;/p&gt;&#xA;&lt;p&gt;除以 $\sqrt{d_k}$ 之后，点积的方差被拉回 1。同样的分数除以 $\sqrt{512} \approx 22.6$，softmax 的结果是 $[0.48,\ 0.29,\ 0.23]$，权重分布得柔和多了，训练也更顺畅。&lt;/p&gt;&#xA;&lt;p&gt;论文还对比了另一种常用的“加性注意力”（additive attention，Bahdanau 用的那种，拿一个小神经网络来算分数）。两者理论复杂度差不多，但点积注意力可以直接用高度优化的矩阵乘法实现，&lt;strong&gt;更快也更省内存&lt;/strong&gt;。缩放这一步，就是为了在 $d_k$ 较大时补上点积注意力的短板。&lt;/p&gt;&#xA;&lt;h3 id=&#34;26-多头注意力八个小专家各看一个侧面&#34;&gt;2.6 多头注意力：八个小专家，各看一个侧面&#xA;&lt;/h3&gt;&lt;p&gt;前面讲的是“单头”注意力：$W^Q$、$W^K$、$W^V$ 都是 512 × 512，“我爱水课”的 4 × 512 矩阵乘过去，Q、K、V 都还是 4 × 512，注意力的输出也是 4 × 512。&lt;/p&gt;&#xA;&lt;p&gt;而 Transformer 实际用的是&lt;strong&gt;多头注意力&lt;/strong&gt;（Multi-Head Attention）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;多头注意力&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;413px&#34; data-flex-grow=&#34;172&#34; height=&#34;1160&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/14-multi-head.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/14-multi-head_hu_35a29a9125eb50b4.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/14-multi-head_hu_fe08aa6d7bf817bb.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/14-multi-head.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;准备 &lt;strong&gt;8 组&lt;/strong&gt;权重矩阵，每组的 $W^Q_i$、$W^K_i$、$W^V_i$ 都是 512 × 64；&lt;/li&gt;&#xA;&lt;li&gt;每组各自算出 4 × 64 的 Q、K、V，各自做一遍注意力，得到 4 × 64 的结果——这就是一个“头”；&lt;/li&gt;&#xA;&lt;li&gt;把 8 个头的结果&lt;strong&gt;拼接&lt;/strong&gt;起来：8 × 64 = 512，又回到 4 × 512；&lt;/li&gt;&#xA;&lt;li&gt;最后再乘一个 512 × 512 的矩阵 $W^O$，得到最终输出。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;写成公式是：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;\text{MultiHead}(Q,K,V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_8),W^O,\qquad \text{head}_i = \text{Attention}(QW^Q_i,\ KW^K_i,\ VW^V_i)&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;这里自然冒出三个问题。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;为什么要拆成多个头？&lt;/strong&gt; 回想一下 512 维空间：你可以想象每个方向代表词的某种特征。视频里举了个很生动的例子，用 512 维描述“汉堡”和“菠萝”：有的维度表示甜不甜、辣不辣、咸不咸（口味），有的表示脂肪、碳水的含量（热量），有的表示维生素含量（营养）。从 512 维投影到 64 维，相当于每个头只抽取出一个“子空间”来看：第一个头可能只关注口味，第二个只关注热量，第三个只关注营养。&lt;/p&gt;&#xA;&lt;p&gt;放到语言上，就是每个头可以学着问不同的问题：一个头关心“附近有没有名词”，一个头关心“谁是主语”，一个头关心“哪个词在修饰我”。单头注意力只能得出一组权重，很难同时兼顾这么多种关系；多头则让模型能&lt;strong&gt;从多个角度同时理解&lt;/strong&gt;同一句话，论文原话是 “jointly attend to information from different representation subspaces at different positions”。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;为什么拼起来之后还要乘一个 $W^O$？&lt;/strong&gt; 拼接只是把 8 份结果首尾摆在一起，每一份都是在自己的小子空间里独立算出来的，彼此之间没有任何交流。视频打了个比方：8 张低清的小图拼在一起，并不等于一张高清大图。$W^O$ 的作用就是学着把这 8 个视角的信息&lt;strong&gt;融合&lt;/strong&gt;起来，重新投影成一个完整的 512 维表示。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;为什么是 8 个 64 维，而不是 8 个 512 维？&lt;/strong&gt; 算一笔账就明白了：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;8 \times (512 \times 64 \times 3) = 786{,}432 = 1 \times (512 \times 512 \times 3)&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;8 个 64 维的小头，参数量和计算量跟 1 个 512 维的大头&lt;strong&gt;完全一样&lt;/strong&gt;。如果每个头都用 512 维，计算量就要翻 8 倍。拆成 8 × 64，等于不花额外成本，白得了 8 个视角。至于为什么偏偏是 512、8、64，这些都是超参数，是作者试出来效果好的取值，换成别的也能训练。&lt;/p&gt;&#xA;&lt;h3 id=&#34;27-残差连接层归一化与前馈网络&#34;&gt;2.7 残差连接、层归一化与前馈网络&#xA;&lt;/h3&gt;&lt;p&gt;多头注意力之后，紧跟着一个“&lt;strong&gt;Add &amp;amp; Norm&lt;/strong&gt;”，然后是前馈网络，再一个 “Add &amp;amp; Norm”。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;残差+归一化，以及逐位置前馈网络&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;558px&#34; data-flex-grow=&#34;232&#34; height=&#34;860&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/15-addnorm-ffn.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/15-addnorm-ffn_hu_f175ebe367c5fedf.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/15-addnorm-ffn_hu_c312371b947df8d2.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/15-addnorm-ffn.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;残差连接&lt;/strong&gt;（Residual Connection）就是图里那条“抄近路”的虚线：把子层的输入 $x$ 原样抄一份，直接加到子层的输出上。&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;\text{输出} = \text{LayerNorm}\big(x + \text{Sublayer}(x)\big)&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;为什么要这样？设想某个子层学得很差，把输入扭曲得面目全非，后面的层再怎么努力，拿到的也只是一堆被搅乱的东西。有了残差连接，不管这个子层学得如何，原始信息都有一条保底通道能继续往下传。子层只需要学“在原来基础上补充点什么”，而不是“从零重建一切”。这在网络很深时尤其关键，Transformer 的编码器和解码器加起来有 30 个子层，靠的就是它才能稳定训练。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;层归一化&lt;/strong&gt;（Layer Normalization）则是把每个词向量的数值重新调整到均值 0、方差 1 附近，让数值保持稳定，方便训练。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;前馈网络&lt;/strong&gt;（Feed-Forward Network）就是第 1.3 节那个最朴素的两层网络：&lt;/p&gt;&#xA;&lt;p&gt;$$&#xA;\text{FFN}(x) = \max(0,\ xW_1 + b_1),W_2 + b_2&#xA;$$&lt;/p&gt;&#xA;&lt;p&gt;先把 512 维撑大到 2048 维，过一个 ReLU（负数变 0，正数不变），再压回 512 维。论文强调它是“逐位置”（position-wise）的：&lt;strong&gt;每个词单独、各自&lt;/strong&gt;过一遍同一个网络，词与词之间在这里不交流。&lt;/p&gt;&#xA;&lt;p&gt;可以这么分工理解：注意力负责“词与词之间交流信息”，前馈网络负责“每个词把收集到的信息自己消化一下”，并引入更多的非线性和参数，增强模型的表达能力。&lt;/p&gt;&#xA;&lt;p&gt;经过“注意力 → Add &amp;amp; Norm → FFN → Add &amp;amp; Norm”，形状依然是 4 × 512，于是可以再送进下一层。重复 6 次，编码器的工作就完成了：最终得到的 4 × 512 矩阵，每一行都是一个融合了&lt;strong&gt;词义、位置和整句上下文&lt;/strong&gt;的向量。&lt;/p&gt;&#xA;&lt;h3 id=&#34;28-解码器掩码与去原文里找答案&#34;&gt;2.8 解码器：掩码，与“去原文里找答案”&#xA;&lt;/h3&gt;&lt;p&gt;解码器的流程和编码器大同小异：答案 “&lt;code&gt;&amp;lt;s&amp;gt;&lt;/code&gt; I love easy” 进来，过词嵌入、位置编码，然后进入 6 层堆叠的模块。区别在于两处。&lt;/p&gt;&#xA;&lt;h4 id=&#34;281-带掩码的自注意力防作弊&#34;&gt;2.8.1 带掩码的自注意力：防作弊&#xA;&lt;/h4&gt;&lt;p&gt;训练时我们把整句答案一次性给了解码器。如果不加限制，预测 “easy” 的时候，模型直接看一眼输入里的 “easy” 就能答对——这是作弊，学不到任何东西。而且在真正使用时，后面的词还没生成，根本没得看。&lt;/p&gt;&#xA;&lt;p&gt;所以解码器的第一个自注意力加了&lt;strong&gt;掩码&lt;/strong&gt;（mask）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;掩码：训练时把未来的答案遮住&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;382px&#34; data-flex-grow=&#34;159&#34; height=&#34;1080&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/16-mask.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/16-mask_hu_bf422985c85a13f.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/16-mask_hu_9b5b12ccc1b17885.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/16-mask.png 1720w&#34; width=&#34;1720&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;解码器的输入是整句答案&lt;strong&gt;右移一位&lt;/strong&gt;（前面补一个开始符 &lt;code&gt;&amp;lt;s&amp;gt;&lt;/code&gt;），每个位置的任务是预测下一个词。在注意力的分数表里，第 $i$ 行只允许看第 1 到第 $i$ 列，右上角的格子全部遮掉。站在 “love” 的位置预测 “easy” 时，它只看得到 &lt;code&gt;&amp;lt;s&amp;gt;&lt;/code&gt;、I、love。&lt;/p&gt;&#xA;&lt;p&gt;具体实现是：在 softmax &lt;strong&gt;之前&lt;/strong&gt;，把被遮住的位置的分数设为 $-\infty$。因为 $e^{-\infty} = 0$，softmax 之后这些位置的权重恰好是 0，也不影响其他位置的权重加起来等于 1。（注意不是把分数设为 0：分数为 0 时 $e^0 = 1$，那个位置照样能分到权重。）&lt;/p&gt;&#xA;&lt;h4 id=&#34;282-编码器-解码器注意力译文拿着问题去原文里找答案&#34;&gt;2.8.2 编码器-解码器注意力：译文拿着问题，去原文里找答案&#xA;&lt;/h4&gt;&lt;p&gt;解码器每一层的第二个注意力模块，和前面的“自”注意力不同，它的 Q 和 K、V 来自两个地方：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;编码器-解码器注意力&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;534px&#34; data-flex-grow=&#34;222&#34; height=&#34;880&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/17-cross-attention.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/17-cross-attention_hu_f7e5ec37d180ec0c.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/17-cross-attention_hu_757de4bba5f8fc8b.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/17-cross-attention.png 1960w&#34; width=&#34;1960&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Query&lt;/strong&gt; 来自解码器自己（下面那层的输出），可以理解为：“我已经写了 I love，下一个词该看原文的哪里？”&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Key 和 Value&lt;/strong&gt; 来自编码器的最终输出，也就是“已经读懂了的原文”。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;计算方式还是那个公式，只是“提问的人”和“被问的人”分属两个句子。这一步就是第 1.6 节那个经典注意力机制在 Transformer 里的化身：译文的每个位置，都去原文里找自己最该关注的部分。这一层在论文里叫 “encoder-decoder attention”，现在也常叫交叉注意力（cross-attention）。&lt;/p&gt;&#xA;&lt;p&gt;至此，Transformer 中多头注意力的&lt;strong&gt;三种用法&lt;/strong&gt;都出场了（论文 3.2.3 节）：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;编码器里的自注意力&lt;/strong&gt;：原文的每个词看原文的所有词；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;解码器里的带掩码自注意力&lt;/strong&gt;：译文的每个词只看它自己和它前面的词；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;编码器-解码器注意力&lt;/strong&gt;：译文的每个词去看原文的所有词。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;之后照例是 Add &amp;amp; Norm、前馈网络、Add &amp;amp; Norm，重复 6 层。&lt;/p&gt;&#xA;&lt;h3 id=&#34;29-最后一步从向量到单词&#34;&gt;2.9 最后一步：从向量到单词&#xA;&lt;/h3&gt;&lt;p&gt;解码器最终输出的，仍然是每个位置一个 512 维向量。它代表“模型认为这个位置该填的词”的语义，但还不是一个具体的词。最后还要两步：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;线性层 + softmax：从 512 维向量到下一个词&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;576px&#34; data-flex-grow=&#34;240&#34; height=&#34;800&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/18-output.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/18-output_hu_2bb665601eff4d84.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/18-output_hu_485362d8b68f835c.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/18-output.png 1920w&#34; width=&#34;1920&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;线性层&lt;/strong&gt;做一次维度变换，把 512 维映射到“词表大小”那么多维。假设词表里有 3 万个词，就得到一个 3 万维的向量，每一维是对应那个词的得分。（论文的英德翻译实验用的是约 37000 个子词单元的共享词表。）&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;softmax&lt;/strong&gt; 再把这些得分变成概率。得分本身没有统一的尺度，10 分算高还是算低，取决于其他词的分数；变成概率后，所有词的可能性加起来等于 1，一目了然。&lt;/p&gt;&#xA;&lt;p&gt;刚开始训练时，模型在 “easy” 这个位置可能给出“water 的概率 0.8，easy 的概率 0.1”。但标准答案是 easy，于是&lt;strong&gt;损失函数&lt;/strong&gt;会衡量预测和答案之间的差距，再通过反向传播去调整模型里所有的参数——词嵌入表、$W^Q$、$W^K$、$W^V$、$W^O$、前馈网络的权重……让下一次 easy 的概率更高一点。成千上万次之后，模型就学会了：“水”后面跟着“课”时，它是 easy，不是 water。&lt;/p&gt;&#xA;&lt;h4 id=&#34;291-训练和推理的区别&#34;&gt;2.9.1 训练和推理的区别&#xA;&lt;/h4&gt;&lt;p&gt;这里正好把第 2.1 节埋的伏笔收回来：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;训练时一次算完；推理时仍要一个词一个词地写&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;461px&#34; data-flex-grow=&#34;192&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/19-train-vs-infer.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/19-train-vs-infer_hu_53b7fef44533140f.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/19-train-vs-infer_hu_4c9fbd8017d23c5e.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/19-train-vs-infer.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;训练时&lt;/strong&gt;，答案在手，配合掩码，5 个位置的预测在一次前向计算里同时完成、同时算误差。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;推理时&lt;/strong&gt;（训练好之后真正拿来用），没有答案。只能先输入 &lt;code&gt;&amp;lt;s&amp;gt;&lt;/code&gt;，让模型预测出 “I”；把 “I” 接到输入后面，再预测出 “love”；再接上，预测 “easy”……直到模型输出结束符 &lt;code&gt;&amp;lt;eos&amp;gt;&lt;/code&gt;。这种“把自己的输出当成下一步输入”的方式叫&lt;strong&gt;自回归&lt;/strong&gt;（auto-regressive）。编码器只需要在开头把原文算一次，之后每一步只跑解码器。&lt;/p&gt;&#xA;&lt;p&gt;你在用 ChatGPT 或 Claude 时，看到回答是一个字一个字“蹦”出来的，原因正在于此。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;3-回到主线为什么这是一场革命&#34;&gt;3 回到主线：为什么这是一场革命&#xA;&lt;/h2&gt;&lt;p&gt;现在终于可以回答开头的问题了。论文第 4 节 “Why Self-Attention” 从三个角度，把自注意力和循环层、卷积层做了对比：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;层类型&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;每层计算复杂度&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;必须串行的操作数&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;任意两位置间最长路径&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;自注意力&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(n^2 \cdot d)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(1)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(1)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;循环（RNN）&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(n \cdot d^2)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(n)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(n)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;卷积（CNN）&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(k \cdot n \cdot d^2)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(1)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;$O(\log_k n)$&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;（$n$ 是序列长度，$d$ 是向量维度，$k$ 是卷积核大小。来自论文 Table 1。）&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;第一，每层的计算量。&lt;/strong&gt; 自注意力要算所有词两两之间的分数，所以和 $n^2$ 成正比；RNN 每一步要做一次 $d \times d$ 的矩阵乘法，所以和 $n \cdot d^2$ 成正比。当句子长度 $n$ 小于向量维度 $d$ 时（论文那个年代的机器翻译，句子通常也就几十个词，而 $d = 512$），自注意力反而更省。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;第二，能不能并行。&lt;/strong&gt; 这是最关键的一列。RNN 必须串行 $n$ 步，自注意力不管句子多长，都是常数步——就是几次矩阵乘法，GPU 一口气全算完。这条瓶颈的突破意义重大：今天的大模型动辄用整个互联网规模的文本训练，如果还像 RNN 那样一步一步地等，根本不可能训练得完。&lt;strong&gt;能并行，才能堆数据、堆算力、堆参数，才有了后来的“大”模型。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;第三，学习长距离依赖的能力。&lt;/strong&gt; 信息从第 1 个词传到第 $n$ 个词要走几步？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;RNN 要接力 n−1 次，自注意力一步直达&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;727px&#34; data-flex-grow=&#34;303&#34; height=&#34;660&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/20-path-length.png&#34; srcset=&#34;https://oi8io.cn/ai/transformer-paper-guide/images/transformer/20-path-length_hu_a70ba653431489.png 800w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/20-path-length_hu_c7a0294a3cab1ccc.png 1600w, https://oi8io.cn/ai/transformer-paper-guide/images/transformer/20-path-length.png 2000w&#34; width=&#34;2000&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;RNN 要接力 $n-1$ 次，每次都有损耗；CNN 要叠 $\log_k n$ 层；自注意力则是&lt;strong&gt;一步直达&lt;/strong&gt;，任意两个词直接相连。路径越短，远距离的依赖关系就越容易学到。&lt;/p&gt;&#xA;&lt;p&gt;除了这三点，论文还提到一个“额外好处”：自注意力&lt;strong&gt;更容易解释&lt;/strong&gt;。可以直接把注意力权重画出来，看每个词关注了哪些词。作者发现，不同的头确实学会了各司其职，有的和句法结构相关，有的和语义相关。&lt;/p&gt;&#xA;&lt;p&gt;最后看看实验结果。在 WMT 2014 英译德任务上，Transformer（大模型）拿到了 28.4 的 BLEU 分数，比当时最好的结果（包括多个模型的集成）高出 2 分以上；在英译法任务上，以 41.8 刷新了单模型的最好成绩，而训练只用了 8 块 GPU、3.5 天，是此前最好模型训练成本的一小部分。基础版模型更是只训练了约 12 小时。&lt;strong&gt;效果更好，训练更快&lt;/strong&gt;——这正是“能并行”带来的直接回报。&lt;/p&gt;&#xA;&lt;p&gt;所以，为什么 2017 年之前没有大模型时代？因为 RNN 那条单行道，让模型没办法高效地吃下海量数据。Transformer 用自注意力同时解决了“记不住远处”和“没法并行”这两个难题，把序列建模变成了 GPU 最擅长的大规模矩阵运算。从此，“更多数据 + 更多算力 = 更强模型”这条路，才真正走得通。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;一页回顾&#34;&gt;一页回顾&#xA;&lt;/h2&gt;&lt;p&gt;如果只记住几句话，就记这些：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;主线&lt;/strong&gt;：Transformer 要解决的，是 RNN 串行计算带来的效率瓶颈，同时不能丢掉注意力机制在长距离依赖上的优势。它的答案是：扔掉 RNN，只用注意力。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;核心思路&lt;/strong&gt;：训练时答案就在手上，所以编码时让每个词同时“看”全句，解码时用掩码遮住后文，所有位置并行计算。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;每个词要编码三样东西&lt;/strong&gt;：词义（词嵌入）、位置（正弦余弦位置编码，直接相加）、上下文（自注意力）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;自注意力&lt;/strong&gt;：每个词变出 Q、K、V 三个分身；用 Q 和所有 K 打分，除以 $\sqrt{d_k}$，过 softmax，再给所有 V 加权求和。除以 $\sqrt{d_k}$ 是为了防止点积太大让 softmax 饱和。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;多头注意力&lt;/strong&gt;：8 个头各在 64 维子空间里从不同角度看，拼接后用 $W^O$ 融合；计算量和单头一样。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;配套组件&lt;/strong&gt;：残差连接给信息留一条保底通道；层归一化稳定数值；逐位置前馈网络让每个词自己消化信息。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;解码器的两个特别之处&lt;/strong&gt;：带掩码的自注意力（防作弊，被遮位置填 $-\infty$）；编码器-解码器注意力（Q 来自译文，K、V 来自原文）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;训练并行，推理仍逐词生成&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;为什么是革命&lt;/strong&gt;：串行步数 $O(1)$、任意两词路径长度 $O(1)$，让大规模训练成为可能。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;后来的故事&#34;&gt;后来的故事&#xA;&lt;/h3&gt;&lt;p&gt;Transformer 原本是为机器翻译设计的，但它的组件很快被拆开来用。只用编码器那一半，就有了 BERT 这类擅长“理解”的模型；只用解码器那一半（带掩码的自注意力 + 前馈网络，去掉交叉注意力），就有了 GPT 系列这类擅长“生成”的模型。今天的大语言模型，绝大多数都是后一种思路的放大版。读懂了这篇论文，也就拿到了理解它们的钥匙。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;Vaswani, A., et al. (2017). &lt;a class=&#34;link&#34; href=&#34;https://arxiv.org/abs/1706.03762&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Attention Is All You Need&lt;/a&gt;. &lt;em&gt;NeurIPS 2017&lt;/em&gt;.&lt;/li&gt;&#xA;&lt;li&gt;堂吉诃德拉曼查的英豪.《Attention Is All You Need》论文解读（视频）. &lt;a class=&#34;link&#34; href=&#34;https://www.bilibili.com/video/BV1xoJwzDESD/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;bilibili BV1xoJwzDESD&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Sutskever, I., Vinyals, O., &amp;amp; Le, Q. V. (2014). &lt;a class=&#34;link&#34; href=&#34;https://arxiv.org/abs/1409.3215&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Sequence to Sequence Learning with Neural Networks&lt;/a&gt;. &lt;em&gt;NeurIPS 2014&lt;/em&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Bahdanau, D., Cho, K., &amp;amp; Bengio, Y. (2014). &lt;a class=&#34;link&#34; href=&#34;https://arxiv.org/abs/1409.0473&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Neural Machine Translation by Jointly Learning to Align and Translate&lt;/a&gt;. &lt;em&gt;arXiv:1409.0473&lt;/em&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Williams, R. J., &amp;amp; Zipser, D. (1989). A learning algorithm for continually running fully recurrent neural networks. &lt;em&gt;Neural Computation&lt;/em&gt;, 1(2).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
        </item></channel>
</rss>
