<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>深度学习 on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/</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/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/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>
    <item>
      <title>《深度学习的数学》核心算法学习总结：从梯度下降到 CNN 反向传播（中学生友好版）</title>
      <link>https://ftmao.com/blog/posts/deep-learning-math-core-algorithms/</link>
      <pubDate>Sat, 01 Nov 2025 11:16:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/deep-learning-math-core-algorithms/</guid>
      <description>&lt;h1 id=&#34;深度学习的数学核心算法学习总结&#34;&gt;《深度学习的数学》核心算法学习总结&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;目标读者：学过函数、导数、向量/矩阵基础的中学生生或刚转行的工程师。&lt;br&gt;
参考书籍：涌井良幸《深度学习的数学》&lt;br&gt;
Excel 示例：&lt;code&gt;https://www.ituring.com.cn/book/2593&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面为什么要先搞懂这-5-个算法&#34;&gt;写在前面：为什么要先搞懂这 5 个算法？&lt;/h2&gt;
&lt;p&gt;深度学习的代码看起来很复杂，但核心无非是这五个环节：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;梯度下降法&lt;/strong&gt;：告诉模型“往哪走、走多远”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NN 求解器&lt;/strong&gt;：用 Excel/数值方法直接“暴力”找出神经网络权重。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NN 误差反向传播法&lt;/strong&gt;：用导数的链式法则高效计算每个权重的调整量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CNN 求解器&lt;/strong&gt;：把同样的思路用到图像上，用卷积和池化提取特征。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CNN 误差反向传播法&lt;/strong&gt;：把反向传播扩展到卷积层和池化层。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面每一节都会先讲直觉，再给公式、例子、图解和踩坑经验。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一梯度下降法gradient-descent&#34;&gt;一、梯度下降法（Gradient Descent）&lt;/h2&gt;
&lt;h3 id=&#34;11-一句话理解&#34;&gt;1.1 一句话理解&lt;/h3&gt;
&lt;p&gt;想象你蒙着眼睛站在山坡上，想走到最低点。你每一步都：&lt;strong&gt;用脚感觉最陡的方向，然后朝相反方向跨一小步&lt;/strong&gt;。重复很多次，就能接近山谷。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“最陡的方向” = 梯度（gradient）。&lt;/li&gt;
&lt;li&gt;“相反方向” = 梯度前面加负号。&lt;/li&gt;
&lt;li&gt;“一小步” = 学习率 η（eta）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;12-数学表达式&#34;&gt;1.2 数学表达式&lt;/h3&gt;
&lt;p&gt;要找函数 $z = f(x, y)$ 的最小值，每一步：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
x_{\text{新}} &amp;amp;= x_{\text{旧}} - \eta \cdot \frac{\partial z}{\partial x} \\
y_{\text{新}} &amp;amp;= y_{\text{旧}} - \eta \cdot \frac{\partial z}{\partial y}
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;其中 $\frac{\partial z}{\partial x}$ 读作“z 对 x 的偏导数”，意思是：&lt;strong&gt;只有 x 动一点点时，z 会变多少&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;13-计算例子z--x--y&#34;&gt;1.3 计算例子：z = x² + y²&lt;/h3&gt;
&lt;p&gt;这是最简单的碗状函数，最小值在 $(0, 0)$。&lt;/p&gt;
&lt;p&gt;偏导数很容易算：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\frac{\partial z}{\partial x} &amp;amp;= 2x \\
\frac{\partial z}{\partial y} &amp;amp;= 2y
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;取学习率 $\eta = 0.1$，起点 $(3, 2)$：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;步数 $i$&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;$x_i$&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;$y_i$&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;$\frac{\partial z}{\partial x}$&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;$\frac{\partial z}{\partial y}$&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;$\Delta x$&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;$\Delta y$&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;$z = x^2 + y^2$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;6.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;4.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.60&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.40&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;13.00&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2.40&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1.60&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;4.80&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3.20&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.48&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.32&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;8.32&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1.92&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1.28&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3.84&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2.56&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.38&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.26&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;5.32&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1.54&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1.02&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3.07&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2.05&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.31&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.20&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3.41&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;4&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1.23&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.82&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2.46&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;1.64&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.25&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.16&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2.18&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;13&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.16&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.11&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.33&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.22&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.03&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.02&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.04&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;18&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.05&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.04&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.11&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.07&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.01&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;-0.01&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.00&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;30&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.01&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.00&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;0.00&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;可以看到：z 越来越小，x、y 越来越靠近 0。Excel 文件 &lt;code&gt;2-11 梯度下降法.xlsx&lt;/code&gt; 就是用完全相同的公式做出来的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;14-流程图&#34;&gt;1.4 流程图&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
    A[初始化参数 x, y] --&amp;gt; B[计算当前梯度]
    B --&amp;gt; C{梯度是否足够小？}
    C --&amp;gt;|是| D[结束，得到近似最优解]
    C --&amp;gt;|否| E[按 x := x - η·grad 更新]
    E --&amp;gt; B&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;15-结构分解图&#34;&gt;1.5 结构分解图&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 LR
    subgraph 输入
        X[&amp;#34;x&amp;#34;]
        Y[&amp;#34;y&amp;#34;]
    end
    subgraph 目标函数
        F[&amp;#34;z = x² + y²&amp;#34;]
    end
    subgraph 输出
        G[&amp;#34;梯度 (∂z/∂x, ∂z/∂y)&amp;#34;]
        L[&amp;#34;当前损失 z&amp;#34;]
    end
    X --&amp;gt; F
    Y --&amp;gt; F
    F --&amp;gt; G
    F --&amp;gt; L
    G --&amp;gt; U[&amp;#34;更新 x, y&amp;#34;]
    U --&amp;gt; X&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;16-使用注意点--避坑指南&#34;&gt;1.6 使用注意点 / 避坑指南&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;坑&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;现象&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;处理方法&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;学习率 η 太大&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;左右震荡、loss 不下降甚至发散到 NaN&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;先设小一点（如 0.001、0.01），再调大&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;学习率 η 太小&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;收敛极慢，训练一万轮还在原地&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;逐步放大，或使用学习率衰减/热身&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;局部最小值&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;卡在不是全局最低的山谷&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;换初始化、用 Momentum/Adam、增加随机性&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;特征尺度不一致&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;某个参数梯度特别大，更新不稳定&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;先标准化/归一化输入数据&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;没有检查收敛&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;一直在迭代，不知道何时停&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;设定 loss 阈值、最大迭代次数或早停 Early Stopping&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;17-异常场景处理&#34;&gt;1.7 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Loss 变成 NaN/Inf&lt;/strong&gt;：立刻减小学习率，检查输入是否归一化，检查是否出现 &lt;code&gt;log(0)&lt;/code&gt; 或除零。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss 不动&lt;/strong&gt;：检查梯度是否接近 0（可能进入平台或死区），换激活函数（如 ReLU），或减少正则化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss 震荡不下降&lt;/strong&gt;：学习率过大，改用 Momentum 或 Adam，或者降低 batch size。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二nn-求解器用优化器求解器训练神经网络&#34;&gt;二、NN 求解器（用优化器/求解器训练神经网络）&lt;/h2&gt;
&lt;h3 id=&#34;21-神经网络在做什么&#34;&gt;2.1 神经网络在做什么？&lt;/h3&gt;
&lt;p&gt;神经网络 = 很多层“加权求和 + 激活函数”拼在一起。&lt;/p&gt;
&lt;p&gt;以书中“0 和 1 的识别”为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输入：3×4 = 12 个像素（0 或 1）。&lt;/li&gt;
&lt;li&gt;隐藏层：3 个神经元。&lt;/li&gt;
&lt;li&gt;输出层：2 个神经元，分别代表“是 0”还是“是 1”。&lt;/li&gt;
&lt;/ul&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
    subgraph 输入层[&amp;#34;输入层（12 个像素）&amp;#34;]
        I1((x₁))
        I2((x₂))
        I3((x₃))
        IDOTS[...]
        I12((x₁₂))
    end
    subgraph 隐藏层[&amp;#34;隐藏层（3 个神经元）&amp;#34;]
        H1((h₁))
        H2((h₂))
        H3((h₃))
    end
    subgraph 输出层[&amp;#34;输出层（2 个神经元）&amp;#34;]
        O1((是 0))
        O2((是 1))
    end

    I1 --&amp;gt; H1
    I1 --&amp;gt; H2
    I1 --&amp;gt; H3
    I2 --&amp;gt; H1
    I2 --&amp;gt; H2
    I2 --&amp;gt; H3
    I3 --&amp;gt; H1
    I3 --&amp;gt; H2
    I3 --&amp;gt; H3
    I12 --&amp;gt; H1
    I12 --&amp;gt; H2
    I12 --&amp;gt; H3

    H1 --&amp;gt; O1
    H1 --&amp;gt; O2
    H2 --&amp;gt; O1
    H2 --&amp;gt; O2
    H3 --&amp;gt; O1
    H3 --&amp;gt; O2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;每个箭头都代表一个权重 &lt;code&gt;w&lt;/code&gt;，每个圆圈（神经元）里都会做“加权求和 + 激活函数”。&lt;/p&gt;
&lt;h3 id=&#34;22-前向传播公式&#34;&gt;2.2 前向传播公式&lt;/h3&gt;
&lt;p&gt;对单个神经元：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\text{加权求和：} \quad z &amp;amp;= w_1 x_1 + w_2 x_2 + \dots + w_n x_n + b \\
\text{激活输出：} \quad a &amp;amp;= \sigma(z) = \frac{1}{1 + e^{-z}}
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;&lt;code&gt;σ&lt;/code&gt; 叫 Sigmoid 函数，能把任意实数压到 0-1 之间，适合当“概率”。&lt;/p&gt;
&lt;p&gt;如果写成更清晰的“层”形式：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;隐藏层第 j 个神经元&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
z_j^{(2)} &amp;amp;= \sum_{i=1}^{12} w_{ji}^{(1)} \cdot x_i + b_j^{(1)} \\
a_j^{(2)} &amp;amp;= \sigma\left(z_j^{(2)}\right)
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出层第 k 个神经元&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
z_k^{(3)} &amp;amp;= \sum_{j=1}^{3} w_{kj}^{(2)} \cdot a_j^{(2)} + b_k^{(3)} \\
a_k^{(3)} &amp;amp;= \sigma\left(z_k^{(3)}\right)
\end{aligned}
$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$x_i$：输入像素（12 个）。&lt;/li&gt;
&lt;li&gt;$w_{ji}^{(1)}$：输入到隐藏层的权重。&lt;/li&gt;
&lt;li&gt;$b_j^{(1)}$：隐藏层的偏置。&lt;/li&gt;
&lt;li&gt;$a_j^{(2)}$：隐藏层输出。&lt;/li&gt;
&lt;li&gt;$w_{kj}^{(2)}$：隐藏层到输出层的权重。&lt;/li&gt;
&lt;li&gt;$b_k^{(3)}$：输出层的偏置。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;23-excel-里的实现测试表&#34;&gt;2.3 Excel 里的实现（测试表）&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;3-5 NN（求解器）.xlsx&lt;/code&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-excel&#34; data-lang=&#34;excel&#34;&gt;# 隐藏层第一个神经元
=SUMPRODUCT(L5:N8, $D$5:$F$8) + $G$5

# Sigmoid 激活
=1/(1+EXP(-O11))

# 输出层
=MMULT($D$17:$F$17, O14:O16) + $G$17&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;对应上面的数学公式：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;Excel 公式&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;数学含义&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;Excel 函数说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;SUMPRODUCT(L5:N8, $D$5:$F$8)&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$\sum_{i=1}^{12} w_i \cdot x_i$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;把两个区域里&lt;strong&gt;对应位置相乘，再把所有乘积加起来&lt;/strong&gt;，本质就是向量的&lt;strong&gt;点积/内积&lt;/strong&gt;。这里输入像素放在 &lt;code&gt;L5:N8&lt;/code&gt;，对应权重放在 &lt;code&gt;$D$5:$F$8&lt;/code&gt;。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;+ $G$5&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$+ b_j^{(1)}$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;加上隐藏层第 1 个神经元的偏置。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;1/(1+EXP(-O11))&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$\sigma(z) = \frac{1}{1 + e^{-z}}$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Sigmoid 激活函数。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;MMULT($D$17:$F$17, O14:O16)&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$\sum_{j=1}^{3} w_{kj}^{(2)} \cdot a_j^{(2)}$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;矩阵乘法&lt;/strong&gt;。&lt;code&gt;$D$17:$F$17&lt;/code&gt; 是 1×3 的输出行权重，&lt;code&gt;O14:O16&lt;/code&gt; 是 3×1 的隐藏层输出列向量，乘出来是一个标量。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;+ $G$17&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$+ b_k^{(3)}$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;加上输出层第 k 个神经元的偏置。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;一句话总结：&lt;strong&gt;Excel 里先用 &lt;code&gt;SUMPRODUCT&lt;/code&gt; 做点积，再用 &lt;code&gt;MMULT&lt;/code&gt; 做矩阵乘法，最后都加上偏置、过 Sigmoid&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;24-计算例子&#34;&gt;2.4 计算例子&lt;/h3&gt;
&lt;h4 id=&#34;例子-1隐藏层神经元sumproduct-在算什么&#34;&gt;例子 1：隐藏层神经元（SUMPRODUCT 在算什么）&lt;/h4&gt;
&lt;p&gt;完整公式是：&lt;/p&gt;
&lt;p&gt;$$
z_j^{(2)} = \sum_{i=1}^{12} w_{ji}^{(1)} \cdot x_i + b_j^{(1)}
$$&lt;/p&gt;
&lt;p&gt;为了手写方便，下面只看前 3 个输入和权重，演示这个过程。假设：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{w} = [-2.06,\ 3.36,\ -0.63]^\top,\quad b = -0.99,\quad \mathbf{x} = [1,\ 1,\ 1]^\top
$$&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
z &amp;amp;= (-2.06) \times 1 + 3.36 \times 1 + (-0.63) \times 1 + (-0.99) \\
&amp;amp;= -0.32 \\[6pt]
a &amp;amp;= \sigma(-0.32) = \frac{1}{1 + e^{0.32}} \approx 0.42
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;Excel 里会用 &lt;code&gt;SUMPRODUCT(L5:N8, $D$5:$F$8)&lt;/code&gt; 一次性把 12 项都乘好再加起来，然后 &lt;code&gt;+ $G$5&lt;/code&gt; 加上偏置。&lt;/p&gt;
&lt;h4 id=&#34;例子-2输出层神经元mmult-在算什么&#34;&gt;例子 2：输出层神经元（MMULT 在算什么）&lt;/h4&gt;
&lt;p&gt;隐藏层输出（来自书中 Excel 第一个样本的近似值）：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{a}^{(2)} = [1.5 \times 10^{-6},\ 0.99999999,\ 0.99999997]^\top
$$&lt;/p&gt;
&lt;p&gt;输出神经元 1 的权重和偏置：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{w}_1^{(2)} = [-14.25,\ -3.70,\ 9.33],\quad b_1^{(2)} = 6.64
$$&lt;/p&gt;
&lt;p&gt;输出层的计算就是一次 &lt;strong&gt;1×3 矩阵 × 3×1 向量&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
z_1^{(3)} &amp;amp;= (-14.25) \times 1.5 \times 10^{-6} + (-3.70) \times 0.99999999 + 9.33 \times 0.99999997 + 6.64 \\
&amp;amp;\approx -3.70 + 9.33 + 6.64 \\
&amp;amp;\approx 12.28 \\[6pt]
a_1^{(3)} &amp;amp;= \sigma(12.28) \approx 0.999995
\end{aligned}
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;含义：模型非常确信这个样本是“0”。Excel 里的 &lt;code&gt;MMULT($D$17:$F$17, O14:O16)&lt;/code&gt; 做的就是这一步矩阵乘法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;25-流程图&#34;&gt;2.5 流程图&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 LR
    I[&amp;#34;输入图像像素 x&amp;#34;] --&amp;gt; W1[&amp;#34;隐藏层加权求和 z²&amp;#34;]
    W1 --&amp;gt; A1[&amp;#34;Sigmoid 激活 a²&amp;#34;]
    A1 --&amp;gt; W2[&amp;#34;输出层加权求和 z³&amp;#34;]
    W2 --&amp;gt; A2[&amp;#34;输出概率 a³&amp;#34;]
    A2 --&amp;gt; C[&amp;#34;计算损失 C&amp;#34;]
    C --&amp;gt; S[&amp;#34;Excel 求解器调整 w, b&amp;#34;]
    S --&amp;gt; W1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;26-使用注意点--避坑&#34;&gt;2.6 使用注意点 / 避坑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;求解器=黑盒&lt;/strong&gt;：Excel Solver 是通过数值方法搜索最优解，参数多的时候很慢，且容易陷入局部最优。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;权重初始化别全 0&lt;/strong&gt;：如果所有权重相同，所有神经元学到的东西也相同，模型退化成“单神经元”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据量不能太少&lt;/strong&gt;：书中只有几十张图是为了教学，真实项目通常需要成千上万张。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出层要配对损失函数&lt;/strong&gt;：二分类用 Sigmoid + 交叉熵，多分类用 Softmax + 交叉熵。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;27-异常场景处理&#34;&gt;2.7 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;求解器提示“找不到可行解”&lt;/strong&gt;：检查公式是否有 &lt;code&gt;#VALUE!&lt;/code&gt;、输入是否规范、约束是否合理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练集准确率 100% 但测试集很差&lt;/strong&gt;：过拟合，增加数据或加正则化/Dropout。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出全是一个类别&lt;/strong&gt;：标签不平衡，或最后一层权重初始化导致，检查损失函数是否写对。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三nn-误差反向传播法backpropagation&#34;&gt;三、NN 误差反向传播法（Backpropagation）&lt;/h2&gt;
&lt;h3 id=&#34;31-核心思想链式法则&#34;&gt;3.1 核心思想：链式法则&lt;/h3&gt;
&lt;p&gt;反向传播就是&lt;strong&gt;从输出倒推，计算每个权重对最终误差的贡献&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;中学学过的复合函数求导：&lt;/p&gt;
&lt;p&gt;如果 $y=f(u)$，$u=g(x)$，那么 $\frac{dy}{dx} = \frac{dy}{du} \cdot \frac{du}{dx}$。&lt;/p&gt;
&lt;p&gt;神经网络层数很多，就是一层一层套起来的复合函数。反向传播只是把链式法则系统化地算一遍。&lt;/p&gt;
&lt;h3 id=&#34;32-计算图&#34;&gt;3.2 计算图&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 LR
    X[&amp;#34;x&amp;#34;] --&amp;gt; M[&amp;#34;× w&amp;#34;]
    B[&amp;#34;b&amp;#34;] --&amp;gt; S[&amp;#34;+ b = z&amp;#34;]
    M --&amp;gt; S
    S --&amp;gt; A[&amp;#34;Sigmoid a&amp;#34;]
    A --&amp;gt; L[&amp;#34;损失 C&amp;#34;]
    L --&amp;gt; D[&amp;#34;反向求 ∂C/∂w, ∂C/∂b&amp;#34;]
    D --&amp;gt; M
    D --&amp;gt; B&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;33-反向传播公式简化版&#34;&gt;3.3 反向传播公式（简化版）&lt;/h3&gt;
&lt;p&gt;设某层输出为 $a$，加权输入为 $z$，下一层传来的误差为 $\delta_{\text{next}}$：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\delta &amp;amp;= \delta_{\text{next}} \cdot w \cdot \sigma&amp;rsquo;(z) \\
\frac{\partial C}{\partial w} &amp;amp;= a_{\text{prev}} \cdot \delta \\
\frac{\partial C}{\partial b} &amp;amp;= \delta
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;其中 $\sigma&amp;rsquo;(z)$ 是 Sigmoid 的导数：&lt;/p&gt;
&lt;p&gt;$$
\sigma&amp;rsquo;(z) = \sigma(z) \cdot (1 - \sigma(z))
$$&lt;/p&gt;
&lt;h3 id=&#34;34-计算例子&#34;&gt;3.4 计算例子&lt;/h3&gt;
&lt;p&gt;假设只有一个输入 &lt;code&gt;x = 1&lt;/code&gt;，目标输出 &lt;code&gt;t = 1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;网络：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
z &amp;amp;= w \cdot x + b \\
a &amp;amp;= \sigma(z) \\
C &amp;amp;= \frac{1}{2}(a - t)^2 \quad \text{（平方误差）}
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;初始 &lt;code&gt;w = 0.5&lt;/code&gt;，&lt;code&gt;b = 0&lt;/code&gt;，学习率 &lt;code&gt;η = 0.1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前向&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
z &amp;amp;= 0.5 \times 1 + 0 = 0.5 \\
a &amp;amp;= \sigma(0.5) \approx 0.6225 \\
C &amp;amp;= \frac{1}{2}(0.6225 - 1)^2 \approx 0.0712
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;反向&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\frac{\partial C}{\partial a} &amp;amp;= a - t = -0.3775 \\
\sigma&amp;rsquo;(z) &amp;amp;= a(1 - a) \approx 0.6225 \times 0.3775 \approx 0.2350 \\
\delta &amp;amp;= \frac{\partial C}{\partial a} \cdot \sigma&amp;rsquo;(z) \approx -0.0887 \\[6pt]
\frac{\partial C}{\partial w} &amp;amp;= x \cdot \delta = -0.0887 \\
\frac{\partial C}{\partial b} &amp;amp;= \delta = -0.0887
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;更新&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
w_{\text{new}} &amp;amp;= 0.5 - 0.1 \times (-0.0887) \approx 0.5089 \\
b_{\text{new}} &amp;amp;= 0 - 0.1 \times (-0.0887) \approx 0.0089
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;再算一次前向，&lt;code&gt;a&lt;/code&gt; 会比 0.6225 更接近 1，误差减小。&lt;/p&gt;
&lt;h3 id=&#34;35-流程图&#34;&gt;3.5 流程图&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
    F[&amp;#34;前向传播：算 z, a, C&amp;#34;] --&amp;gt; B[&amp;#34;从输出层开始反向求 δ&amp;#34;]
    B --&amp;gt; G[&amp;#34;计算 ∂C/∂w, ∂C/∂b&amp;#34;]
    G --&amp;gt; U[&amp;#34;梯度下降更新权重&amp;#34;]
    U --&amp;gt; F&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;36-使用注意点--避坑&#34;&gt;3.6 使用注意点 / 避坑&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;坑&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;说明&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;处理&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;Sigmoid 梯度消失&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;输入很大或很小时，Sigmoid 导数接近 0，深层网络传不动误差&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用 ReLU / LeakyReLU&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;ReLU 死亡&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;某些神经元永远输出 0，梯度也永远 0&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用 LeakyReLU、PReLU，或调小学习率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;梯度爆炸&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;深层网络梯度越乘越大，权重变成 NaN&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;梯度裁剪（Gradient Clipping）、BatchNorm、残差连接&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;损失与输出不匹配&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用 Sigmoid 配 Softmax 损失会出问题&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;二分类用 &lt;code&gt;binary_crossentropy&lt;/code&gt;，多分类用 &lt;code&gt;categorical_crossentropy&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;batch 太小&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;梯度噪声大，训练抖动&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;增大 batch，或使用带动量的优化器&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;37-异常场景处理&#34;&gt;3.7 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;某层梯度全为 0&lt;/strong&gt;：可能是激活函数“死”了，或学习率过大导致参数进入饱和区。检查激活函数输出分布。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练 loss 下降但验证 loss 上升&lt;/strong&gt;：典型过拟合，早停或加 Dropout。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不同层梯度尺度差 1000 倍&lt;/strong&gt;：深层网络梯度不稳定，考虑 Batch Normalization 或更合适的初始化（He/Xavier）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四cnn-求解器卷积神经网络训练&#34;&gt;四、CNN 求解器（卷积神经网络训练）&lt;/h2&gt;
&lt;h3 id=&#34;41-卷积是什么&#34;&gt;4.1 卷积是什么？&lt;/h3&gt;
&lt;p&gt;卷积 = 用一个小窗口（卷积核 / filter）在图片上滑来滑去，&lt;strong&gt;局部加权求和&lt;/strong&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;/ul&gt;
&lt;h3 id=&#34;42-池化pooling&#34;&gt;4.2 池化（Pooling）&lt;/h3&gt;
&lt;p&gt;池化 = 把一小块区域压缩成一个数，常用 &lt;strong&gt;Max Pooling（取最大值）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;作用：降维、减少计算量、让特征对位置变化不那么敏感。&lt;/p&gt;
&lt;h3 id=&#34;43-计算例子&#34;&gt;4.3 计算例子&lt;/h3&gt;
&lt;p&gt;输入图像（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;1 1 0 0
1 1 0 0
0 0 1 1
0 0 1 1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;卷积核（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;1  1
1 -1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;卷积&lt;/strong&gt;（无 padding，stride=1）第一步取左上角：&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;1×1 + 1×1 + 1×1 + (-1)×1 = 2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;滑完得到 3×3 特征图：&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;2  0  0
0  2  0
0  0  2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;Max Pooling（2×2，stride=2）&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;2  0
0  2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;然后拉平成 &lt;code&gt;[2, 0, 0, 2]&lt;/code&gt;，接到全连接层做分类。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;书中 &lt;code&gt;5-4 CNN（求解器）.xlsx&lt;/code&gt; 就是用类似流程识别“文字 1、2、3”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;44-结构图&#34;&gt;4.4 结构图&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 LR
    I[&amp;#34;输入图像&amp;#34;] --&amp;gt; C[&amp;#34;卷积层&amp;#34;]
    C --&amp;gt; R[&amp;#34;激活函数 ReLU/Sigmoid&amp;#34;]
    R --&amp;gt; P[&amp;#34;池化层 Max Pooling&amp;#34;]
    P --&amp;gt; F[&amp;#34;拉平 Flatten&amp;#34;]
    F --&amp;gt; D[&amp;#34;全连接层&amp;#34;]
    D --&amp;gt; O[&amp;#34;输出分类&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;45-使用注意点--避坑&#34;&gt;4.5 使用注意点 / 避坑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;输出尺寸算错&lt;/strong&gt;：卷积后尺寸为 $H_{\text{out}} = \frac{H_{\text{in}} - K + 2P}{S} + 1$，忘记 padding 会导致后续层维度不匹配。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核太大&lt;/strong&gt;：会丢失细节，图像任务一般 3×3 最常用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;池化丢失位置信息&lt;/strong&gt;：如果任务需要精确定位（如目标检测的边界框），Max Pooling 不宜太多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通道数暴涨&lt;/strong&gt;：每加一个卷积层通道数翻倍会迅速爆显存，要结合池化或stride=2降采样。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;46-异常场景处理&#34;&gt;4.6 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特征图全 0&lt;/strong&gt;：可能是权重初始化太差，或学习率过大导致 ReLU 全部死亡。加 BatchNorm 或换初始化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出尺寸报错&lt;/strong&gt;：逐层打印特征图 shape，检查核大小、stride、padding。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;显存不足&lt;/strong&gt;：减小 batch size，或减少通道数/层数。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五cnn-误差反向传播法&#34;&gt;五、CNN 误差反向传播法&lt;/h2&gt;
&lt;h3 id=&#34;51-卷积层的反向传播&#34;&gt;5.1 卷积层的反向传播&lt;/h3&gt;
&lt;p&gt;卷积的反向传播本质上仍是卷积，只是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;误差图需要和&lt;strong&gt;旋转 180° 的卷积核&lt;/strong&gt;做卷积。&lt;/li&gt;
&lt;li&gt;再乘以当前层激活函数的导数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简化公式：&lt;/p&gt;
&lt;p&gt;$$
\delta_l = \delta_{l+1} \circledast \text{rot180}(W_{l+1}) \odot f&amp;rsquo;(z_l)
$$&lt;/p&gt;
&lt;p&gt;其中 &lt;code&gt;⊛&lt;/code&gt; 表示卷积，&lt;code&gt;⊙&lt;/code&gt; 表示对应元素相乘。&lt;/p&gt;
&lt;h3 id=&#34;52-池化层的反向传播&#34;&gt;5.2 池化层的反向传播&lt;/h3&gt;
&lt;p&gt;Max Pooling 反向传播最简单：&lt;strong&gt;把误差传回给“最大值所在位置”，其余位置填 0&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 LR
    subgraph 前向
        A[&amp;#34;2 1\n0 3&amp;#34;] --&amp;gt; B[&amp;#34;Max=3&amp;#34;]
    end
    subgraph 反向
        E[&amp;#34;误差 0.5&amp;#34;] --&amp;gt; C[&amp;#34;0   0\n0 0.5&amp;#34;]
    end
    B -.-&amp;gt; E&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;53-计算例子&#34;&gt;5.3 计算例子&lt;/h3&gt;
&lt;p&gt;前向 Max Pooling 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;输入：          输出：
2  1            3
0  3&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;反向时，如果输出位置误差是 &lt;code&gt;0.5&lt;/code&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;0    0
0  0.5&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;然后继续往前传给卷积层。&lt;/p&gt;
&lt;h3 id=&#34;54-流程图&#34;&gt;5.4 流程图&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 前向
        F1[&amp;#34;卷积 + 激活&amp;#34;] --&amp;gt; F2[&amp;#34;Max Pooling&amp;#34;] --&amp;gt; F3[&amp;#34;全连接输出&amp;#34;]
    end
    subgraph 反向
        B1[&amp;#34;输出层误差 δ&amp;#34;] --&amp;gt; B2[&amp;#34;池化层反向：把误差还给最大值位置&amp;#34;]
        B2 --&amp;gt; B3[&amp;#34;卷积层反向：rot180 核卷积 δ&amp;#34;]
        B3 --&amp;gt; B4[&amp;#34;更新卷积核权重&amp;#34;]
    end
    F3 -.-&amp;gt; B1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;55-使用注意点--避坑&#34;&gt;5.5 使用注意点 / 避坑&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;坑&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;说明&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;处理&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;Max Pooling 不可导&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;它本身不是光滑函数，但反向传播时我们只把梯度传给最大值位置，工程上可行&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;注意保存前向时的“最大值位置掩码”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;stride &amp;gt; 1 反向 upsample 复杂&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;误差图尺寸变小，传回去要补 0&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;框架会自动处理，手写时要小心&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;Padding 的梯度&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;padding 区域不应该有梯度，加 padding 时要把这些位置屏蔽&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;反向传播只更新非 padding 区域&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;BatchNorm 插在卷积后&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;会改变反向传播的梯度分布，但通常更稳定&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;BN 需要和卷积一起训练&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;56-异常场景处理&#34;&gt;5.6 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;卷积核学不到东西&lt;/strong&gt;：检查初始化、学习率，或前面层是否已经“死掉”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;深层 CNN loss 不下降&lt;/strong&gt;：可能是梯度消失，加残差连接（ResNet）或 BatchNorm。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练集准确率很高，测试集很低&lt;/strong&gt;：CNN 参数多，极易过拟合，加数据增强、Dropout、L2 正则化。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六通用训练避坑指南&#34;&gt;六、通用训练避坑指南&lt;/h2&gt;
&lt;p&gt;下面这 10 条适用于 NN 和 CNN：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据先归一化&lt;/strong&gt;：像素除以 255，数值特征减去均值除以标准差。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;划分训练 / 验证 / 测试集&lt;/strong&gt;：不要拿测试集调参。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;从小模型开始&lt;/strong&gt;：先跑通一个两层的 baseline，再加深。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学习率是最重要的超参数&lt;/strong&gt;：先用默认值，再按 10 倍上下调。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控 loss 曲线&lt;/strong&gt;：训练 loss 和验证 loss 一起画，才能判断是否过拟合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;早停 Early Stopping&lt;/strong&gt;：验证 loss 连续 N 轮不降就停。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;权重初始化&lt;/strong&gt;：ReLU 用 He 初始化，Sigmoid/Tanh 用 Xavier/Glorot 初始化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch Size&lt;/strong&gt;：小 batch（16-64）通常泛化更好，大 batch 训练更快但可能陷在尖锐最小值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标签检查&lt;/strong&gt;：花 10 分钟抽样看标签是否正确，比调一周模型都有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;随机种子固定&lt;/strong&gt;：方便复现和对比实验。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七异常场景与业务异常处理&#34;&gt;七、异常场景与业务异常处理&lt;/h2&gt;
&lt;h3 id=&#34;71-训练阶段&#34;&gt;7.1 训练阶段&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;异常&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;可能原因&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;处理&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Loss = NaN&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;学习率过大、梯度爆炸、log(0)&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;降低学习率、梯度裁剪、加 ε&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Loss 完全不降&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;学习率太小、数据损坏、标签全相同&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;逐步调大 lr、检查数据pipeline&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;验证 loss 上升&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;过拟合&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;早停、Dropout、数据增强、简化模型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;训练 loss 和验证 loss 都高&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;欠拟合&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;增加模型容量、训练更久、减少正则&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;类别严重不平衡&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;某些类别样本极少&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;加权损失、过采样、Focal Loss&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;72-部署业务阶段&#34;&gt;7.2 部署/业务阶段&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;业务异常&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;表现&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;处理&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;概念漂移&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;线上数据分布变了，模型准确率下降&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;监控分布、定期重训、在线学习&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;输入越界&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用户上传纯黑图、超大图、非图片文件&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;前置校验、异常输入兜底规则&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;** adversarial 样本**&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;人眼看不出区别，模型却错判&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;对抗训练、输出置信度+人工复核&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;长尾类别错误&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;冷门类别识别率低&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;收集更多样本、用度量学习/少样本学习&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;时延/成本超标&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;模型太大，推理慢&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;剪枝、量化、蒸馏、换小模型&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;73-一个实用的排查-checklist&#34;&gt;7.3 一个实用的排查 checklist&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&gt;□ 输入数据范围对吗？（0~1 还是 -1~1？）
□ 标签编码对吗？（one-hot / integer / 概率？）
□ 损失函数和输出激活匹配吗？
□ 第一层输出 shape 符合预期吗？
□ 权重还有在更新吗？（打印梯度范数）
□ 训练一个 batch 能过拟合吗？（ Sanity Check ）
□ 学习率是不是在合理区间？&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;八总结&#34;&gt;八、总结&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;算法&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;核心作用&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;一句话口诀&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;梯度下降法&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;找函数最小值&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;看梯度，反方向，迈小步&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;NN 求解器&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用优化器直接调权重&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;输入加权求和，Sigmoid 出概率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;NN 反向传播&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;高效算每个权重的梯度&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;从后往前，链式求导&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;CNN 求解器&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;图像特征提取 + 分类&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;卷积找局部特征，池化降维&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;CNN 反向传播&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;卷积和池化的梯度回传&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;卷积核旋转 180°，池化只传最大值&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;如果你是第一次接触，建议：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先打开 &lt;code&gt;2-11 梯度下降法.xlsx&lt;/code&gt;，改改 &lt;code&gt;η&lt;/code&gt; 和起点，看 z 怎么变。&lt;/li&gt;
&lt;li&gt;再打开 &lt;code&gt;3-5 NN（求解器）.xlsx&lt;/code&gt;，试着改输入像素，观察输出概率。&lt;/li&gt;
&lt;li&gt;最后对照 &lt;code&gt;4-4&lt;/code&gt;、&lt;code&gt;5-4&lt;/code&gt;、&lt;code&gt;5-6&lt;/code&gt; 这几个 Excel，理解“求解器版”和“反向传播版”其实是同一套东西的不同实现方式。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;本文档持续维护中。如果有哪一步的公式或例子让你卡住，欢迎在评论区指出，我会继续用更直观的方式补充图解。&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
  </channel>
</rss>
