<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Attention on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/attention/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Thu, 06 Nov 2025 21:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/attention/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>Transformer 不完全图解：一个 AI 工程师需要理解到多深？</title>
      <link>https://ftmao.com/blog/posts/transformer/</link>
      <pubDate>Thu, 06 Nov 2025 21:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/transformer/</guid>
      <description>&lt;h1 id=&#34;transformer-不完全图解一个-ai-工程师需要理解到多深&#34;&gt;Transformer 不完全图解：一个 AI 工程师需要理解到多深？&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;做 AI 应用开发，不一定要会手推反向传播，但理解 Transformer 的基本工作原理非常有价值。这篇文章结合经典文章《The Illustrated Transformer》与&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;中的图解，从零梳理我最常被人问到的几个核心问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一为什么-ai-工程师需要懂-transformer&#34;&gt;一、为什么 AI 工程师需要懂 Transformer？&lt;/h2&gt;
&lt;p&gt;我自己是从 Java 后端转型到 AI 工程的，最初有个困惑：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;「我只是调用 LLM API，为什么要懂 Transformer？」&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;后来在实际项目中发现，不懂底层会导致很多问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不知道 Token 是怎么切分的，导致成本估算偏差&lt;/li&gt;
&lt;li&gt;不理解上下文窗口限制的本质，导致长文本处理方案选错&lt;/li&gt;
&lt;li&gt;不明白 Attention 机制，做不好 RAG 和 Prompt 设计&lt;/li&gt;
&lt;li&gt;不清楚自回归生成，理解不了为什么 LLM 会&amp;quot;胡编&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你不需要成为算法研究员，但需要知道&lt;strong&gt;模型在做什么、能力边界在哪里&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二一句话理解-llm词语接龙预测器&#34;&gt;二、一句话理解 LLM：词语接龙预测器&lt;/h2&gt;
&lt;p&gt;如果你之前对 LLM 略有耳闻，很可能听过这个说法：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;LLM 本质上是一个 &lt;strong&gt;Next Token Predictor（下一个 Token 预测器）&lt;/strong&gt;，也就是&amp;quot;词语接龙&amp;quot;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但大多数解释到此为止。真正的问题是：&lt;strong&gt;它怎么知道下一个词该接什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;答案可以简化成三步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;把文字变成数字&lt;/strong&gt;：用 Embedding 把每个 Token 表示成向量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;层层加工语义&lt;/strong&gt;：用 Transformer 不断提炼上下文信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出概率分布&lt;/strong&gt;：预测词表里每个 Token 出现的可能性，选最可能的那个&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;输入文本&amp;#34;] --&amp;gt; B[&amp;#34;变成向量&amp;#34;]
    B --&amp;gt; C[&amp;#34;多层 Transformer 加工&amp;#34;]
    C --&amp;gt; D[&amp;#34;输出概率分布&amp;#34;]
    D --&amp;gt; E[&amp;#34;选出下一个 Token&amp;#34;]

    style E fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;三从单词到向量embedding-是什么&#34;&gt;三、从单词到向量：Embedding 是什么？&lt;/h2&gt;
&lt;p&gt;人类用字母表示单词，比如 C-A-T 表示&amp;quot;猫&amp;quot;。但神经网络只认识数字，所以我们需要把单词映射成&lt;strong&gt;词向量（word vector）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;例如，&amp;ldquo;cat&amp;rdquo; 可能被表示成这样一个向量：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0.0074, 0.0030, -0.0105, 0.0742, …, 0.0002]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这个向量的维度通常是 300、1000、1536，甚至像 GPT-3 那样达到 &lt;strong&gt;12,288 维&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;31-词向量的神奇性质&#34;&gt;3.1 词向量的神奇性质&lt;/h3&gt;
&lt;p&gt;在训练好的词向量空间里，含义相近的词会离得很近。比如 &amp;ldquo;cat&amp;rdquo; 附近会有 dog、kitten、pet。&lt;/p&gt;
&lt;p&gt;更神奇的是，词向量还能做&amp;quot;语义计算&amp;quot;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;biggest - big + small ≈ smallest
Paris - France + Germany ≈ Berlin
Swiss - Switzerland + Cambodia ≈ Cambodian&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这种能力让模型不仅能&amp;quot;认识&amp;quot;词，还能在一定程度上&amp;quot;理解&amp;quot;词之间的关系。&lt;/p&gt;
&lt;h3 id=&#34;32-词向量是怎么得到的&#34;&gt;3.2 词向量是怎么得到的？&lt;/h3&gt;
&lt;p&gt;早期的 word2vec 通过分析大量文本，让模型预测&amp;quot;一个词旁边常出现哪些词&amp;quot;，从而把语义相近的词放到相近的位置。&lt;/p&gt;
&lt;p&gt;现代 LLM 不再单独训练词向量，而是把 Embedding 层作为模型的一部分，端到端地训练。但核心思想没变：&lt;strong&gt;把离散的符号映射成连续的、有意义的向量&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四transformer-总览数据是怎么流动的&#34;&gt;四、Transformer 总览：数据是怎么流动的？&lt;/h2&gt;
&lt;p&gt;2017 年，Google 发表论文《Attention Is All You Need》，提出了 Transformer 架构。它彻底改变了 NLP，也是 GPT、Claude、DeepSeek 等模型的基础。&lt;/p&gt;
&lt;p&gt;下面这张图是原始 Transformer 的完整结构（包含 Encoder 和 Decoder）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/transformer-architecture-classic.webp&#34; alt=&#34;原始 Transformer 架构图&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;41-图中这些英文标签是什么意思&#34;&gt;4.1 图中这些英文标签是什么意思？&lt;/h3&gt;
&lt;p&gt;第一次看到这张图，很多人会被里面的英文缩写吓到。其实它们都是高中数学/线性代数里很基础的操作：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;标签&lt;/th&gt;
					&lt;th&gt;全称/含义&lt;/th&gt;
					&lt;th&gt;简单解释&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;MatMul&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Matrix Multiplication&lt;/td&gt;
					&lt;td&gt;矩阵乘法。把两个矩阵按规则相乘，是神经网络里最常用的计算。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Dot-Product&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;点积&lt;/td&gt;
					&lt;td&gt;两个向量对应位置相乘再相加，结果越大表示两个向量越&amp;quot;像&amp;quot;。Attention 里用 Q 和 K 的点积来衡量&amp;quot;相关性&amp;quot;。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Scale&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;缩放&lt;/td&gt;
					&lt;td&gt;把点积结果除以 &lt;code&gt;√d_k&lt;/code&gt;，防止数值太大导致 Softmax 梯度消失。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Mask&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;掩码&lt;/td&gt;
					&lt;td&gt;在 Decoder 里把&amp;quot;未来的 Token&amp;quot;遮起来（变成 -∞），让模型不能偷看答案。Encoder 不需要，所以是 opt.（可选）。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Softmax&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;归一化指数函数&lt;/td&gt;
					&lt;td&gt;把任意一组分数变成&amp;quot;概率分布&amp;quot;：都是正数，且加起来等于 1。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Linear&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线性层&lt;/td&gt;
					&lt;td&gt;简单的 &lt;code&gt;y = xW + b&lt;/code&gt;，也就是对向量做一次线性变换。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对应的标准 Attention 公式也要贴出来：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Attention(Q, K, V) = softmax(QK^T / √d_k) × V&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;一句话串起来：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q 和 K 做 MatMul（这一步本质上在计算 Dot-Product）→ Scale → Mask（可选）→ Softmax 得到权重 → 权重再和 V 做 MatMul → 最后过 Linear 层。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对 AI 应用开发者来说，不需要记住每一个方块，但要理解整体数据流：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[输入文本] --&amp;gt; B[Tokenizer&amp;lt;br/&amp;gt;切分成 Token]
    B --&amp;gt; C[Embedding 层&amp;lt;br/&amp;gt;Token → 向量]
    C --&amp;gt; D[位置编码&amp;lt;br/&amp;gt;加入位置信息]
    D --&amp;gt; E[多层 Transformer Block]
    subgraph &amp;#34;一个 Transformer Block 重复 N 次&amp;#34;
        E --&amp;gt; F[Masked Self-Attention&amp;lt;br/&amp;gt;带因果掩码的自注意力]
        F --&amp;gt; G[Add &amp;amp; Norm&amp;lt;br/&amp;gt;残差连接 + 层归一化]
        G --&amp;gt; H[Feed Forward Network&amp;lt;br/&amp;gt;前馈神经网络]
        H --&amp;gt; I[Add &amp;amp; Norm&amp;lt;br/&amp;gt;残差连接 + 层归一化]
    end
    I --&amp;gt; J[线性层 + Softmax]
    J --&amp;gt; K[词表上的概率分布]
    K --&amp;gt; L[采样/取最大概率&amp;lt;br/&amp;gt;得到下一个 Token]
    L --&amp;gt; M[拼回已生成序列&amp;lt;br/&amp;gt;继续预测]
    M --&amp;gt; E&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;一句话总结&lt;/strong&gt;：文本先变成向量，再经过多层&amp;quot;Attention + FFN&amp;quot;的处理，最后预测下一个 Token。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五transformer-的每一层在做什么&#34;&gt;五、Transformer 的每一层在做什么？&lt;/h2&gt;
&lt;p&gt;想象你读一句话：&amp;ldquo;John wants his bank to cash the &amp;ldquo;。&lt;/p&gt;
&lt;p&gt;第一层 Transformer 可能会发现：wants 和 cash 在这里是动词；第二层会进一步澄清：his 指的是 John，bank 指的是金融机构而不是河岸。&lt;/p&gt;
&lt;p&gt;每一层都在前一个层的基础上，给词向量&amp;quot;写注释&amp;rdquo;，帮助模型理解上下文。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/transformer-layer-function.webp&#34; alt=&#34;Transformer 各层功能示意图&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;这些&amp;quot;注释&amp;quot;人类无法直接解读，但它们以数字的形式存储在词向量中，并随着层数增加逐渐丰富。最终，最后一层输出的向量包含了预测下一个 Token 所需的全部信息。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六从-token-到向量输入表示&#34;&gt;六、从 Token 到向量：输入表示&lt;/h2&gt;
&lt;h3 id=&#34;61-token-与-embedding&#34;&gt;6.1 Token 与 Embedding&lt;/h3&gt;
&lt;p&gt;用户输入一句话，比如「你好世界」，模型并不会直接理解汉字。首先要经过 Tokenizer 切分成 Token：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#34;你好世界&amp;#34; → [&amp;#34;你&amp;#34;, &amp;#34;好&amp;#34;, &amp;#34;世&amp;#34;, &amp;#34;界&amp;#34;]
或
&amp;#34;你好世界&amp;#34; → [&amp;#34;你好&amp;#34;, &amp;#34;世界&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;不同模型的 Tokenizer 不同，这也是为什么同样的中文文本，在不同模型里 Token 数可能差很多。&lt;/p&gt;
&lt;p&gt;每个 Token 会被映射成一个向量，叫做 &lt;strong&gt;Embedding&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#34;你&amp;#34; → x₁ (一个 d 维向量)
&amp;#34;好&amp;#34; → x₂
&amp;#34;世&amp;#34; → x₃
&amp;#34;界&amp;#34; → x₄&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;用流程图表示：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;原始文本：&amp;lt;br/&amp;gt;你好世界&amp;#34;] --&amp;gt; B[&amp;#34;Tokenizer&amp;lt;br/&amp;gt;分词器&amp;#34;]
    B --&amp;gt; C[&amp;#34;Token 序列：&amp;lt;br/&amp;gt;[&amp;#39;你&amp;#39;, &amp;#39;好&amp;#39;, &amp;#39;世&amp;#39;, &amp;#39;界&amp;#39;]&amp;#34;]
    C --&amp;gt; D[&amp;#34;Embedding 层&amp;lt;br/&amp;gt;查表/投影&amp;#34;]
    D --&amp;gt; E[&amp;#34;向量序列：&amp;lt;br/&amp;gt;x₁, x₂, x₃, x₄&amp;#34;]

    style A fill:#e1f5e1
    style E fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;62-位置编码&#34;&gt;6.2 位置编码&lt;/h3&gt;
&lt;p&gt;Transformer 本身没有顺序概念（它一次看到所有 Token），所以需要加入位置信息。原始 Transformer 用正弦/余弦函数生成位置编码：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PE(pos, 2i)   = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;直观理解：位置编码向量的左半部分变化平缓（正弦），右半部分变化较快（余弦），中间会有明显的分隔。&lt;/p&gt;
&lt;p&gt;最终输入向量是：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;x_i = Embedding(token_i) + PE(pos_i)&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;Token Embedding&amp;lt;br/&amp;gt;你 → x₁&amp;#34;] --&amp;gt; C[&amp;#34;相加&amp;#34;]
    B[&amp;#34;位置编码&amp;lt;br/&amp;gt;pos=1 → PE₁&amp;#34;] --&amp;gt; C
    C --&amp;gt; D[&amp;#34;最终输入向量&amp;lt;br/&amp;gt;x₁ + PE₁&amp;#34;]

    style D fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么需要位置编码？&lt;/strong&gt; 因为 Attention 机制本质上是对所有 Token 做&amp;quot;加权平均&amp;rdquo;，如果不告诉模型&amp;quot;谁在哪个位置&amp;quot;，&amp;ldquo;我爱你&amp;quot;和&amp;quot;你爱我&amp;quot;对它来说就完全没有区别。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七self-attention核心计算&#34;&gt;七、Self-Attention：核心计算&lt;/h2&gt;
&lt;h3 id=&#34;71-qkv-是怎么来的&#34;&gt;7.1 Q、K、V 是怎么来的？&lt;/h3&gt;
&lt;p&gt;对于每个输入向量 x_i，分别乘以三个权重矩阵，得到：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;q_i = x_i × W_q
k_i = x_i × W_k
v_i = x_i × W_v&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Q（Query）&lt;/strong&gt;：当前 Token 在问什么&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;K（Key）&lt;/strong&gt;：每个 Token 能提供什么信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;V（Value）&lt;/strong&gt;：每个 Token 的实际内容&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;W_q、W_k、W_v 是&lt;strong&gt;训练出来的&lt;/strong&gt;，通过反向传播和梯度下降不断优化。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;输入向量 x_i&amp;#34;] --&amp;gt; B[&amp;#34;× W_q&amp;#34;]
    A --&amp;gt; C[&amp;#34;× W_k&amp;#34;]
    A --&amp;gt; D[&amp;#34;× W_v&amp;#34;]
    B --&amp;gt; E[&amp;#34;q_i&amp;lt;br/&amp;gt;查询向量&amp;#34;]
    C --&amp;gt; F[&amp;#34;k_i&amp;lt;br/&amp;gt;键向量&amp;#34;]
    D --&amp;gt; G[&amp;#34;v_i&amp;lt;br/&amp;gt;值向量&amp;#34;]

    style E fill:#e1f5fe
    style F fill:#e1f5fe
    style G fill:#e1f5fe&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;72-attention-分数计算一步一步看&#34;&gt;7.2 Attention 分数计算：一步一步看&lt;/h3&gt;
&lt;p&gt;计算每个 Token 对其他 Token 的关注程度：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Attention(Q, K, V) = softmax(Q × K^T / √d_k) × V&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;以 &amp;ldquo;q₁&amp;rdquo;（对应 Token &amp;ldquo;你&amp;rdquo;）为例，整个过程可以拆成 4 步：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;步骤 1：算相似度&amp;lt;br/&amp;gt;q₁ × k₁, q₁ × k₂,&amp;lt;br/&amp;gt;q₁ × k₃, q₁ × k₄&amp;#34;] --&amp;gt; B[&amp;#34;步骤 2：缩放&amp;lt;br/&amp;gt;每个分数 ÷ √d_k&amp;#34;]
    B --&amp;gt; C[&amp;#34;步骤 3：Softmax&amp;lt;br/&amp;gt;变成概率分布&amp;lt;br/&amp;gt;和为 1&amp;#34;]
    C --&amp;gt; D[&amp;#34;步骤 4：加权求和&amp;lt;br/&amp;gt;概率 × [v₁, v₂, v₃, v₄]&amp;lt;br/&amp;gt;得到 z₁&amp;#34;]

    style D fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;更具体地，对于序列中的每个位置：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Q1[&amp;#34;q₁&amp;#34;] --&amp;gt; S[&amp;#34;点积&amp;lt;br/&amp;gt;q₁·k₁, q₁·k₂, q₁·k₃, q₁·k₄&amp;#34;]
    K1[&amp;#34;k₁, k₂, k₃, k₄&amp;#34;] --&amp;gt; S
    S --&amp;gt; D[&amp;#34;÷ √d_k&amp;#34;]
    D --&amp;gt; SM[&amp;#34;Softmax&amp;#34;]
    SM --&amp;gt; W[&amp;#34;权重：&amp;lt;br/&amp;gt;0.5, 0.3, 0.1, 0.1&amp;#34;]
    V1[&amp;#34;v₁, v₂, v₃, v₄&amp;#34;] --&amp;gt; SUM[&amp;#34;加权求和&amp;#34;]
    W --&amp;gt; SUM
    SUM --&amp;gt; Z[&amp;#34;z₁ = 0.5v₁ + 0.3v₂ + 0.1v₃ + 0.1v₄&amp;#34;]

    style Z fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;z₁ 就是 &amp;ldquo;你&amp;rdquo; 这个 Token 经过 Self-Attention 后的新表示，它融合了整个句子的信息。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：上面的例子假设是&lt;strong&gt;双向 Self-Attention&lt;/strong&gt;（Encoder 场景），所以位置 1 能看到所有位置。如果是 GPT 这类 &lt;strong&gt;Decoder-only 模型&lt;/strong&gt;，由于有&lt;strong&gt;因果掩码&lt;/strong&gt;，位置 1 只能看到自己，结果会变成 &lt;code&gt;z₁ = 1.0 × v₁&lt;/code&gt;。只有最后一个位置（比如 z₄）才能看到所有 &lt;code&gt;k₁, k₂, k₃, k₄&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;73-多头-attention&#34;&gt;7.3 多头 Attention&lt;/h3&gt;
&lt;p&gt;实际 Transformer 不会只算一组 Q/K/V，而是算多组（Multi-Head）。最后把多组结果拼接，再乘以 W_o：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Z = Concat(z_0, z_1, ..., z_h) × W_o&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;多头的好处是：不同头可以关注不同类型的信息，比如一个头关注语法，一个头关注语义。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;输入 X&amp;#34;] --&amp;gt; B1[&amp;#34;Head 1&amp;#34;]
    A --&amp;gt; B2[&amp;#34;Head 2&amp;#34;]
    A --&amp;gt; B3[&amp;#34;Head ...&amp;#34;]
    A --&amp;gt; B4[&amp;#34;Head h&amp;#34;]

    B1 --&amp;gt; C1[&amp;#34;z₁&amp;#34;]
    B2 --&amp;gt; C2[&amp;#34;z₂&amp;#34;]
    B3 --&amp;gt; C3[&amp;#34;...&amp;#34;]
    B4 --&amp;gt; C4[&amp;#34;zₕ&amp;#34;]

    C1 --&amp;gt; D[&amp;#34;Concat&amp;lt;br/&amp;gt;拼接&amp;#34;]
    C2 --&amp;gt; D
    C3 --&amp;gt; D
    C4 --&amp;gt; D

    D --&amp;gt; E[&amp;#34;× W_o&amp;lt;br/&amp;gt;线性投影&amp;#34;]
    E --&amp;gt; F[&amp;#34;最终输出 Z&amp;#34;]

    style F fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;74-一个完整演算输入-x-x怎么预测-x&#34;&gt;7.4 一个完整演算：输入 x₁, x₂，怎么预测 x₃？&lt;/h3&gt;
&lt;p&gt;前面讲了很多公式，现在用一个具体的 Decoder-only 例子把流程走一遍。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景&lt;/strong&gt;：用户已经输入了 &lt;code&gt;x₁, x₂&lt;/code&gt;（比如「你」「好」），模型要预测下一个 Token &lt;code&gt;x₃&lt;/code&gt;（比如「世」）。&lt;/p&gt;
&lt;h4 id=&#34;第-1-步生成-qkv&#34;&gt;第 1 步：生成 Q、K、V&lt;/h4&gt;
&lt;p&gt;每个输入向量各自乘以三个权重矩阵：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;x₁ → q₁, k₁, v₁
x₂ → q₂, k₂, v₂&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;第-2-步应用因果掩码&#34;&gt;第 2 步：应用因果掩码&lt;/h4&gt;
&lt;p&gt;Decoder 不能偷看未来，所以 2×2 的掩码矩阵是：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[[0, -∞],
 [0,  0]]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;位置 1 只能看到位置 1&lt;/li&gt;
&lt;li&gt;位置 2 能看到位置 1 和位置 2&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph &amp;#34;位置 1&amp;#34;
        A1[&amp;#34;只能看到 x₁&amp;#34;]
    end
    subgraph &amp;#34;位置 2&amp;#34;
        A2[&amp;#34;可以看到 x₁, x₂&amp;#34;]
    end
    A1 --&amp;gt; A2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;第-3-步计算-z&#34;&gt;第 3 步：计算 z₁&lt;/h4&gt;
&lt;p&gt;位置 1 被掩码挡住了 x₂，所以：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;分数 = [q₁·k₁/√d_k,  -∞]
       ↓ Softmax
权重 = [1.0,  0.0]

z₁ = 1.0 × v₁ + 0.0 × v₂ = v₁&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Q1[&amp;#34;q₁&amp;#34;] --&amp;gt; S[&amp;#34;点积&amp;lt;br/&amp;gt;q₁·k₁, -∞&amp;#34;]
    K1[&amp;#34;k₁, k₂&amp;#34;] --&amp;gt; S
    S --&amp;gt; D[&amp;#34;÷ √d_k&amp;#34;]
    D --&amp;gt; SM[&amp;#34;Softmax&amp;lt;br/&amp;gt;→ [1.0, 0.0]&amp;#34;]
    SM --&amp;gt; W[&amp;#34;权重&amp;#34;]
    V1[&amp;#34;v₁, v₂&amp;#34;] --&amp;gt; SUM[&amp;#34;加权求和&amp;#34;]
    W --&amp;gt; SUM
    SUM --&amp;gt; Z[&amp;#34;z₁ = v₁&amp;#34;]

    style Z fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;第-4-步计算-z&#34;&gt;第 4 步：计算 z₂&lt;/h4&gt;
&lt;p&gt;位置 2 可以看到 x₁ 和 x₂：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;分数 = [q₂·k₁/√d_k,  q₂·k₂/√d_k]
       ↓ Softmax
权重 = [0.3,  0.7]   ← 假设的示例值

z₂ = 0.3 × v₁ + 0.7 × v₂&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Q2[&amp;#34;q₂&amp;#34;] --&amp;gt; S[&amp;#34;点积&amp;lt;br/&amp;gt;q₂·k₁, q₂·k₂&amp;#34;]
    K2[&amp;#34;k₁, k₂&amp;#34;] --&amp;gt; S
    S --&amp;gt; D[&amp;#34;÷ √d_k&amp;#34;]
    D --&amp;gt; SM[&amp;#34;Softmax&amp;lt;br/&amp;gt;→ [0.3, 0.7]&amp;#34;]
    SM --&amp;gt; W[&amp;#34;权重&amp;#34;]
    V2[&amp;#34;v₁, v₂&amp;#34;] --&amp;gt; SUM[&amp;#34;加权求和&amp;#34;]
    W --&amp;gt; SUM
    SUM --&amp;gt; Z[&amp;#34;z₂ = 0.3v₁ + 0.7v₂&amp;#34;]

    style Z fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;第-5-步用-z-预测-x&#34;&gt;第 5 步：用 z₂ 预测 x₃&lt;/h4&gt;
&lt;p&gt;只有最后一个位置 z₂ 才包含&amp;quot;已输入全部信息&amp;rdquo;，所以：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Z2[&amp;#34;z₂&amp;#34;] --&amp;gt; L[&amp;#34;Linear&amp;lt;br/&amp;gt;线性层&amp;#34;]
    L --&amp;gt; SM[&amp;#34;Softmax&amp;#34;]
    SM --&amp;gt; P[&amp;#34;词表概率分布&amp;#34;]
    P --&amp;gt; X3[&amp;#34;选出概率最大的 Token&amp;lt;br/&amp;gt;即 x₃&amp;#34;]

    style X3 fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h4 id=&#34;z-有必要算吗&#34;&gt;z₁ 有必要算吗？&lt;/h4&gt;
&lt;p&gt;这个问题要分&amp;quot;概念上&amp;quot;和&amp;quot;工程实现上&amp;quot;两层来理解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;概念上&lt;/strong&gt;：如果你只想预测 x₃，那确实只需要 &lt;strong&gt;z₂&lt;/strong&gt;。z₁ 对应的是预测 x₂，不是 x₃。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工程实现上&lt;/strong&gt;：标准 Transformer 在前向传播时会一次性把 &lt;code&gt;z₁, z₂&lt;/code&gt; 都算出来（因为矩阵运算适合并行）。所以 z₁ 通常还是被算了，只是它的输出被丢弃，不参与生成 x₃。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;那因果掩码还有必要吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;有必要&lt;/strong&gt;，原因有两个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;架构是统一的&lt;/strong&gt;：Transformer 不知道你这次只想要 z₂，它仍然按同样的规则处理所有位置。既然要算 z₁，就必须对 z₁ 应用掩码，防止它偷看 x₂。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prompt 阶段需要并行&lt;/strong&gt;：实际推理时，对于用户输入的整段 Prompt（比如 &lt;code&gt;[x₁, x₂]&lt;/code&gt;），模型通常是一次性并行算出所有位置的，而不是一个一个算。这时候如果不加掩码，z₁ 就会看到后面的 x₂，破坏因果性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;KV Cache 优化&lt;/strong&gt;：在生成后续 Token 时（比如已经生成到 &lt;code&gt;[x₁, x₂, x₃]&lt;/code&gt;，要预测 x₄），工程上会把之前算好的 K、V 缓存起来，只计算新位置。这时 z₁、z₂ 确实不会被重复计算，但因果掩码仍然保留在架构中。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八看看真实模型长什么样gpt-3-的维度&#34;&gt;八、看看真实模型长什么样：GPT-3 的维度&lt;/h2&gt;
&lt;p&gt;理论知识看多了，看看真实模型的尺寸会更有体感。下面是一张手绘风格的 GPT-3 结构图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/gpt3-architecture-handdrawn.webp&#34; alt=&#34;GPT-3 架构手绘图&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;从这张图可以看到几个关键数字：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;词向量维度：12,288&lt;/strong&gt; —— 每个 Token 用 12,288 个数字表示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文长度：2,048&lt;/strong&gt; —— GPT-3 一次能处理 2,048 个 Token&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;层数：96 层&lt;/strong&gt; —— 同样的 Transformer Block 重复 96 次&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数量：约 1,750 亿&lt;/strong&gt; —— 这些参数就是 W_q、W_k、W_v、W_o、W₁、W₂ 等矩阵&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;你可以把这些高维向量看作&amp;quot;草稿纸&amp;quot;，前面的层写下的注释可以被后面的层读取和修改，模型就这样逐层加深对上下文的理解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这也解释了为什么**上下文窗口（context window）**不是无限的：每个 Token 都要和上下文里所有 Token 计算 Attention，长度越长，计算和显存开销越大。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九add--norm-与-ffn&#34;&gt;九、Add &amp;amp; Norm 与 FFN&lt;/h2&gt;
&lt;h3 id=&#34;91-残差连接&#34;&gt;9.1 残差连接&lt;/h3&gt;
&lt;p&gt;Self-Attention 的输出会做一个残差连接：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Output = LayerNorm(Z + X)&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;也就是把 Attention 前的输入 X 和 Attention 后的输出 Z 相加，再 Layer Normalization。&lt;/p&gt;
&lt;p&gt;残差连接的作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缓解梯度消失，帮助深层网络训练&lt;/li&gt;
&lt;li&gt;保留原始输入信息，避免 Attention 过度改变表示&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;输入 X&amp;#34;] --&amp;gt; B[&amp;#34;Self-Attention&amp;#34;]
    B --&amp;gt; C[&amp;#34;Z&amp;#34;]
    A --&amp;gt; D[&amp;#34;相加&amp;lt;br/&amp;gt;X + Z&amp;#34;]
    C --&amp;gt; D
    D --&amp;gt; E[&amp;#34;LayerNorm&amp;#34;]
    E --&amp;gt; F[&amp;#34;输出&amp;#34;]

    style F fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;92-feed-forward-network&#34;&gt;9.2 Feed Forward Network&lt;/h3&gt;
&lt;p&gt;每个位置独立经过两层全连接：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;FFN(x) = max(0, x × W₁ + b₁) × W₂ + b₂&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;中间用 ReLU 激活&lt;/li&gt;
&lt;li&gt;通常先升维（4 倍），再降维回原维度&lt;/li&gt;
&lt;li&gt;每个位置独立计算，不跨位置交互&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FFN 的作用是为模型引入非线性变换能力，增强表达能力。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;输入 x&amp;#34;] --&amp;gt; B[&amp;#34;线性层 1&amp;lt;br/&amp;gt;x × W₁ + b₁&amp;#34;]
    B --&amp;gt; C[&amp;#34;ReLU 激活&amp;lt;br/&amp;gt;max(0, ...)&amp;#34;]
    C --&amp;gt; D[&amp;#34;线性层 2&amp;lt;br/&amp;gt;× W₂ + b₂&amp;#34;]
    D --&amp;gt; E[&amp;#34;输出&amp;#34;]

    style E fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;93-一个完整的-transformer-block&#34;&gt;9.3 一个完整的 Transformer Block&lt;/h3&gt;
&lt;p&gt;把上面的模块拼起来，就是一个标准的 Transformer Block：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;输入 X&amp;#34;] --&amp;gt; B[&amp;#34;Masked Self-Attention&amp;#34;]
    B --&amp;gt; C[&amp;#34;X + Attention输出&amp;#34;]
    A --&amp;gt; C
    C --&amp;gt; D[&amp;#34;LayerNorm&amp;#34;]
    D --&amp;gt; E[&amp;#34;FFN&amp;#34;]
    E --&amp;gt; F[&amp;#34;D + FFN输出&amp;#34;]
    D --&amp;gt; F
    F --&amp;gt; G[&amp;#34;LayerNorm&amp;#34;]
    G --&amp;gt; H[&amp;#34;输出&amp;#34;]

    style H fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这个 Block 会重复堆叠几十层（比如 GPT-3 有 96 层）。每一层都在前一层的基础上进一步提炼信息。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十decoder-与自回归生成&#34;&gt;十、Decoder 与自回归生成&lt;/h2&gt;
&lt;h3 id=&#34;101-编码器-vs-解码器&#34;&gt;10.1 编码器 vs 解码器&lt;/h3&gt;
&lt;p&gt;原始 Transformer 有 Encoder 和 Decoder：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encoder&lt;/strong&gt;：读取整个输入序列，生成上下文表示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decoder&lt;/strong&gt;：根据已生成的 Token，逐个预测下一个 Token&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但我们常用的 GPT、DeepSeek、Claude 等都是 &lt;strong&gt;Decoder-only&lt;/strong&gt; 结构，只有解码器。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    subgraph &amp;#34;原始 Transformer&amp;#34;
        A[&amp;#34;输入序列&amp;#34;] --&amp;gt; B[&amp;#34;Encoder&amp;#34;]
        B --&amp;gt; C[&amp;#34;上下文表示&amp;#34;]
        C --&amp;gt; D[&amp;#34;Decoder&amp;#34;]
        D --&amp;gt; E[&amp;#34;输出序列&amp;#34;]
    end

    subgraph &amp;#34;GPT / Claude / DeepSeek&amp;lt;br/&amp;gt;Decoder-only&amp;#34;
        F[&amp;#34;已生成 Token&amp;#34;] --&amp;gt; G[&amp;#34;Decoder&amp;#34;]
        G --&amp;gt; H[&amp;#34;预测下一个 Token&amp;#34;]
        H --&amp;gt; I[&amp;#34;拼回输入&amp;#34;]
        I --&amp;gt; F
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;102-因果掩码&#34;&gt;10.2 因果掩码&lt;/h3&gt;
&lt;p&gt;Decoder 在训练和推理时都不能偷看未来的 Token，所以要用因果掩码（Causal Mask）。它用一个 4×4 的下三角矩阵表示：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[[0, -∞, -∞, -∞],
 [0,  0, -∞, -∞],
 [0,  0,  0, -∞],
 [0,  0,  0,  0]]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;上三角为 -∞，经过 softmax 后变成 0，从而实现&amp;quot;不能看未来&amp;quot;的约束。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph &amp;#34;位置 1&amp;#34;
        A1[&amp;#34;只能看到自己&amp;lt;br/&amp;gt;你&amp;#34;]
    end
    subgraph &amp;#34;位置 2&amp;#34;
        A2[&amp;#34;可以看到&amp;lt;br/&amp;gt;你、好&amp;#34;]
    end
    subgraph &amp;#34;位置 3&amp;#34;
        A3[&amp;#34;可以看到&amp;lt;br/&amp;gt;你、好、世&amp;#34;]
    end
    subgraph &amp;#34;位置 4&amp;#34;
        A4[&amp;#34;可以看到&amp;lt;br/&amp;gt;你、好、世、界&amp;#34;]
    end

    A1 --&amp;gt; A2 --&amp;gt; A3 --&amp;gt; A4&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;103-预测下一个-token&#34;&gt;10.3 预测下一个 Token&lt;/h3&gt;
&lt;p&gt;Decoder 最后一个位置的隐藏状态 h_t，经过线性层和 softmax，得到词表上的概率分布：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;logits = W_o × h_t + b_o
probabilities = softmax(logits)&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;词表通常有几万维，每一维代表一个 Token 的概率。选择概率最高的 Token 作为输出。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;最后一个隐藏状态 h_t&amp;#34;] --&amp;gt; B[&amp;#34;线性层&amp;lt;br/&amp;gt;W_o × h_t + b_o&amp;#34;]
    B --&amp;gt; C[&amp;#34;Logits&amp;lt;br/&amp;gt;词表大小维度的分数&amp;#34;]
    C --&amp;gt; D[&amp;#34;Softmax&amp;#34;]
    D --&amp;gt; E[&amp;#34;概率分布&amp;#34;]
    E --&amp;gt; F[&amp;#34;取 argmax&amp;lt;br/&amp;gt;或采样&amp;#34;]
    F --&amp;gt; G[&amp;#34;下一个 Token&amp;#34;]

    style G fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;104-为什么预测的是-t1&#34;&gt;10.4 为什么预测的是 t+1？&lt;/h3&gt;
&lt;p&gt;训练时，输入序列的每个位置 i 都对应一个标签：下一个位置 i+1 的 Token。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;输入：[你， 好， 世， 界]
标签：[好， 世， 界， EOS]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;所以位置 i 的隐状态 h_i 被训练来预测位置 i+1。&lt;/p&gt;
&lt;p&gt;推理时，模型每次用已生成的所有 Token 预测下一个 Token，然后把它拼回输入，继续预测。&lt;/p&gt;
&lt;h3 id=&#34;105-自回归生成流程&#34;&gt;10.5 自回归生成流程&lt;/h3&gt;
&lt;p&gt;自回归的核心就是&amp;quot;一步一步来&amp;quot;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;输入：你&amp;#34;] --&amp;gt; B[&amp;#34;预测：好&amp;#34;]
    B --&amp;gt; C[&amp;#34;输入：你好&amp;#34;]
    C --&amp;gt; D[&amp;#34;预测：世&amp;#34;]
    D --&amp;gt; E[&amp;#34;输入：你好世&amp;#34;]
    E --&amp;gt; F[&amp;#34;预测：界&amp;#34;]
    F --&amp;gt; G[&amp;#34;输入：你好世界&amp;#34;]
    G --&amp;gt; H[&amp;#34;预测：EOS&amp;#34;]
    H --&amp;gt; I[&amp;#34;结束&amp;#34;]

    style I fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;106-训练-vs-推理有什么不一样&#34;&gt;10.6 训练 vs 推理：有什么不一样？&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    subgraph 训练阶段
        A[&amp;#34;输入：你好世界&amp;#34;] --&amp;gt; B[&amp;#34;一次前向传播&amp;#34;]
        B --&amp;gt; C[&amp;#34;同时计算所有位置&amp;#34;]
        C --&amp;gt; D[&amp;#34;位置1 预测 好&amp;lt;br/&amp;gt;位置2 预测 世&amp;lt;br/&amp;gt;位置3 预测 界&amp;lt;br/&amp;gt;位置4 预测 EOS&amp;#34;]
    end

    subgraph 推理阶段
        E[&amp;#34;输入：你&amp;#34;] --&amp;gt; F[&amp;#34;预测 好&amp;#34;]
        F --&amp;gt; G[&amp;#34;输入：你好&amp;#34;]
        G --&amp;gt; H[&amp;#34;预测 世&amp;#34;]
        H --&amp;gt; I[&amp;#34;...&amp;#34;]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键区别&lt;/strong&gt;：训练时和推理时都会用因果掩码，区别在于——训练时可以一次性输入整句话，并行计算所有位置（同时得到所有位置的预测结果）；推理时只能一个一个地生成，每次把已生成的 Token 拼回去再预测下一个。&lt;/p&gt;
&lt;h3 id=&#34;107-生成什么时候结束&#34;&gt;10.7 生成什么时候结束？&lt;/h3&gt;
&lt;p&gt;通常有两个停止条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;生成了结束符 &lt;strong&gt;EOS&lt;/strong&gt;（End of Sequence）&lt;/li&gt;
&lt;li&gt;达到了预设的最大生成长度&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;实际工程中还会加上停止字符串等兜底策略。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;模型预测下一个 Token&amp;#34;] --&amp;gt; B{&amp;#34;是 EOS 吗？&amp;#34;}
    B --&amp;gt;|是| C[&amp;#34;结束生成&amp;#34;]
    B --&amp;gt;|否| D{&amp;#34;超过最大长度？&amp;#34;}
    D --&amp;gt;|是| C
    D --&amp;gt;|否| E[&amp;#34;拼回输入&amp;lt;br/&amp;gt;继续预测&amp;#34;]
    E --&amp;gt; A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;十一模型是怎么训练出来的&#34;&gt;十一、模型是怎么训练出来的？&lt;/h2&gt;
&lt;p&gt;理解 Transformer 的结构后，再来看模型是怎么&amp;quot;学会&amp;quot;的。整个过程可以分成两个阶段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;预训练（Pre-training）&lt;/strong&gt;：让模型学会语言的基本规律&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;微调（Fine-tuning）&lt;/strong&gt;：让模型学会遵循指令、生成有用回答&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/gpt-training-pretrain-finetune.webp&#34; alt=&#34;GPT 训练过程概览&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;111-预训练词语接龙&#34;&gt;11.1 预训练：词语接龙&lt;/h3&gt;
&lt;p&gt;预训练阶段，模型会阅读海量文本（网页、书籍、维基百科等），学习目标很简单：给定前 N 个 Token，预测第 N+1 个 Token。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;今天是个好天气，我准备去____&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;模型会预测&amp;quot;公园&amp;quot;、&amp;ldquo;超市&amp;rdquo;、&amp;ldquo;图书馆&amp;quot;等词的概率。预测错了就调整参数，预测对了也微调，让概率分布更接近真实世界。&lt;/p&gt;
&lt;p&gt;GPT-3 的预训练数据构成如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/gpt3-dataset-table.webp&#34; alt=&#34;GPT-3 训练数据集&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;可以看到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Common Crawl&lt;/strong&gt; 占大头，但经过了过滤&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebText2&lt;/strong&gt; 是高质量网页文本&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Books1/Books2&lt;/strong&gt; 是书籍数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wikipedia&lt;/strong&gt; 虽然量少但质量高&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Common Crawl 的数据来源非常广泛：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/commoncrawl-sources.webp&#34; alt=&#34;Common Crawl 数据来源分布&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;预训练完成后得到的是&lt;strong&gt;基座模型（Base Model）&lt;/strong&gt;。它很擅长&amp;quot;续写&amp;rdquo;，但不一定擅长对话或遵循指令。比如你让它&amp;quot;写一首关于月亮的诗&amp;quot;，它可能只会开始写关于月亮的百科介绍。&lt;/p&gt;
&lt;h3 id=&#34;112-微调让模型变成助手&#34;&gt;11.2 微调：让模型变成&amp;quot;助手&amp;quot;&lt;/h3&gt;
&lt;p&gt;微调阶段，研究人员会准备大量高质量的&amp;quot;指令-回答&amp;quot;数据对，比如 Alpaca 数据集：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/alpaca-finetune-dataset.webp&#34; alt=&#34;Alpaca 微调数据集示例&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;每一行包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Instruction&lt;/strong&gt;：任务指令&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input&lt;/strong&gt;：可选的输入上下文&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output&lt;/strong&gt;：期望的回答&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text&lt;/strong&gt;：拼接后的完整训练样本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过在这些数据上继续训练，模型学会了理解指令、按格式输出、拒绝有害请求等能力，最终变成我们日常使用的&lt;strong&gt;助手模型（Assistant Model）&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;113-rlhf人类反馈强化学习&#34;&gt;11.3 RLHF：人类反馈强化学习&lt;/h3&gt;
&lt;p&gt;更进一步的训练还会用到 RLHF（Reinforcement Learning from Human Feedback）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;让模型对同一个问题生成多个回答&lt;/li&gt;
&lt;li&gt;人类标注员比较哪个回答更好&lt;/li&gt;
&lt;li&gt;用这些比较数据训练一个&amp;quot;奖励模型&amp;quot;&lt;/li&gt;
&lt;li&gt;用奖励模型指导基座模型生成更人类喜欢的回答&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/rlhf-comparison-labeling.webp&#34; alt=&#34;RLHF 比较标注&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;为什么用&amp;quot;比较&amp;quot;而不是&amp;quot;写答案&amp;quot;？因为对人类来说，判断哪个回答更好往往比自己写回答容易得多。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十二上下文窗口的限制&#34;&gt;十二、上下文窗口的限制&lt;/h2&gt;
&lt;p&gt;前文提到，Transformer 的上下文窗口不是无限的。GPT-3 只有 2,048 个 Token，GPT-4 后来扩展到 128K，但即便如此，&lt;strong&gt;长上下文下的信息检索也会下降&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;下面这张图是著名的&amp;quot;大海捞针&amp;quot;测试（Needle In A Haystack）：把一条关键信息藏在长文档的不同位置，然后让模型回答相关问题。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ftmao.com/blog/blog/images/transformer-juejin/needle-in-haystack-context.webp&#34; alt=&#34;大海捞针测试：长上下文检索准确率&#34;&gt;
&lt;em&gt;图片来源：&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;《LLM 安全 | 大语言模型应用安全入门》&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;绿色表示模型能准确找到信息，红色/黄色表示失败。可以看到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当文档较短时，模型几乎全能找到&lt;/li&gt;
&lt;li&gt;当文档很长、且关键信息位于中间位置时，准确率明显下降&lt;/li&gt;
&lt;li&gt;这就是常说的 &lt;strong&gt;&amp;ldquo;Lost in the Middle&amp;rdquo;&lt;/strong&gt; 问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对 AI 工程师的启示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要把整本书直接塞进 Prompt&lt;/li&gt;
&lt;li&gt;做 RAG 时，召回的 chunk 要尽量精准&lt;/li&gt;
&lt;li&gt;关键信息尽量放在上下文的开头或结尾&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十三这些知识在工程中有什么用&#34;&gt;十三、这些知识在工程中有什么用？&lt;/h2&gt;
&lt;h3 id=&#34;131-理解-token-消耗&#34;&gt;13.1 理解 Token 消耗&lt;/h3&gt;
&lt;p&gt;模型的输入和输出都按 Token 计费。理解 Tokenizer 后，你会知道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么中文比英文更&amp;quot;贵&amp;quot;&lt;/li&gt;
&lt;li&gt;为什么同样的 Prompt 在不同模型上价格不同&lt;/li&gt;
&lt;li&gt;为什么长文本容易超出上下文窗口&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;132-设计更好的-rag&#34;&gt;13.2 设计更好的 RAG&lt;/h3&gt;
&lt;p&gt;Attention 机制让模型能关注输入中的相关信息。做 RAG 时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;召回的 chunk 要尽量相关&lt;/li&gt;
&lt;li&gt;上下文不能太长，否则注意力会稀释&lt;/li&gt;
&lt;li&gt;关键信息要放在 Prompt 的重要位置&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;133-理解-llm-的局限性&#34;&gt;13.3 理解 LLM 的局限性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;LLM 是自回归生成，每次只预测下一个 Token，所以会出现&amp;quot;说胡话&amp;quot;&lt;/li&gt;
&lt;li&gt;没有真正的推理，只是概率模式匹配&lt;/li&gt;
&lt;li&gt;上下文窗口有限，不能无限记忆&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些认知会直接影响你的产品设计方案。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十四延伸deepseek-的-mla&#34;&gt;十四、延伸：DeepSeek 的 MLA&lt;/h2&gt;
&lt;p&gt;传统 Transformer 的 Attention 需要保存每个 Token 的 K 和 V，显存开销大。&lt;/p&gt;
&lt;p&gt;DeepSeek 的 &lt;strong&gt;MLA（Multi-head Latent Attention）&lt;/strong&gt; 做了压缩：不再直接存储完整的 K/V，而是存储一个低维的潜在向量，推理时动态解压。&lt;/p&gt;
&lt;p&gt;这样显著降低了显存占用，让长上下文推理更便宜。&lt;/p&gt;
&lt;p&gt;对于应用开发者来说，这意味着：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;长上下文能力的成本在下降&lt;/li&gt;
&lt;li&gt;未来可以设计更复杂的 Agent 工作流&lt;/li&gt;
&lt;li&gt;但仍要关注 Token 成本&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph &amp;#34;传统 Attention&amp;#34;
        A1[&amp;#34;每个 Token 存储完整 K, V&amp;#34;] --&amp;gt; B1[&amp;#34;显存占用大&amp;#34;]
    end

    subgraph &amp;#34;MLA&amp;#34;
        A2[&amp;#34;每个 Token 存储低维潜在向量&amp;#34;] --&amp;gt; B2[&amp;#34;推理时动态解压为 K, V&amp;#34;]
        B2 --&amp;gt; C2[&amp;#34;显存占用小&amp;#34;]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;十五总结&#34;&gt;十五、总结&lt;/h2&gt;
&lt;p&gt;Transformer 不需要你推导每个公式，但核心机制要知道：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;输入&lt;/strong&gt;：Token → Embedding + 位置编码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attention&lt;/strong&gt;：Q/K/V 计算，softmax 得到关注权重&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;残差与 FFN&lt;/strong&gt;：帮助深层网络训练和非线性表达&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decoder&lt;/strong&gt;：因果掩码 + 自回归生成&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出&lt;/strong&gt;：线性层 + softmax 预测下一个 Token&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练&lt;/strong&gt;：预训练学语言规律，微调学指令遵循&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;作为 AI 工程师，理解这些不是为了造模型，而是为了&lt;strong&gt;更好地使用模型、设计产品、控制成本&lt;/strong&gt;。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[&amp;#34;输入文本&amp;#34;] --&amp;gt; B[&amp;#34;Token + Embedding&amp;#34;]
    B --&amp;gt; C[&amp;#34;位置编码&amp;#34;]
    C --&amp;gt; D[&amp;#34;Multi-Head Self-Attention&amp;#34;]
    D --&amp;gt; E[&amp;#34;Add &amp;amp; Norm&amp;#34;]
    E --&amp;gt; F[&amp;#34;FFN&amp;#34;]
    F --&amp;gt; G[&amp;#34;Add &amp;amp; Norm&amp;#34;]
    G --&amp;gt; H[&amp;#34;重复 N 层&amp;#34;]
    H --&amp;gt; I[&amp;#34;Linear + Softmax&amp;#34;]
    I --&amp;gt; J[&amp;#34;预测下一个 Token&amp;#34;]

    style J fill:#fff4e1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;p&gt;&lt;em&gt;你对 Transformer 的哪个部分最困惑？欢迎在评论区讨论。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;参考文章&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://jalammar.github.io/illustrated-transformer/&#34;&gt;The Illustrated Transformer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://juejin.cn/post/7361253974051602441&#34;&gt;LLM 安全 | 大语言模型应用安全入门&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
