<?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/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Sat, 08 Aug 2026 11:16:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>大模型是怎么炼成的？LLM 训练全流程数学拆解（公式 &#43; 演算 &#43; 避坑）</title>
      <link>https://ftmao.com/blog/posts/llm-training-math-guide/</link>
      <pubDate>Sat, 08 Aug 2026 11:16:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/llm-training-math-guide/</guid>
      <description>&lt;h1 id=&#34;大模型是怎么炼成的llm-训练全流程数学拆解&#34;&gt;大模型是怎么炼成的？LLM 训练全流程数学拆解&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;目标读者：学过函数、导数、向量/矩阵基础，想搞清楚 LLM 训练本质的同学。&lt;br&gt;
本文目标：把“炼丹”过程拆成可计算的公式和可复现的例子。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面llm-训练其实就是猜下一个词&#34;&gt;写在前面：LLM 训练其实就是“猜下一个词”&lt;/h2&gt;
&lt;p&gt;大语言模型（Large Language Model，LLM）看起来很神秘，但核心任务可以概括为一句话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;给定前面的词，预测下一个词。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;整个训练流程可以拆成 5 大块：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据预处理&lt;/strong&gt;：把互联网上的文本变成模型能吃的“数字串”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tokenization&lt;/strong&gt;：把句子切分成 token，再映射成向量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transformer 前向传播&lt;/strong&gt;：用 Attention 机制捕捉上下文关系。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算损失&lt;/strong&gt;：模型猜的下一个词和真实下一个词差多少。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;反向传播 + 优化器&lt;/strong&gt;：用梯度调整权重，让模型越猜越准。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面每一节都会先讲直觉，再给公式、例子、图解和踩坑经验。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一训练全景图从原始文本到可用模型&#34;&gt;一、训练全景图：从原始文本到可用模型&lt;/h2&gt;
&lt;h3 id=&#34;11-一句话理解&#34;&gt;1.1 一句话理解&lt;/h3&gt;
&lt;p&gt;LLM 的训练就像教一个小孩学说话：先给他看大量书（预训练），再教他怎么礼貌回答（SFT），最后告诉他哪些回答更好（RLHF）。&lt;/p&gt;
&lt;h3 id=&#34;12-三阶段训练流程&#34;&gt;1.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
    subgraph 数据
        D1[&amp;#34;原始文本（网页、书籍、代码）&amp;#34;]
        D2[&amp;#34;清洗 / 去重 / 过滤&amp;#34;]
        D3[&amp;#34;Token 序列&amp;#34;]
    end

    subgraph 训练阶段
        P[&amp;#34;① 预训练 Pre-training&amp;#34;]
        S[&amp;#34;② 监督微调 SFT&amp;#34;]
        R[&amp;#34;③ 强化学习 RLHF / DPO&amp;#34;]
    end

    subgraph 输出
        M[&amp;#34;基础大模型&amp;#34;]
        C[&amp;#34;对话模型&amp;#34;]
        A[&amp;#34;对齐模型&amp;#34;]
    end

    D1 --&amp;gt; D2 --&amp;gt; D3 --&amp;gt; P --&amp;gt; M
    M --&amp;gt; S --&amp;gt; C
    C --&amp;gt; R --&amp;gt; A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;13-每个阶段在优化什么&#34;&gt;1.3 每个阶段在优化什么？&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;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;td style=&#34;text-align: left&#34;&gt;下一个 token 的交叉熵&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;SFT&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;（ prompt, answer ）配对&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;RLHF&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;prompt + 多条回答 + 人类排序&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;学会生成更受欢迎的回答&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;PPO / DPO 奖励模型&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二数据预处理与-tokenization&#34;&gt;二、数据预处理与 Tokenization&lt;/h2&gt;
&lt;h3 id=&#34;21-一句话理解&#34;&gt;2.1 一句话理解&lt;/h3&gt;
&lt;p&gt;模型看不懂汉字或英文，只能看数字。Tokenization 就是&lt;strong&gt;把文本切成最小单元，再查表换成整数 ID&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;22-bpe-编码例子&#34;&gt;2.2 BPE 编码例子&lt;/h3&gt;
&lt;p&gt;BPE（Byte Pair Encoding）是 LLM 最常用的分词方法，核心思想：&lt;strong&gt;把出现频率高的子词合并成一个 token&lt;/strong&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;low, lower, lowest, high, higher, highest&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;初始把每个字符当做一个 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;l, o, w, e, r, h, i, g&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;发现 &lt;code&gt;er&lt;/code&gt; 出现很多次，合并成新 token &lt;code&gt;er&lt;/code&gt;；发现 &lt;code&gt;est&lt;/code&gt; 出现很多次，合并成 &lt;code&gt;est&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;low, lower, lowest, high, higher, highest, er, est&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;23-从文本到-id-的例子&#34;&gt;2.3 从文本到 ID 的例子&lt;/h3&gt;
&lt;p&gt;假设词表（vocabulary）有 10000 个 token，其中：&lt;/p&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;Token ID&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;1024&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;7&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;2048&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;3&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;4096&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&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;变成 token ID 序列：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{x} = [1024,\ 7,\ 2048,\ 3,\ 4096]
$$&lt;/p&gt;
&lt;h3 id=&#34;24-embedding把-id-变成向量&#34;&gt;2.4 Embedding：把 ID 变成向量&lt;/h3&gt;
&lt;p&gt;每个 token ID 会查一张 Embedding 表，得到长度为 $d$ 的向量。假设 $d=4$，词表大小 $V=10000$：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{E} \in \mathbb{R}^{10000 \times 4}
$$&lt;/p&gt;
&lt;p&gt;对 token ID $1024$，取第 $1024$ 行：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{e}_{1024} = \mathbf{E}[1024] \in \mathbb{R}^4
$$&lt;/p&gt;
&lt;p&gt;整个句子就变成矩阵：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{X} =
\begin{bmatrix}
\mathbf{e}_{1024}^\top \\
\mathbf{e}_{7}^\top \\
\mathbf{e}_{2048}^\top \\
\mathbf{e}_{3}^\top \\
\mathbf{e}_{4096}^\top
\end{bmatrix}
\in \mathbb{R}^{5 \times 4}
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;实际 LLM 中 $d$ 通常是 768、1024、4096、8192 等。&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
    T[&amp;#34;原始文本&amp;#34;] --&amp;gt; B[&amp;#34;BPE / SentencePiece 分词&amp;#34;]
    B --&amp;gt; I[&amp;#34;Token ID 序列&amp;#34;]
    I --&amp;gt; E[&amp;#34;Embedding 查表&amp;#34;]
    E --&amp;gt; X[&amp;#34;输入向量矩阵 X ∈ R^(T×d)&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;26-使用注意点--避坑&#34;&gt;2.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;很多词被切成很多 token，序列变长、效率低&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;词表一般设 32k-200k&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;稀疏 token 训练不充分，Embedding 质量差&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;中文常按字切，导致同样内容 token 数比英文多&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;训练中文专用 BPE&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;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;27-异常场景处理&#34;&gt;2.7 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OOV（Out of Vocabulary）&lt;/strong&gt;：现代 BPE 会把未知字符拆成 &lt;code&gt;&amp;lt;unk&amp;gt;&lt;/code&gt; 或字节级子词，基本不会出现完全无法表示的情况。出现 &lt;code&gt;&amp;lt;unk&amp;gt;&lt;/code&gt; 过多时，检查清洗流程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;序列超长&lt;/strong&gt;： truncation 截断或滑动窗口切分，不要硬塞。&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;三transformer-架构attention--ffn&#34;&gt;三、Transformer 架构：Attention + FFN&lt;/h2&gt;
&lt;h3 id=&#34;31-一句话理解&#34;&gt;3.1 一句话理解&lt;/h3&gt;
&lt;p&gt;Transformer 就像一个“全连接阅读器”：每个词都能直接看到其他所有词，并通过 Attention 机制决定该关注谁。&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 TD
    subgraph TransformerBlock[&amp;#34;Transformer Block&amp;#34;]
        X[&amp;#34;输入 X&amp;#34;] --&amp;gt; LN1[&amp;#34;LayerNorm&amp;#34;]
        LN1 --&amp;gt; A[&amp;#34;Multi-Head Self-Attention&amp;#34;]
        A --&amp;gt; Add1[&amp;#34;X + Attention(X)&amp;#34;]
        Add1 --&amp;gt; LN2[&amp;#34;LayerNorm&amp;#34;]
        LN2 --&amp;gt; F[&amp;#34;Feed Forward Network&amp;#34;]
        F --&amp;gt; Add2[&amp;#34;+ 残差连接&amp;#34;]
    end
    Add2 --&amp;gt; OUT[&amp;#34;输出&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;堆叠很多个这样的 Block，再接一个输出层，就是 GPT 系列的结构。&lt;/p&gt;
&lt;h3 id=&#34;33-attention-的数学公式&#34;&gt;3.3 Attention 的数学公式&lt;/h3&gt;
&lt;p&gt;对于某个输入序列，先通过三个权重矩阵算出 Query、Key、Value：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\mathbf{Q} &amp;amp;= \mathbf{X} \mathbf{W}^Q \\
\mathbf{K} &amp;amp;= \mathbf{X} \mathbf{W}^K \\
\mathbf{V} &amp;amp;= \mathbf{X} \mathbf{W}^V
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;然后计算 Scaled Dot-Product Attention：&lt;/p&gt;
&lt;p&gt;$$
\text{Attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \text{softmax}\left( \frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{d_k}} \right) \mathbf{V}
$$&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$d_k$：每个 head 的 Key/Query 维度。&lt;/li&gt;
&lt;li&gt;除以 $\sqrt{d_k}$ 是为了防止点积结果太大，导致 softmax 梯度消失。&lt;/li&gt;
&lt;li&gt;softmax 把分数变成概率分布（每行之和为 1）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;34-计算例子attention-到底在算什么&#34;&gt;3.4 计算例子：Attention 到底在算什么？&lt;/h3&gt;
&lt;p&gt;假设输入序列有 3 个 token，每个 token 的向量维度 $d=4$。为了演示，简化为 $d_k = 2$。&lt;/p&gt;
&lt;p&gt;输入矩阵：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{X} =
\begin{bmatrix}
1 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 \\
0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 1 \\
1 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0
\end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;假设已经学过权重（实际训练中得到）：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{W}^Q =
\begin{bmatrix}
1 &amp;amp; 0 \\
0 &amp;amp; 1 \\
0 &amp;amp; 0 \\
0 &amp;amp; 0
\end{bmatrix},
\quad
\mathbf{W}^K =
\begin{bmatrix}
0 &amp;amp; 1 \\
1 &amp;amp; 0 \\
0 &amp;amp; 0 \\
0 &amp;amp; 0
\end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;计算 Q 和 K：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{Q} = \mathbf{X}\mathbf{W}^Q =
\begin{bmatrix}
1 &amp;amp; 0 \\
0 &amp;amp; 1 \\
1 &amp;amp; 1
\end{bmatrix},
\quad
\mathbf{K} = \mathbf{X}\mathbf{W}^K =
\begin{bmatrix}
0 &amp;amp; 1 \\
1 &amp;amp; 0 \\
1 &amp;amp; 1
\end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;计算 $\mathbf{Q}\mathbf{K}^\top$：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\mathbf{Q}\mathbf{K}^\top &amp;amp;=
\begin{bmatrix}
1 &amp;amp; 0 \\
0 &amp;amp; 1 \\
1 &amp;amp; 1
\end{bmatrix}
\begin{bmatrix}
0 &amp;amp; 1 &amp;amp; 1 \\
1 &amp;amp; 0 &amp;amp; 1
\end{bmatrix}
\\
&amp;amp;=
\begin{bmatrix}
0 &amp;amp; 1 &amp;amp; 1 \\
1 &amp;amp; 0 &amp;amp; 1 \\
1 &amp;amp; 1 &amp;amp; 2
\end{bmatrix}
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;除以 $\sqrt{d_k} = \sqrt{2} \approx 1.414$：&lt;/p&gt;
&lt;p&gt;$$
\frac{\mathbf{Q}\mathbf{K}^\top}{\sqrt{2}} \approx
\begin{bmatrix}
0 &amp;amp; 0.707 &amp;amp; 0.707 \\
0.707 &amp;amp; 0 &amp;amp; 0.707 \\
0.707 &amp;amp; 0.707 &amp;amp; 1.414
\end{bmatrix}
$$&lt;/p&gt;
&lt;p&gt;对每一行做 softmax（以第一行为例）：&lt;/p&gt;
&lt;p&gt;$$
\text{softmax}([0,\ 0.707,\ 0.707]) =
\left[ \frac{e^0}{Z},\ \frac{e^{0.707}}{Z},\ \frac{e^{0.707}}{Z} \right]
$$&lt;/p&gt;
&lt;p&gt;其中 $Z = e^0 + e^{0.707} + e^{0.707} \approx 1 + 2.028 + 2.028 = 5.056$。&lt;/p&gt;
&lt;p&gt;所以第一行：&lt;/p&gt;
&lt;p&gt;$$
[0.198,\ 0.401,\ 0.401]
$$&lt;/p&gt;
&lt;p&gt;含义：第一个 token 更关注第二个和第三个 token。&lt;/p&gt;
&lt;h3 id=&#34;35-为什么需要-masked-attention&#34;&gt;3.5 为什么需要 Masked Attention？&lt;/h3&gt;
&lt;p&gt;训练语言模型时，模型只能看到当前位置&lt;strong&gt;及之前&lt;/strong&gt;的 token，不能偷看答案。所以要用一个上三角为 $-\infty$ 的 Mask：&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&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这样 softmax 之后，当前位置看不到后面的词。&lt;/p&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;$d_k$ 算错&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Attention 分数尺度异常，训练不稳定&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;检查 head 维度 = 总维度 / head 数&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;忘记 Mask&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;模型作弊，直接看到未来 token，loss 特别低但推理崩溃&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;训练时加 causal mask&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Softmax 数值溢出&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$e^{1000}$ 变成 Inf&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;实现时先做 &lt;code&gt;x - max(x)&lt;/code&gt; 再 exp&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;Q/K 初始化或学习率问题&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;检查初始化、LayerNorm 位置&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;Attention 权重集中在某一个位置&lt;/strong&gt;：可能是某个 token 的 Key 向量特别大，检查是否没做 scale，或 LayerNorm 失效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss 很低但生成质量差&lt;/strong&gt;：可能是 mask 写错，训练时模型偷看了未来词，推理时却没有未来词可用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-Head Attention 输出震荡&lt;/strong&gt;：不同 head 学到的模式冲突，适当增加 warmup 轮数。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四前向传播从输入到预测概率&#34;&gt;四、前向传播：从输入到预测概率&lt;/h2&gt;
&lt;h3 id=&#34;41-一句话理解&#34;&gt;4.1 一句话理解&lt;/h3&gt;
&lt;p&gt;前向传播就是数据从输入层一直流到输出层，最后得到“下一个词是词表里每个词的概率”。&lt;/p&gt;
&lt;h3 id=&#34;42-计算图&#34;&gt;4.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;输入 Token IDs&amp;#34;] --&amp;gt; E[&amp;#34;Embedding&amp;#34;]
    E --&amp;gt; PE[&amp;#34;+ 位置编码 Positional Encoding&amp;#34;]
    PE --&amp;gt; TB[&amp;#34;Transformer Blocks × N&amp;#34;]
    TB --&amp;gt; LN[&amp;#34;Final LayerNorm&amp;#34;]
    LN --&amp;gt; LM[&amp;#34;线性层 Linear&amp;#34;]
    LM --&amp;gt; Soft[&amp;#34;Softmax&amp;#34;]
    Soft --&amp;gt; P[&amp;#34;概率分布 P(next token | previous)&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;43-输出层公式&#34;&gt;4.3 输出层公式&lt;/h3&gt;
&lt;p&gt;Transformer 最后一层的输出 $\mathbf{H} \in \mathbb{R}^{T \times d}$，乘以输出权重矩阵 $\mathbf{W}_{\text{out}} \in \mathbb{R}^{d \times V}$，得到 logits：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{Z} = \mathbf{H} \mathbf{W}_{\text{out}} + \mathbf{b}_{\text{out}} \in \mathbb{R}^{T \times V}
$$&lt;/p&gt;
&lt;p&gt;对 logits 做 softmax，得到概率：&lt;/p&gt;
&lt;p&gt;$$
P(w_t = j \mid w_{&amp;lt;t}) = \frac{e^{z_{t,j}}}{\sum_{k=1}^{V} e^{z_{t,k}}}
$$&lt;/p&gt;
&lt;h3 id=&#34;44-计算例子&#34;&gt;4.4 计算例子&lt;/h3&gt;
&lt;p&gt;假设词表大小 $V=5$，某一步的 logits：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{z} = [2.0,\ 1.0,\ 0.5,\ 0.1,\ -1.0]
$$&lt;/p&gt;
&lt;p&gt;先求 $e^{z_i}$：&lt;/p&gt;
&lt;p&gt;$$
e^{2.0} \approx 7.389,\ e^{1.0} \approx 2.718,\ e^{0.5} \approx 1.649,\ e^{0.1} \approx 1.105,\ e^{-1.0} \approx 0.368
$$&lt;/p&gt;
&lt;p&gt;求和：&lt;/p&gt;
&lt;p&gt;$$
Z = 7.389 + 2.718 + 1.649 + 1.105 + 0.368 = 13.229
$$&lt;/p&gt;
&lt;p&gt;概率分布：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{p} = [0.558,\ 0.205,\ 0.125,\ 0.084,\ 0.028]
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;模型认为第一个词概率最大，为 55.8%。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;45-使用注意点--避坑&#34;&gt;4.5 使用注意点 / 避坑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;logits 尺度影响 softmax&lt;/strong&gt;：如果 logits 都很大，softmax 会接近 one-hot，梯度变小；温度参数 $T$ 可以调整：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$
P_i = \frac{e^{z_i / T}}{\sum_j e^{z_j / T}}
$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;输出层权重共享（Weight Tying）&lt;/strong&gt;：很多 LLM 把 Embedding 矩阵和输出层矩阵共享，减少参数并提升效果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推理时不要复用训练时的 dropout&lt;/strong&gt;：切换到 eval 模式，否则结果不稳定。&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;Softmax 输出全 0 或 NaN&lt;/strong&gt;：检查 logits 是否 overflow，实现时减去最大值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成结果重复同一个 token&lt;/strong&gt;：可能是温度太低、top-k/top-p 设置不当，或训练数据里该模式重复过多。&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;五损失函数cross-entropy-loss&#34;&gt;五、损失函数：Cross Entropy Loss&lt;/h2&gt;
&lt;h3 id=&#34;51-一句话理解&#34;&gt;5.1 一句话理解&lt;/h3&gt;
&lt;p&gt;Cross Entropy 衡量“模型预测的分布”和“真实分布”之间的距离。&lt;strong&gt;预测越准，loss 越小&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;52-数学公式&#34;&gt;5.2 数学公式&lt;/h3&gt;
&lt;p&gt;对于下一个 token 的真实标签是第 $c$ 个词（one-hot 向量 $\mathbf{y}$），模型预测概率为 $\mathbf{p}$：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L} = -\sum_{j=1}^{V} y_j \log(p_j) = -\log(p_c)
$$&lt;/p&gt;
&lt;p&gt;因为只有真实位置 $c$ 的 $y_c=1$，其他为 0，所以 loss 简化为 &lt;strong&gt;负对数似然&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;53-计算例子&#34;&gt;5.3 计算例子&lt;/h3&gt;
&lt;p&gt;真实下一个词是第 1 个（从 0 开始数也是第 1 个），模型预测概率：&lt;/p&gt;
&lt;p&gt;$$
\mathbf{p} = [0.558,\ 0.205,\ 0.125,\ 0.084,\ 0.028]
$$&lt;/p&gt;
&lt;p&gt;真实标签 $c=1$，所以 $p_c = 0.205$：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L} = -\log(0.205) \approx 1.585
$$&lt;/p&gt;
&lt;p&gt;如果模型完全猜对，$p_c = 0.999$：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L} = -\log(0.999) \approx 0.001
$$&lt;/p&gt;
&lt;p&gt;如果完全猜错，$p_c = 0.001$：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L} = -\log(0.001) \approx 6.908
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;loss 越小，模型对真实下一个词的预测概率越高。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;54-一个-batch-的平均-loss&#34;&gt;5.4 一个 batch 的平均 loss&lt;/h3&gt;
&lt;p&gt;训练时一个 batch 有 $B$ 个样本，每个样本有 $T$ 个 token 位置参与预测，平均 loss：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L}_{\text{batch}} = -\frac{1}{B \cdot T} \sum_{b=1}^{B} \sum_{t=1}^{T} \log p\left(w_t^{(b)} \mid w_{&amp;lt;t}^{(b)}\right)
$$&lt;/p&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;标签 smoothing 过度&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;模型变得不自信，输出模糊&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;label smoothing 一般 0.1 左右&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;忽略 padding&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;padding 位置也参与 loss 计算，污染梯度&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用 mask 屏蔽 padding&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;对数定义域问题或实现 bug&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;检查 softmax 前是否减了最大值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;z-loss 没加&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;MoE 模型路由不稳定&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;加 auxiliary loss 约束专家负载&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;Loss 一开始很大然后骤降&lt;/strong&gt;：正常现象，说明模型快速学习简单模式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss 一直不下降&lt;/strong&gt;：检查学习率、数据质量、标签是否正确。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss 变成 NaN&lt;/strong&gt;：通常是学习率过大、梯度爆炸或出现了 $\log(0)$，加 epsilon 或做梯度裁剪。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六反向传播从损失回到每个权重&#34;&gt;六、反向传播：从损失回到每个权重&lt;/h2&gt;
&lt;h3 id=&#34;61-一句话理解&#34;&gt;6.1 一句话理解&lt;/h3&gt;
&lt;p&gt;反向传播就是&lt;strong&gt;用链式法则，从输出层的 loss 倒推，算出每个权重对 loss 的贡献&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;62-链式法则回顾&#34;&gt;6.2 链式法则回顾&lt;/h3&gt;
&lt;p&gt;复合函数求导：&lt;/p&gt;
&lt;p&gt;$$
\frac{\partial \mathcal{L}}{\partial w} = \frac{\partial \mathcal{L}}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w}
$$&lt;/p&gt;
&lt;p&gt;神经网络就是很多层复合函数套在一起，反向传播只是系统化地算一遍。&lt;/p&gt;
&lt;h3 id=&#34;63-计算例子一个简单的输出层权重&#34;&gt;6.3 计算例子：一个简单的输出层权重&lt;/h3&gt;
&lt;p&gt;假设模型最后一层只有一个神经元，简化为：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
z &amp;amp;= w \cdot h + b \\
p &amp;amp;= \sigma(z) \\
\mathcal{L} &amp;amp;= -y \log(p) - (1-y)\log(1-p)
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;其中 $h$ 是 Transformer 最后一层的某个隐藏状态，$y$ 是真实标签（0 或 1）。&lt;/p&gt;
&lt;p&gt;已知：$h=2.0$，$w=0.5$，$b=-1.0$，$y=1$。&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 2.0 + (-1.0) = 0 \\
p &amp;amp;= \sigma(0) = 0.5 \\
\mathcal{L} &amp;amp;= -\log(0.5) \approx 0.693
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;反向&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\frac{\partial \mathcal{L}}{\partial z} = p - y = 0.5 - 1 = -0.5
$$&lt;/p&gt;
&lt;p&gt;然后：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\frac{\partial \mathcal{L}}{\partial w} &amp;amp;= \frac{\partial \mathcal{L}}{\partial z} \cdot \frac{\partial z}{\partial w} = -0.5 \times 2.0 = -1.0 \\
\frac{\partial \mathcal{L}}{\partial b} &amp;amp;= \frac{\partial \mathcal{L}}{\partial z} \cdot \frac{\partial z}{\partial b} = -0.5 \times 1 = -0.5
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;更新&lt;/strong&gt;（学习率 $\eta = 0.1$）：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
w_{\text{new}} &amp;amp;= 0.5 - 0.1 \times (-1.0) = 0.6 \\
b_{\text{new}} &amp;amp;= -1.0 - 0.1 \times (-0.5) = -0.95
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;再算一次前向，$z = 0.6 \times 2.0 - 0.95 = 0.25$，$p = \sigma(0.25) \approx 0.562$，loss 变小。&lt;/p&gt;
&lt;h3 id=&#34;64-transformer-里的反向传播&#34;&gt;6.4 Transformer 里的反向传播&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
    L[&amp;#34;Loss&amp;#34;] --&amp;gt; O[&amp;#34;输出层梯度&amp;#34;]
    O --&amp;gt; TB[&amp;#34;Transformer Block N&amp;#34;]
    TB --&amp;gt; TB2[&amp;#34;Transformer Block N-1&amp;#34;]
    TB2 --&amp;gt; DOTS[&amp;#34;...&amp;#34;]
    DOTS --&amp;gt; E[&amp;#34;Embedding 层&amp;#34;]
    E --&amp;gt; G[&amp;#34;所有权重梯度&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;65-使用注意点--避坑&#34;&gt;6.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;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;深层网络前面层梯度接近 0，学不动&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;残差连接、LayerNorm、更好的初始化&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;loss 突然变成 NaN，权重更新巨大&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;ReLU 神经元永久输出 0&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用 GeLU/SiLU，或用 SwiGLU&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;checkpoint 丢失梯度&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;梯度检查点实现错误&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;验证 checkpoint 前后梯度一致&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;66-异常场景处理&#34;&gt;6.6 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;某些层梯度全 0&lt;/strong&gt;：检查激活函数是否全部死亡，或该层是否被 freeze。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不同层梯度差 1000 倍&lt;/strong&gt;：深层网络不稳定，加梯度裁剪或 LayerNorm。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss 反升&lt;/strong&gt;：学习率过大或数据里有异常样本，先降学习率再查数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七优化器adamw--学习率调度&#34;&gt;七、优化器：AdamW + 学习率调度&lt;/h2&gt;
&lt;h3 id=&#34;71-一句话理解&#34;&gt;7.1 一句话理解&lt;/h3&gt;
&lt;p&gt;AdamW 是 Adam 的改进版，它在更新权重的同时做&lt;strong&gt;真正的权重衰减（Weight Decay）&lt;/strong&gt;，让模型参数不要太大，防止过拟合。&lt;/p&gt;
&lt;h3 id=&#34;72-adam-更新公式&#34;&gt;7.2 Adam 更新公式&lt;/h3&gt;
&lt;p&gt;对于参数 $\theta$ 和梯度 $g_t$：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
m_t &amp;amp;= \beta_1 m_{t-1} + (1 - \beta_1) g_t \\
v_t &amp;amp;= \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 \\
\hat{m}_t &amp;amp;= \frac{m_t}{1 - \beta_1^t} \\
\hat{v}_t &amp;amp;= \frac{v_t}{1 - \beta_2^t} \\
\theta_t &amp;amp;= \theta_{t-1} - \eta \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}
\end{aligned}
$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$m_t$：一阶动量（梯度的指数移动平均）。&lt;/li&gt;
&lt;li&gt;$v_t$：二阶动量（梯度平方的指数移动平均）。&lt;/li&gt;
&lt;li&gt;$\beta_1=0.9$，$\beta_2=0.999$，$\epsilon=10^{-8}$ 是常用默认值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;73-adamw-的权重衰减&#34;&gt;7.3 AdamW 的权重衰减&lt;/h3&gt;
&lt;p&gt;AdamW 把权重衰减放在梯度更新&lt;strong&gt;之外&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;$$
\theta_t = \theta_{t-1} - \eta \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} - \eta \lambda \theta_{t-1}
$$&lt;/p&gt;
&lt;p&gt;其中 $\lambda$ 是 weight decay 系数，常见值 $0.01$。&lt;/p&gt;
&lt;h3 id=&#34;74-计算例子&#34;&gt;7.4 计算例子&lt;/h3&gt;
&lt;p&gt;假设参数 $\theta_{t-1} = 1.0$，梯度 $g_t = -2.0$，学习率 $\eta = 0.1$，$\lambda = 0.01$。&lt;/p&gt;
&lt;p&gt;为了简化，假设 $m_t \approx g_t = -2.0$，$v_t \approx g_t^2 = 4.0$（已经稳定）。&lt;/p&gt;
&lt;p&gt;Adam 部分：&lt;/p&gt;
&lt;p&gt;$$
\Delta \theta_{\text{Adam}} = -\eta \cdot \frac{g_t}{\sqrt{g_t^2} + \epsilon}
= -0.1 \cdot \frac{-2.0}{2.0 + 10^{-8}} \approx 0.1
$$&lt;/p&gt;
&lt;p&gt;Weight Decay 部分：&lt;/p&gt;
&lt;p&gt;$$
\Delta \theta_{\text{WD}} = -\eta \lambda \theta_{t-1} = -0.1 \times 0.01 \times 1.0 = -0.001
$$&lt;/p&gt;
&lt;p&gt;最终更新：&lt;/p&gt;
&lt;p&gt;$$
\theta_t = 1.0 + 0.1 - 0.001 = 1.099
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;没有 weight decay 时 $\theta_t = 1.1$，AdamW 让它稍微小一点。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;75-学习率调度&#34;&gt;7.5 学习率调度&lt;/h3&gt;
&lt;p&gt;LLM 训练通常用 &lt;strong&gt;warmup + cosine decay&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
    A[&amp;#34;lr = 0&amp;#34;] --&amp;gt; B[&amp;#34;Warmup 线性上升&amp;#34;]
    B --&amp;gt; C[&amp;#34;Cosine Decay 下降&amp;#34;]
    C --&amp;gt; D[&amp;#34;最小学习率保持&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;公式：&lt;/p&gt;
&lt;p&gt;$$
\eta_t =
\begin{cases}
\eta_{\max} \cdot \frac{t}{t_{\text{warmup}}}, &amp;amp; t &amp;lt; t_{\text{warmup}} \\
\eta_{\min} + \frac{1}{2}(\eta_{\max} - \eta_{\min}) \left(1 + \cos\left(\frac{t - t_{\text{warmup}}}{t_{\max} - t_{\text{warmup}}} \pi\right)\right), &amp;amp; t \ge t_{\text{warmup}}
\end{cases}
$$&lt;/p&gt;
&lt;h3 id=&#34;76-使用注意点--避坑&#34;&gt;7.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;Weight decay 太大&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;参数被压得太小，欠拟合&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;常见 0.01，小模型可 0.1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Warmup 太短&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;warmup 步数设总步数的 1%-3%&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;还没收敛就降到 0&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;调整 cosine 周期或最小学习率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;AdamW β 参数写错&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;训练异常&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;β1=0.9，β2=0.999，不要混淆&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;77-异常场景处理&#34;&gt;7.7 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Loss 在 warmup 阶段就 NaN&lt;/strong&gt;：说明峰值学习率太高，或 warmup 太短，降低 $\eta_{\max}$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loss 降到一定程度后停滞&lt;/strong&gt;：可能是学习率太小，检查 cosine 是否已经进入尾部。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;验证 loss 比训练 loss 高很多&lt;/strong&gt;：过拟合，增大 weight decay 或加 dropout。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八从预训练到-rlhf三阶段训练&#34;&gt;八、从预训练到 RLHF：三阶段训练&lt;/h2&gt;
&lt;h3 id=&#34;81-预训练让模型博览群书&#34;&gt;8.1 预训练：让模型“博览群书”&lt;/h3&gt;
&lt;p&gt;目标函数：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L}_{\text{PT}} = -\mathbb{E}_{x \sim D_{\text{pretrain}}} \left[ \sum_t \log P(x_t \mid x_{&amp;lt;t}; \theta) \right]
$$&lt;/p&gt;
&lt;p&gt;数据量通常是万亿级 token，算力消耗最大。&lt;/p&gt;
&lt;h3 id=&#34;82-sft监督微调&#34;&gt;8.2 SFT：监督微调&lt;/h3&gt;
&lt;p&gt;用人工标注的 （prompt, answer） 对训练：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L}_{\text{SFT}} = -\mathbb{E}_{(x,y) \sim D_{\text{sft}}} \left[ \sum_t \log P(y_t \mid x, y_{&amp;lt;t}; \theta) \right]
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：通常只计算 answer 部分的 loss，prompt 部分用 mask 屏蔽。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;83-rlhf人类反馈强化学习&#34;&gt;8.3 RLHF：人类反馈强化学习&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
    P[&amp;#34;Prompt&amp;#34;] --&amp;gt; RM[&amp;#34;奖励模型 Reward Model&amp;#34;]
    RM --&amp;gt; R[&amp;#34;奖励分数 r&amp;#34;]
    R --&amp;gt; PPO[&amp;#34;PPO 优化策略模型&amp;#34;]
    PPO --&amp;gt; M[&amp;#34;更新后的模型&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;奖励模型给回答打分，PPO 用策略梯度优化：&lt;/p&gt;
&lt;p&gt;$$
\nabla_\theta J = \mathbb{E}_{x,y} \left[ r(x,y) \cdot \nabla_\theta \log P(y \mid x; \theta) \right] - \beta \cdot \text{KL}(P_\theta | P_{\text{ref}})
$$&lt;/p&gt;
&lt;p&gt;第二项是 KL 散度约束，防止模型跑得太偏。&lt;/p&gt;
&lt;h3 id=&#34;84-dpo更简单的对齐方法&#34;&gt;8.4 DPO：更简单的对齐方法&lt;/h3&gt;
&lt;p&gt;DPO（Direct Preference Optimization）不用训练奖励模型，直接用偏好数据优化：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L}_{\text{DPO}} = -\mathbb{E}_{(x, y_w, y_l)} \left[ \log \sigma\left( \beta \log \frac{P(y_w \mid x)}{P_{\text{ref}}(y_w \mid x)} - \beta \log \frac{P(y_l \mid x)}{P_{\text{ref}}(y_l \mid x)} \right) \right]
$$&lt;/p&gt;
&lt;p&gt;其中 $y_w$ 是人类更喜欢的回答，$y_l$ 是较差的回答。&lt;/p&gt;
&lt;h3 id=&#34;85-使用注意点--避坑&#34;&gt;8.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;SFT 数据太少&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;模型学会模板但泛化差&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;SFT 数据通常 10k-1M 条&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;SFT 只训 answer&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;prompt 也参与 loss 会干扰&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;用 label mask 只保留 answer&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;RLHF 奖励黑客&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;模型钻奖励模型漏洞，生成无意义高分回答&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;加 KL 约束、人工抽检&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;DPO 偏好数据噪声&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;86-异常场景处理&#34;&gt;8.6 异常场景处理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SFT 后模型不会遵循指令&lt;/strong&gt;：检查 prompt 格式是否和预训练一致，增加多轮对话样本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RLHF 后模型过度讨好&lt;/strong&gt;：奖励模型可能偏向“长回答”或“道歉”，调整奖励函数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对齐后模型能力下降&lt;/strong&gt;：KL 系数太大，模型被锁死；太小，模型跑偏。需要调 $\beta$。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九pytorch-实战一个可运行的-minigpt-demo&#34;&gt;九、PyTorch 实战：一个可运行的 MiniGPT Demo&lt;/h2&gt;
&lt;h3 id=&#34;91-一句话理解&#34;&gt;9.1 一句话理解&lt;/h3&gt;
&lt;p&gt;前面几节的公式，在 PyTorch 里其实只有几行代码：前向传播是 &lt;code&gt;model(x)&lt;/code&gt;，交叉熵是 &lt;code&gt;F.cross_entropy&lt;/code&gt;，反向传播是 &lt;code&gt;loss.backward()&lt;/code&gt;，AdamW 更新是 &lt;code&gt;optimizer.step()&lt;/code&gt;。下面这个约 70 行的脚本可以在 CPU 上直接跑通完整训练流程。&lt;/p&gt;
&lt;h3 id=&#34;92-完整代码cpu-可运行&#34;&gt;9.2 完整代码（CPU 可运行）&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;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;MiniGPT：用 PyTorch 跑通 LLM 训练全流程&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; math
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; torch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; torch.nn &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; nn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; torch.nn.functional &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; F
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;manual_seed(&lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ===== 0. 复现 3.4 节的 Attention 手算例子 =====&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;X &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tensor([[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]], dtype&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;float32)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WQ &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tensor([[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]], dtype&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;float32)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WK &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tensor([[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], [&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]], dtype&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;float32)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Q, K &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; X &lt;span style=&#34;color:#f92672&#34;&gt;@&lt;/span&gt; WQ, X &lt;span style=&#34;color:#f92672&#34;&gt;@&lt;/span&gt; WK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;attn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;softmax(Q &lt;span style=&#34;color:#f92672&#34;&gt;@&lt;/span&gt; K&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;T &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; math&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sqrt(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;), dim&lt;span style=&#34;color:#f92672&#34;&gt;=-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Attention 第一行:&amp;#34;&lt;/span&gt;, attn[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tolist())  &lt;span style=&#34;color:#75715e&#34;&gt;# ≈ [0.198, 0.401, 0.401]，与手算一致&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ===== 1. 数据预处理与 Tokenization（对应第二节）=====&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 玩具语料：字符级分词，真实 LLM 用的是 BPE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;corpus &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;北京是中国的首都。北京有天安门。中国的首都是北京。&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chars &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sorted(set(corpus))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;stoi &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {ch: i &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i, ch &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; enumerate(chars)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;itos &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {i: ch &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; ch, i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; stoi&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;items()}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;V &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; len(chars)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tensor([stoi[ch] &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; ch &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; corpus], dtype&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;long)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ===== 2. 模型：Embedding + Transformer Block + 输出层（第三、四节）=====&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MiniGPT&lt;/span&gt;(nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Module):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__init__&lt;/span&gt;(self, vocab_size, d_model&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;, n_head&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, n_layer&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, max_len&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        super()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;__init__&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;max_len &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; max_len
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tok_emb &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Embedding(vocab_size, d_model)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pos_emb &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Embedding(max_len, d_model)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        layer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;TransformerEncoderLayer(d_model, n_head, dim_feedforward&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; d_model,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                           batch_first&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;, norm_first&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;blocks &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;TransformerEncoder(layer, num_layers&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;n_layer)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ln_f &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;LayerNorm(d_model)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;head &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Linear(d_model, vocab_size, bias&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;False&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;head&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;weight &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tok_emb&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;weight  &lt;span style=&#34;color:#75715e&#34;&gt;# Weight Tying（4.5 节）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;forward&lt;/span&gt;(self, idx):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        T &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; idx&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tok_emb(idx) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pos_emb(torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;arange(T, device&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;idx&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;device))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# causal mask：上三角为 -inf，防止偷看未来 token（3.5 节）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        mask &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;triu(torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;full((T, T), float(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-inf&amp;#34;&lt;/span&gt;), device&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;idx&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;device), diagonal&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        h &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ln_f(self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;blocks(x, mask&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;mask))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;head(h)  &lt;span style=&#34;color:#75715e&#34;&gt;# logits: (B, T, V)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;model &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; MiniGPT(V)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ===== 3. 取 batch：输入和标签错开一位（预测下一个 token）=====&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;B, T &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_batch&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ix &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;randint(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, len(data) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; T &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, (B,))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;stack([data[i:i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; T] &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; ix])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;stack([data[i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; T &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; ix])  &lt;span style=&#34;color:#75715e&#34;&gt;# 标签 = 输入右移一位&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; x, y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ===== 4. 优化器与学习率调度：AdamW + warmup + cosine（第七节）=====&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;max_steps, warmup_steps, lr_max, lr_min &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3e-3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3e-4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;optimizer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;optim&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;AdamW(model&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;parameters(), lr&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;lr_max, weight_decay&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.01&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lr_lambda&lt;/span&gt;(step):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; step &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; warmup_steps:                      &lt;span style=&#34;color:#75715e&#34;&gt;# warmup 线性上升&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; step &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; warmup_steps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    p &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (step &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; warmup_steps) &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; (max_steps &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; warmup_steps)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; lr_min &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; lr_max &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.5&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; lr_min &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; lr_max) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; math&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;cos(math&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;pi &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; p))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scheduler &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;optim&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;lr_scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;LambdaLR(optimizer, lr_lambda)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ===== 5. 训练循环：前向 → CE loss → 反向传播 → 更新（第四、五、六节）=====&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; step &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(max_steps):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    x, y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; get_batch()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    logits &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; model(x)                                        &lt;span style=&#34;color:#75715e&#34;&gt;# 前向传播&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    loss &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; F&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;cross_entropy(logits&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;view(&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, V), y&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;view(&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;))   &lt;span style=&#34;color:#75715e&#34;&gt;# 交叉熵（5.2 节）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    optimizer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;zero_grad()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    loss&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;backward()                                          &lt;span style=&#34;color:#75715e&#34;&gt;# 反向传播（链式法则）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    grad_norm &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;nn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;utils&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;clip_grad_norm_(model&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;parameters(), &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt;)  &lt;span style=&#34;color:#75715e&#34;&gt;# 梯度裁剪（6.5 节）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    optimizer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;step()                                         &lt;span style=&#34;color:#75715e&#34;&gt;# AdamW 更新权重&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;step()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; step &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;or&lt;/span&gt; step &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; max_steps &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        lr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_last_lr()[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ppl &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; math&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;exp(loss&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;item())                          &lt;span style=&#34;color:#75715e&#34;&gt;# perplexity（第十节第 5 条）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;step &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;step&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;4d&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; | loss &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;loss&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;item()&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.4f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; | ppl &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;ppl&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;7.2f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; | lr &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;lr&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.5f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; | grad &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;grad_norm&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;.2f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ===== 6. 生成：贪心解码 =====&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;model&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;eval()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;idx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tensor([[stoi[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;北&amp;#34;&lt;/span&gt;]]], dtype&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;long)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; _ &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    logits &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; model(idx[:, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;model&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;max_len:])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nxt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; logits[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;argmax()                             &lt;span style=&#34;color:#75715e&#34;&gt;# 贪心：取概率最大的 token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    idx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;cat([idx, nxt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;view(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)], dim&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;生成:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;join(itos[i] &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; idx[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;tolist()))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install torch   &lt;span style=&#34;color:#75715e&#34;&gt;# CPU 版即可&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python demo.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;93-实际运行输出&#34;&gt;9.3 实际运行输出&lt;/h3&gt;
&lt;p&gt;在 CPU（torch 2.5.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;Attention 第一行: [0.1978, 0.4011, 0.4011]
词表大小 V=13, 总 token 数=500
参数量: 102976
step    0 | loss 41.3162 | ppl 8.8e+17 | lr 0.00030 | grad 14.51
step   30 | loss 0.6630  | ppl    1.94 | lr 0.00297 | grad 1.07
step   60 | loss 0.2738  | ppl    1.32 | lr 0.00280 | grad 1.08
step   90 | loss 0.0683  | ppl    1.07 | lr 0.00251 | grad 0.28
step  120 | loss 0.0576  | ppl    1.06 | lr 0.00214 | grad 0.24
step  150 | loss 0.0315  | ppl    1.03 | lr 0.00171 | grad 0.20
step  180 | loss 0.0456  | ppl    1.05 | lr 0.00127 | grad 0.21
step  210 | loss 0.0325  | ppl    1.03 | lr 0.00088 | grad 0.18
step  240 | loss 0.0330  | ppl    1.03 | lr 0.00057 | grad 0.20
step  270 | loss 0.0369  | ppl    1.04 | lr 0.00037 | grad 0.11
step  299 | loss 0.0458  | ppl    1.05 | lr 0.00030 | grad 0.20
生成: 北京有天安门。中国的首都是北京。&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;几个值得注意的点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attention 第一行 &lt;code&gt;[0.198, 0.401, 0.401]&lt;/code&gt; 和 3.4 节手算结果完全一致。&lt;/li&gt;
&lt;li&gt;step 0 的 loss 高达 41，远高于随机猜测的理论值 $\ln 13 \approx 2.56$——这是 Weight Tying 下随机初始化的 Embedding 同时当输出层，产生了极端 logits。30 步内就降到 2.56 以下，说明 AdamW + warmup 很快把它拉回正常区间。&lt;/li&gt;
&lt;li&gt;最终 loss 降到 0.03 左右（PPL ≈ 1.03），模型基本“背”下了玩具语料，所以贪心生成能接出通顺的句子。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;94-代码与前文章节的对应关系&#34;&gt;9.4 代码与前文章节的对应关系&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;code&gt;stoi&lt;/code&gt; / &lt;code&gt;itos&lt;/code&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;真实场景换成 BPE（如 &lt;code&gt;tiktoken&lt;/code&gt;）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;nn.Embedding&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;2.4 节&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;就是查表 $\mathbf{E}[id]$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;Q @ K.T / math.sqrt(2)&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3.3 节&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Scaled Dot-Product Attention&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;torch.triu(..., &amp;quot;-inf&amp;quot;, diagonal=1)&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;3.5 节&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Causal mask，忘了它模型就作弊&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;self.head.weight = self.tok_emb.weight&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;4.5 节&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Weight Tying&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;F.cross_entropy(logits, y)&lt;/code&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;内部已做 softmax + 负对数似然，数值稳定&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;loss.backward()&lt;/code&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;code&gt;clip_grad_norm_(..., 1.0)&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;6.5 节&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;梯度裁剪防 NaN&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;torch.optim.AdamW&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;7.2、7.3 节&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$\beta_1=0.9, \beta_2=0.999$ 是默认值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;LambdaLR&lt;/code&gt; + &lt;code&gt;lr_lambda&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;7.5 节&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;warmup + cosine decay&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;math.exp(loss.item())&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;第十节第 5 条&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;PPL $= e^{\mathcal{L}}$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;95-使用注意点--避坑&#34;&gt;9.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;code&gt;optimizer.zero_grad()&lt;/code&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;梯度跨 step 累积，loss 曲线异常&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;每个 step 先清零梯度&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;dropout 在推理时还生效，结果不稳定&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;训练 &lt;code&gt;model.train()&lt;/code&gt;，生成 &lt;code&gt;model.eval()&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;cross_entropy&lt;/code&gt; 前手动 softmax&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;直接传 logits，PyTorch 内部已做稳定化&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;模型在学“复制当前 token”，loss 极低但没学会预测&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;&lt;code&gt;y = x&lt;/code&gt; 右移一位&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;mask 写成下三角 -inf&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;每个 token 只能看自己，模型学不到上下文&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 降不到 0 就慌&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;96-动手练习建议&#34;&gt;9.6 动手练习建议&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;把 &lt;code&gt;lr_max&lt;/code&gt; 从 &lt;code&gt;3e-3&lt;/code&gt; 改成 &lt;code&gt;3e-2&lt;/code&gt;，观察 loss 是否 NaN（体会 warmup 和梯度裁剪的作用）。&lt;/li&gt;
&lt;li&gt;注释掉 causal mask，看 loss 是不是“假低”——训练 loss 很低，但生成崩了。&lt;/li&gt;
&lt;li&gt;把 &lt;code&gt;n_layer&lt;/code&gt; 从 2 加到 6，观察梯度范数变化和训练速度。&lt;/li&gt;
&lt;li&gt;把玩具语料换成一段真实文本（如《论语》），词表改为字级，看 PPL 能降到多少。&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;torch.autograd.grad&lt;/code&gt; 手动验证 6.3 节手算的梯度 $\partial \mathcal{L} / \partial w = -1.0$。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十通用训练避坑指南&#34;&gt;十、通用训练避坑指南&lt;/h2&gt;
&lt;p&gt;下面这 12 条适用于 LLM 全阶段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据质量 &amp;gt; 数据数量&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;：先用 1B 参数或少量数据跑通 pipeline。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控 loss 曲线&lt;/strong&gt;：训练 loss、验证 loss、perplexity 一起画。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;perplexity 是核心指标&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$$
\text{PPL} = e^{\mathcal{L}}
$$&lt;/p&gt;
&lt;p&gt;PPL 越低越好，一般预训练 PPL 在 2-10 之间。&lt;/p&gt;
&lt;ol start=&#34;6&#34;&gt;
&lt;li&gt;&lt;strong&gt;检查梯度范数&lt;/strong&gt;：突然变大说明要梯度裁剪。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学习率是最重要的超参数&lt;/strong&gt;：先按论文默认值，再按 10 倍上下调。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch size 影响稳定性&lt;/strong&gt;：大 batch 需要更大学习率，小 batch 噪声大但泛化好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不要用测试集调参&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;：代码、中文、英文、数学数据比例影响模型能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;保存多个 checkpoint&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;111-训练阶段异常&#34;&gt;11.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 / Inf&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;降学习率、梯度裁剪、检查 softmax 实现&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、抽查数据、检查 mask&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;早停、加 dropout、增数据、加正则&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;加模型容量、训练更久、减正则&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;显存 OOM&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;batch 太大、序列太长、模型太大&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;降 batch、用 gradient accumulation、激活检查点&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;通信问题、某些 GPU 慢&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;检查 NCCL、负载均衡、all-reduce 同步&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;某些 token 生成重复&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;训练数据偏差或解码参数问题&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;调 temperature、top-p、加重复惩罚&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;112-部署业务阶段异常&#34;&gt;11.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;用户输入超长、乱码、恶意 prompt&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;RAG 检索增强、增加事实性数据、后验校验&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;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;领域 SFT、RAG、专家模型路由&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;113-一个实用的排查-checklist&#34;&gt;11.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;□ 输入 token 范围对吗？（padding 是否被 mask？）
□ 标签 mask 对吗？（SFT 是否只算 answer loss？）
□ 损失函数和输出层匹配吗？（CE for classification）
□ 学习率调度正常吗？（warmup + decay）
□ 权重还有在更新吗？（打印梯度范数）
□ 单条数据能过拟合吗？（Sanity Check）
□ 分布式通信正常吗？（loss 同步一致）
□ 显存占用符合预期吗？（避免 OOM）&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;Tokenization&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;Embedding&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;ID → 向量&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;每个 token 对应一行稠密向量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;Transformer&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;提取上下文关系&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;QK 点积算 attention，再乘 V&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;输出层 + Softmax&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;Cross Entropy&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 越小&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;AdamW&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;更新权重&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;动量 + 二阶矩 + 真正 weight decay&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;LR 调度&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;控制学习节奏&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;先 warmup，再 cosine 下降&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;SFT / RLHF&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;p&gt;如果你是第一次接触 LLM 训练，建议按这个顺序动手：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先用一个小型 Transformer（如 nanoGPT）跑通“下一个 token 预测”。&lt;/li&gt;
&lt;li&gt;改改学习率、batch size、warmup，观察 loss 曲线变化。&lt;/li&gt;
&lt;li&gt;打印 attention 权重，看看模型在关注哪些 token。&lt;/li&gt;
&lt;li&gt;用少量 SFT 数据微调，体会 mask answer 的重要性。&lt;/li&gt;
&lt;li&gt;最后尝试 DPO，理解偏好对齐的数学本质。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;本文档持续维护中。如果有哪一步的公式或例子让你卡住，欢迎在评论区指出，我会继续用更直观的方式补充图解和代码。&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    <item>
      <title>生成式AI原理与实战（Part 4）学习笔记：推理模型、DeepSeek-R1 与高效训练架构</title>
      <link>https://ftmao.com/blog/posts/llm-interview-notes-part4/</link>
      <pubDate>Tue, 11 Nov 2025 17:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/llm-interview-notes-part4/</guid>
      <description>&lt;h1 id=&#34;生成式ai原理与实战part-4学习笔记推理模型deepseek-r1-与高效训练架构&#34;&gt;生成式AI原理与实战（Part 4）学习笔记：推理模型、DeepSeek-R1 与高效训练架构&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这是《生成式AI原理与实战》学习笔记的第四篇，也是这个系列的收尾篇。Part 4 的问题非常“硬核”，集中在&lt;strong&gt;推理模型（Reasoning Model）&lt;/strong&gt;、&lt;strong&gt;强化学习训练&lt;/strong&gt;、&lt;strong&gt;DeepSeek-R1 系列&lt;/strong&gt;以及&lt;strong&gt;DeepSeek 的高效训练架构&lt;/strong&gt;上。目标读者仍然是&lt;strong&gt;刚接触 AI 的初中级开发者&lt;/strong&gt;：我会尽量用工程直觉和生活化类比，把这些问题串成一条可理解的脉络。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面为什么推理模型这么重要&#34;&gt;写在前面：为什么推理模型这么重要？&lt;/h2&gt;
&lt;p&gt;过去两年，大模型领域最大的变化之一，就是从“问什么答什么”的聊天模型，演进到“会思考”的推理模型。DeepSeek-R1、OpenAI o1/o3、QwQ-32B 等模型展示了一个趋势：&lt;strong&gt;让模型在回答前多“想一会儿”，能显著提升复杂任务的准确率&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但这背后涉及很多问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模型为什么会“思考”？这和写 &lt;code&gt;let&#39;s think step by step&lt;/code&gt; 有什么区别？&lt;/li&gt;
&lt;li&gt;推理模型是怎么训练出来的？为什么它贵？&lt;/li&gt;
&lt;li&gt;DeepSeek-R1 为什么要先做 SFT 冷启动？&lt;/li&gt;
&lt;li&gt;训练大模型要花多少数据和算力？&lt;/li&gt;
&lt;li&gt;DeepSeek 的 MLA、MoE、FP8、DualPipe 到底在解决什么问题？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文章会按四个主题展开：&lt;strong&gt;推理模型基础&lt;/strong&gt;、&lt;strong&gt;训练与对齐方法选择&lt;/strong&gt;、&lt;strong&gt;DeepSeek-R1 解析&lt;/strong&gt;、&lt;strong&gt;DeepSeek 架构与训练系统&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一推理模型基础从直接回答到测试时计算&#34;&gt;一、推理模型基础：从“直接回答”到“测试时计算”&lt;/h2&gt;
&lt;h3 id=&#34;11-缩放定律训练一个模型需要多少数据和算力&#34;&gt;1.1 缩放定律：训练一个模型需要多少数据和算力？&lt;/h3&gt;
&lt;p&gt;缩放定律（Scaling Laws）告诉我们：模型的性能大致随&lt;strong&gt;参数量&lt;/strong&gt;、&lt;strong&gt;训练数据量&lt;/strong&gt;和&lt;strong&gt;计算量&lt;/strong&gt;一起提升。Chinchilla 论文给出的经验是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定固定算力预算，模型参数量 N 和训练 token 数 D 应该大致成比例增长，即 &lt;strong&gt;D ≈ 20N&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说，一个 70B 参数的模型，理想情况下需要用约 &lt;strong&gt;1.4 万亿 token&lt;/strong&gt; 来训练。&lt;/p&gt;
&lt;p&gt;算力估算：每个 token 的前向 + 反向传播大约需要 &lt;strong&gt;6 × 参数量&lt;/strong&gt; 次浮点运算（FLOPs）。所以训练 70B 模型用 1.4T 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;6 × 70B × 1.4T ≈ 5.9 × 10^23 FLOPs&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[参数量 N] --&amp;gt; C[计算量 C ~ 6ND]
    B[数据量 D] --&amp;gt; C
    C --&amp;gt; P[模型能力]
    style C fill:#fff2cc&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;工程直觉&lt;/strong&gt;：大模型训练就像烧开水——水壶越大（参数越多）、火越旺（数据越多）、烧得越久（训练越久），水温才越高。但三者的配比要合理，否则就是浪费。&lt;/p&gt;
&lt;h3 id=&#34;12-为什么普通大模型不能可靠解决-24-点&#34;&gt;1.2 为什么普通大模型不能可靠解决 24 点？&lt;/h3&gt;
&lt;p&gt;24 点问题需要：给定 4 个整数，通过加减乘除得到 24。这本质上是一个&lt;strong&gt;搜索 + 验证&lt;/strong&gt;问题。&lt;/p&gt;
&lt;p&gt;普通大模型（如 Llama-3 70B）在不输出思维链的情况下，只能做&lt;strong&gt;一次前向传播&lt;/strong&gt;，每个位置预测一个 token。Transformer 没有内置的“试错-回溯”机制，无法枚举所有数字组合并验证结果。因此它可能猜对，但不能&lt;strong&gt;可靠地&lt;/strong&gt;保证正确。&lt;/p&gt;
&lt;p&gt;而一旦允许输出思维链，模型就可以：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;写出候选算式；&lt;/li&gt;
&lt;li&gt;逐步计算；&lt;/li&gt;
&lt;li&gt;检查结果是否为 24；&lt;/li&gt;
&lt;li&gt;错了就换一条路。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这就是“测试时计算（Test-Time Compute）”的威力：&lt;strong&gt;用更多的生成 token 换取更高的准确率&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;13-cot-提示词-vs-推理模型同样是多想一会儿区别在哪&#34;&gt;1.3 CoT 提示词 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 CoT 提示工程
        P1[用户问题] --&amp;gt; T1[写 let&amp;#39;s think step by step]
        T1 --&amp;gt; G1[模型按已有习惯推理]
    end

    subgraph 推理模型
        P2[用户问题] --&amp;gt; T2[模型自动生成&amp;lt;br/&amp;gt;长思维链]
        T2 --&amp;gt; R2[自我验证/修正]
        R2 --&amp;gt; G2[更高质量答案]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比项&lt;/th&gt;
					&lt;th&gt;CoT 提示词&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;/td&gt;
					&lt;td&gt;提示工程技巧&lt;/td&gt;
					&lt;td&gt;训练出来的推理能力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;思维链质量&lt;/td&gt;
					&lt;td&gt;依赖模型原始能力&lt;/td&gt;
					&lt;td&gt;被 RL 训练专门优化&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;长度&lt;/td&gt;
					&lt;td&gt;通常较短&lt;/td&gt;
					&lt;td&gt;可生成很长的内部思考&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;上限&lt;/td&gt;
					&lt;td&gt;受限于模型本身&lt;/td&gt;
					&lt;td&gt;通过测试时计算持续提升&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;推理模型上限更高的原因是：它在训练时被&lt;strong&gt;显式激励&lt;/strong&gt;去生成更多推理步骤、进行自我验证、尝试不同路径。而普通模型只是被训练成“预测下一个词”，没有专门被优化去“想得更深”。&lt;/p&gt;
&lt;h3 id=&#34;14-推理模型的-rl-与非推理模型的-rlhf-有什么区别&#34;&gt;1.4 推理模型的 RL 与非推理模型的 RLHF 有什么区别？&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比项&lt;/th&gt;
					&lt;th&gt;推理模型 RL&lt;/th&gt;
					&lt;th&gt;普通模型 RLHF&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;奖励信号&lt;/td&gt;
					&lt;td&gt;通常是可自动验证的（答案对错）&lt;/td&gt;
					&lt;td&gt;人类偏好（好坏、有用、安全）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;优化目标&lt;/td&gt;
					&lt;td&gt;提升推理正确率&lt;/td&gt;
					&lt;td&gt;提升人类满意度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;典型任务&lt;/td&gt;
					&lt;td&gt;数学、编程、逻辑推理&lt;/td&gt;
					&lt;td&gt;对话、写作、问答&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;奖励模型&lt;/td&gt;
					&lt;td&gt;可以直接用规则/单元测试&lt;/td&gt;
					&lt;td&gt;需要训练 Reward Model&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;推理模型 RL 更像是“做数学题对答案”：对了加分，错了扣分。RLHF 更像是“写作文给老师看”：老师打分，模型学着更符合人类口味。&lt;/p&gt;
&lt;h3 id=&#34;15-alphazero-的启示训练时计算-vs-测试时计算的最优配比&#34;&gt;1.5 AlphaZero 的启示：训练时计算 vs 测试时计算的最优配比&lt;/h3&gt;
&lt;p&gt;AlphaZero 下围棋时，&lt;strong&gt;训练阶段&lt;/strong&gt;通过自我对弈生成大量棋谱、更新策略网络；&lt;strong&gt;测试阶段&lt;/strong&gt;用 MCTS 在每一步搜索最佳落子。&lt;/p&gt;
&lt;p&gt;它的启示是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;训练时计算&lt;/strong&gt;用于学习通用策略和价值判断；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试时计算&lt;/strong&gt;用于在具体局面下做精细搜索；&lt;/li&gt;
&lt;li&gt;最优配比取决于任务：对围棋这类可验证、搜索空间大的任务，测试时计算可以非常多；对开放性文本生成，测试时计算受延迟限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有研究认为，在可验证推理任务上，&lt;strong&gt;训练时计算 : 测试时计算&lt;/strong&gt; 的最优配比可能在 &lt;strong&gt;1000:1 到 10000:1&lt;/strong&gt; 量级。但这不是固定值，更多是一种设计哲学：&lt;strong&gt;先让模型学到好的“直觉”，再让它在推理时多花时间验证&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二训练推理模型奖励模型mcts-与-star&#34;&gt;二、训练推理模型：奖励模型、MCTS 与 STaR&lt;/h2&gt;
&lt;h3 id=&#34;21-过程奖励模型-vs-结果奖励模型&#34;&gt;2.1 过程奖励模型 vs 结果奖励模型&lt;/h3&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;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;ORM（结果奖励模型）&lt;/td&gt;
					&lt;td&gt;最终答案&lt;/td&gt;
					&lt;td&gt;简单、可自动验证&lt;/td&gt;
					&lt;td&gt;不知道哪步错了&lt;/td&gt;
					&lt;td&gt;数学、编程等答案可验证任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;PRM（过程奖励模型）&lt;/td&gt;
					&lt;td&gt;中间推理步骤&lt;/td&gt;
					&lt;td&gt;能定位错误步骤&lt;/td&gt;
					&lt;td&gt;需要大量过程标注&lt;/td&gt;
					&lt;td&gt;长推理、可分解任务&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;ORM 像期末考试只看最终分数；PRM 像老师批改作业，每步都打分。PRM 更好，但标注成本更高。&lt;/p&gt;
&lt;h3 id=&#34;22-mcts-中的探索与利用&#34;&gt;2.2 MCTS 中的探索与利用&lt;/h3&gt;
&lt;p&gt;MCTS（蒙特卡洛树搜索）在推理中用于探索不同解题路径。每选择一个节点时，需要平衡：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;利用（Exploitation）&lt;/strong&gt;：选择当前平均奖励高的节点；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;探索（Exploration）&lt;/strong&gt;：选择访问次数少、潜力未知的节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常用 UCB1 公式：&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;UCB = Q/N + c × sqrt(ln(N_parent) / N)&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;其中 Q 是累计奖励，N 是访问次数，c 是探索系数。&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;graph TD
    Root[根节点] --&amp;gt; A[节点 A&amp;lt;br/&amp;gt;Q=10 N=5]
    Root --&amp;gt; B[节点 B&amp;lt;br/&amp;gt;Q=3 N=1]
    Root --&amp;gt; C[节点 C&amp;lt;br/&amp;gt;Q=8 N=4]
    B --&amp;gt;|探索加分高| B1[优先探索 B]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;23-star让模型自己教自己推理&#34;&gt;2.3 STaR：让模型自己教自己推理&lt;/h3&gt;
&lt;p&gt;STaR（Self-Taught Reasoner）的核心流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;模型自己生成大量推理过程和答案；&lt;/li&gt;
&lt;li&gt;只保留答案正确的样本；&lt;/li&gt;
&lt;li&gt;用这些正确的 &lt;code&gt;(问题, 推理, 答案)&lt;/code&gt; 数据微调模型；&lt;/li&gt;
&lt;li&gt;迭代重复。&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
    Q[问题] --&amp;gt; G[模型生成推理+答案]
    G --&amp;gt; F{答案正确？}
    F --&amp;gt;|是| S[加入训练数据]
    F --&amp;gt;|否| D[丢弃]
    S --&amp;gt; T[微调模型]
    T --&amp;gt; Q&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;优点：不需要人工标注推理链；缺点：如果模型一开始生成能力差，容易陷入“错误循环”。&lt;/p&gt;
&lt;h3 id=&#34;24-推理深度与响应延迟的权衡&#34;&gt;2.4 推理深度与响应延迟的权衡&lt;/h3&gt;
&lt;p&gt;推理模型思考越久，准确率越高，但用户等待越久。常用平衡手段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;动态早停&lt;/strong&gt;：模型自己对答案有把握时停止思考。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预算控制&lt;/strong&gt;：设置最大思考 token 数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户可选深度&lt;/strong&gt;：比如“快速回答 / 详细推理 / 深度分析”。&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;三方法论选择什么时候用什么技术&#34;&gt;三、方法论选择：什么时候用什么技术？&lt;/h2&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;/td&gt;
					&lt;td&gt;提示工程&lt;/td&gt;
					&lt;td&gt;成本低、见效快&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;用户个性化记忆&lt;/td&gt;
					&lt;td&gt;提示工程 + 记忆系统&lt;/td&gt;
					&lt;td&gt;把用户历史注入上下文&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;案例库和事实知识&lt;/td&gt;
					&lt;td&gt;RAG&lt;/td&gt;
					&lt;td&gt;外挂知识库，减少幻觉&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;输出格式和语言风格&lt;/td&gt;
					&lt;td&gt;SFT&lt;/td&gt;
					&lt;td&gt;用成对数据训练模型习惯&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;领域基础能力&lt;/td&gt;
					&lt;td&gt;SFT&lt;/td&gt;
					&lt;td&gt;让模型学会领域表达和常识&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;领域深度思考能力&lt;/td&gt;
					&lt;td&gt;RL / 推理模型 RL&lt;/td&gt;
					&lt;td&gt;用可验证奖励优化推理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;领域工具调用能力&lt;/td&gt;
					&lt;td&gt;RL + Tool Calling&lt;/td&gt;
					&lt;td&gt;奖励正确的工具使用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;根据用户反馈持续优化&lt;/td&gt;
					&lt;td&gt;RLHF / DPO&lt;/td&gt;
					&lt;td&gt;把偏好信号转化为训练目标&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&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
    Need{需求是什么？} --&amp;gt;|知识/事实| RAG[RAG]
    Need --&amp;gt;|格式/风格| SFT[SFT]
    Need --&amp;gt;|快速验证| PE[提示工程]
    Need --&amp;gt;|深度推理| RL[RL 推理训练]
    Need --&amp;gt;|用户偏好| RLHF[RLHF/DPO]
    Need --&amp;gt;|工具使用| Tool[RL + Tool Calling]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;四deepseek-r1-深度解析&#34;&gt;四、DeepSeek-R1 深度解析&lt;/h2&gt;
&lt;h3 id=&#34;41-r1-与-r1-zero两条路径&#34;&gt;4.1 R1 与 R1-Zero：两条路径&lt;/h3&gt;
&lt;p&gt;DeepSeek-R1-Zero 是&lt;strong&gt;纯强化学习&lt;/strong&gt;的产物：直接在基座模型上用 GRPO 做 RL，没有任何 SFT 冷启动。它证明了：即使没有人工标注的推理数据，模型也能自发学会长思维链推理。&lt;/p&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;通用任务弱&lt;/strong&gt;：在非推理任务（写作、翻译、对话）上表现下降。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;DeepSeek-R1 则先用少量高质量 CoT 数据做 &lt;strong&gt;SFT 冷启动&lt;/strong&gt;，然后再用 GRPO 做 RL。这样既保留了推理能力，又改善了可读性和通用能力。&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 R1-Zero
        B1[基座模型] --&amp;gt; RL1[纯 RL]
        RL1 --&amp;gt; M1[推理强但可读性差]
    end

    subgraph R1
        B2[基座模型] --&amp;gt; SFT[SFT 冷启动]
        SFT --&amp;gt; RL2[RL 优化]
        RL2 --&amp;gt; M2[推理强 + 可读 + 通用]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;R1-Zero 的价值&lt;/strong&gt;：它证明了大模型可以通过纯 RL 自发涌现复杂推理能力。这是通向“超越人类智能”的一条可能路径——因为模型不再依赖人类标注的解题思路，而是可以自己探索策略。&lt;/p&gt;
&lt;h3 id=&#34;42-为什么-r1-在创意写作上也比基座模型更好&#34;&gt;4.2 为什么 R1 在创意写作上也比基座模型更好？&lt;/h3&gt;
&lt;p&gt;这看似违反直觉：推理模型不是做数学题的吗？&lt;/p&gt;
&lt;p&gt;实际上，R1 学到的不仅是“数学推理”，更是一种&lt;strong&gt;问题分解和自我评估&lt;/strong&gt;的元能力。在创意写作中，它会：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分析用户需求和潜在情绪；&lt;/li&gt;
&lt;li&gt;构思多个创意方向；&lt;/li&gt;
&lt;li&gt;快速评估哪个更有趣；&lt;/li&gt;
&lt;li&gt;输出最终内容。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这种“先想后写”的能力，让它即使思考过程较短，也能产出更有趣的内容。&lt;/p&gt;
&lt;h3 id=&#34;43-为什么-r1-不用-prmmctsbeam-search&#34;&gt;4.3 为什么 R1 不用 PRM、MCTS、Beam Search？&lt;/h3&gt;
&lt;p&gt;DeepSeek 的论文明确提到，他们尝试过 PRM 和 MCTS，但效果不佳。原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PRM&lt;/strong&gt;：需要大量高质量的过程标注，成本高，且很难定义“哪一步好”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCTS&lt;/strong&gt;：在开放文本生成中，搜索空间是组合爆炸的，每一步的“走法”太多了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Beam Search&lt;/strong&gt;：同样受限于巨大的候选空间，且不利于探索非确定性推理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GRPO + 可验证奖励（如答案正确性）更简单、更可扩展。&lt;/p&gt;
&lt;h3 id=&#34;44-grpo-vs-ppo为什么-r1-选择-grpo&#34;&gt;4.4 GRPO vs PPO：为什么 R1 选择 GRPO？&lt;/h3&gt;
&lt;p&gt;PPO 训练时需要维护多个模型：Actor、Critic、Reward Model、Reference Model。其中 Critic 模型通常和 Actor 一样大，显存开销很高。&lt;/p&gt;
&lt;p&gt;GRPO（Group Relative Policy Optimization）的改进：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不需要 Critic 模型&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;对同一个问题采样一组回答；&lt;/li&gt;
&lt;li&gt;用组内相对奖励计算优势函数（减去组内均值，除以标准差）。&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
    subgraph PPO
        P[Prompt] --&amp;gt; A[Actor]
        P --&amp;gt; C[Critic]
        A --&amp;gt; R[Reward Model]
        A --&amp;gt; Ref[Reference Model]
    end

    subgraph GRPO
        G[Prompt] --&amp;gt; GA[Actor]
        GA --&amp;gt;|采样 N 个回答| GR[组内相对奖励]
        GR --&amp;gt; GN[归一化优势]
        GA --&amp;gt; GRef[Reference Model]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;优势值归一化解决了 PPO 中 Critic 估计不准的问题，同时大幅降低了显存和计算成本。&lt;/p&gt;
&lt;h3 id=&#34;45-grpo-中的-kl-惩罚项&#34;&gt;4.5 GRPO 中的 KL 惩罚项&lt;/h3&gt;
&lt;p&gt;KL 惩罚项衡量当前策略与参考策略（通常是 SFT 模型）的差异，防止模型在 RL 训练中“跑偏”。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;KL 太大&lt;/strong&gt;：策略更新保守，学不到新能力；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KL 太小&lt;/strong&gt;：策略可能崩溃，输出乱码或 reward hacking。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;合适的 KL 系数需要在探索能力和稳定性之间找平衡。&lt;/p&gt;
&lt;h3 id=&#34;46-为什么-r1-的-sft-要加-20-万条非推理样本&#34;&gt;4.6 为什么 R1 的 SFT 要加 20 万条非推理样本？&lt;/h3&gt;
&lt;p&gt;如果只用推理数据做 SFT，模型会变成“只会做题的偏科生”。加入非推理样本（写作、翻译、对话、常识问答）可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保持通用语言能力；&lt;/li&gt;
&lt;li&gt;防止模型在非推理任务上退化；&lt;/li&gt;
&lt;li&gt;让最终模型既能深度思考，也能正常聊天。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;47-如何把-r1-蒸馏到小模型&#34;&gt;4.7 如何把 R1 蒸馏到小模型？&lt;/h3&gt;
&lt;p&gt;蒸馏的核心是用 R1 生成的高质量数据（包括长思维链）去监督微调一个小模型。步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 R1 在目标领域生成大量 &lt;code&gt;(问题, 思维链, 答案)&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;清洗和筛选高质量样本；&lt;/li&gt;
&lt;li&gt;在小模型上做 SFT；&lt;/li&gt;
&lt;li&gt;在垂直领域任务上评估。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;要保留特定领域能力，关键是&lt;strong&gt;蒸馏数据要覆盖该领域的典型问题和推理模式&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;48-r1-zero-为什么会多语言混杂&#34;&gt;4.8 R1-Zero 为什么会多语言混杂？&lt;/h3&gt;
&lt;p&gt;R1-Zero 的奖励函数只关心最终答案是否正确，不关心中间过程用什么语言。由于基座模型是多语言训练的，它会自发选择任何能表达推理的语言。中文 prompt 可能触发英文思考，反之亦然。&lt;/p&gt;
&lt;p&gt;R1 通过 SFT 冷启动，让模型先学会用规范、统一的语言输出思维链，解决了这个问题。&lt;/p&gt;
&lt;h3 id=&#34;49-如何把-r1-zero-方法扩展到主观领域&#34;&gt;4.9 如何把 R1-Zero 方法扩展到主观领域？&lt;/h3&gt;
&lt;p&gt;R1-Zero 依赖&lt;strong&gt;可验证奖励&lt;/strong&gt;，所以最适合数学、编程。扩展到创意写作、战略分析等主观领域，需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;定义可自动评估的代理指标（如多样性、一致性、可读性）；&lt;/li&gt;
&lt;li&gt;用 LLM-as-Judge 作为奖励信号；&lt;/li&gt;
&lt;li&gt;用人工偏好数据做 RLHF/DPO；&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-架构与训练系统创新&#34;&gt;五、DeepSeek 架构与训练系统创新&lt;/h2&gt;
&lt;h3 id=&#34;51-mla低秩压缩的-kv-缓存&#34;&gt;5.1 MLA：低秩压缩的 KV 缓存&lt;/h3&gt;
&lt;p&gt;多头注意力（MHA）每一层都要保存 Query、Key、Value。KV 缓存是推理时显存占用的主要来源。&lt;/p&gt;
&lt;p&gt;MLA（Multi-head Latent Attention）的核心思想：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;把 KV 压缩到一个低维“潜空间”，需要时再解压。&lt;/p&gt;
&lt;/blockquote&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;gt; Q[生成 Query]
    X --&amp;gt; K[生成 Key]
    X --&amp;gt; V[生成 Value]
    K --&amp;gt; C[低秩压缩]
    V --&amp;gt; C
    C --&amp;gt; KV[小 KV 缓存]
    KV --&amp;gt; D[解压]
    Q --&amp;gt; A[Attention]
    D --&amp;gt; A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;虽然 MLA 单 token 的 KV 可能比 MQA（Multi-Query Attention）多一点，但它保留了更多信息，模型性能更好。它本质上是对 &lt;strong&gt;(注意力头数, 隐藏维度)&lt;/strong&gt; 这个高维空间做低秩压缩。&lt;/p&gt;
&lt;h3 id=&#34;52-mla-与-rope-位置编码的兼容性&#34;&gt;5.2 MLA 与 RoPE 位置编码的兼容性&lt;/h3&gt;
&lt;p&gt;RoPE（旋转位置编码）把位置信息直接编码进 Q/K 向量中。如果直接对 KV 做低秩压缩，位置信息会被破坏。&lt;/p&gt;
&lt;p&gt;DeepSeek 的解决方案是把位置编码部分和可压缩部分&lt;strong&gt;解耦&lt;/strong&gt;：保留一个带位置信息的短向量，把其余信息压缩到潜空间。这样既能低秩压缩，又不丢失位置信息。&lt;/p&gt;
&lt;p&gt;如果用 ALiBi 等基于注意力偏置的位置编码，低秩压缩会引入与位置相关的偏置，更难处理。&lt;/p&gt;
&lt;h3 id=&#34;53-deepseek-moe为什么前-3-层用稠密连接&#34;&gt;5.3 DeepSeek MoE：为什么前 3 层用稠密连接？&lt;/h3&gt;
&lt;p&gt;MoE（Mixture of Experts）把每一层换成多个“专家网络”，每次只激活一部分。DeepSeek 的设计是：前 3 层保持稠密，后面用 MoE。&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;如果早期就用 MoE，不同 token 可能路由到不同专家，导致基础表示不一致，影响后续层。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;54-deepseek-moe-vs-mixtral-moe&#34;&gt;5.4 DeepSeek MoE vs Mixtral MoE&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;Mixtral MoE&lt;/th&gt;
					&lt;th&gt;DeepSeek MoE&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;专家数量&lt;/td&gt;
					&lt;td&gt;较少（如 8 个）&lt;/td&gt;
					&lt;td&gt;很多（细粒度专家）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;专家大小&lt;/td&gt;
					&lt;td&gt;较大&lt;/td&gt;
					&lt;td&gt;较小&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;共享专家&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;有共享专家始终激活&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;路由策略&lt;/td&gt;
					&lt;td&gt;Top-2&lt;/td&gt;
					&lt;td&gt;更细粒度的负载均衡路由&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;DeepSeek 的&lt;strong&gt;细粒度专家分割&lt;/strong&gt;让模型能组合更多专家能力；&lt;strong&gt;共享专家隔离&lt;/strong&gt;确保通用知识始终可用，避免所有 token 都涌向少数专家。&lt;/p&gt;
&lt;h3 id=&#34;55-专家负载均衡防止路由崩溃&#34;&gt;5.5 专家负载均衡：防止“路由崩溃”&lt;/h3&gt;
&lt;p&gt;如果所有 token 都选择同一个专家，其他专家就浪费了，这叫“路由崩溃”。DeepSeek 通过&lt;strong&gt;辅助损失函数&lt;/strong&gt;解决：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;专家级平衡损失&lt;/strong&gt;：鼓励每个专家处理的 token 数量均衡；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通信平衡损失&lt;/strong&gt;：减少节点间通信开销；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设备级平衡损失&lt;/strong&gt;：让不同 GPU 上的负载均衡。&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
    T[Token] --&amp;gt; R[路由网络]
    R --&amp;gt; E1[专家 1]
    R --&amp;gt; E2[专家 2]
    R --&amp;gt; E3[专家 3]
    E1 --&amp;gt; L[负载均衡损失]
    E2 --&amp;gt; L
    E3 --&amp;gt; L&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;56-多词元预测一次预测多个未来-token&#34;&gt;5.6 多词元预测：一次预测多个未来 token&lt;/h3&gt;
&lt;p&gt;传统模型一次只预测下一个 token。DeepSeek-V3 的多词元预测（Multi-Token Prediction）会同时预测后面几个 token。&lt;/p&gt;
&lt;p&gt;优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;样本效率更高&lt;/strong&gt;：每个训练位置提供多个监督信号；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;推理更快&lt;/strong&gt;：可以配合投机解码，一次验证多个 token。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;57-fp8-混合精度训练&#34;&gt;5.7 FP8 混合精度训练&lt;/h3&gt;
&lt;p&gt;DeepSeek-V3 在大量矩阵计算中使用 FP8（8 位浮点）量化，包括 Linear 层和 Attention 中的矩阵乘法。为了降低精度损失，它采用了&lt;strong&gt;分组量化（tile/block-wise quantization）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把大矩阵切成小块；&lt;/li&gt;
&lt;li&gt;每块独立计算 scale 和 zero-point；&lt;/li&gt;
&lt;li&gt;对激活值和权重都这样做。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样比全局量化更精细，损失更小。&lt;/p&gt;
&lt;h3 id=&#34;58-dualpipe双向流水线并行&#34;&gt;5.8 DualPipe：双向流水线并行&lt;/h3&gt;
&lt;p&gt;训练超大模型时，流水线并行把模型分层放到不同 GPU 上。传统流水线有“气泡时间”——GPU 在等待上下游数据时空闲。&lt;/p&gt;
&lt;p&gt;DualPipe 的创新是&lt;strong&gt;双向流水线&lt;/strong&gt;：同时从前后两个方向传递数据，让 GPU 尽可能不空闲。结合专家并行，它还能平衡 MoE 中不同专家的负载，提高整体训练效率。&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[GPU 1] --&amp;gt; B[GPU 2]
        B --&amp;gt; C[GPU 3]
        C --&amp;gt; D[GPU 4]
        style B fill:#f8cecc
        style C fill:#f8cecc
    end

    subgraph DualPipe
        E[GPU 1] --&amp;gt; F[GPU 2]
        F --&amp;gt; G[GPU 3]
        G --&amp;gt; H[GPU 4]
        H -.-&amp;gt; E
        style F fill:#e1f5e1
        style G fill:#e1f5e1
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;六扩展垂直领域与多模态&#34;&gt;六、扩展：垂直领域与多模态&lt;/h2&gt;
&lt;h3 id=&#34;61-在-qwq-32b-上强化-deep-research-能力&#34;&gt;6.1 在 QwQ-32B 上强化 Deep Research 能力&lt;/h3&gt;
&lt;p&gt;Deep Research 场景需要模型：搜索 → 浏览 → 总结 → 再搜索。构建 RL 训练数据时：&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;62-让-r1-支持图片推理&#34;&gt;6.2 让 R1 支持图片推理&lt;/h3&gt;
&lt;p&gt;要把 R1 扩展到多模态，需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增加视觉编码器（如 ViT）；&lt;/li&gt;
&lt;li&gt;构建图片 + 问题 + CoT + 答案的训练数据；&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;七从面试题到工程实践&#34;&gt;七、从面试题到工程实践&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要迷信大模型参数&lt;/strong&gt;。同样参数的推理模型和普通模型，能力侧重点完全不同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可验证奖励是 RL 训练的关键&lt;/strong&gt;。数学、编程适合 RL；开放域生成更适合 RLHF/DPO。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试时计算是新的 scaling 维度&lt;/strong&gt;。未来提升模型能力，不一定只靠堆参数量，也可以让它“想得更久”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;架构创新是为了训练和服务更便宜&lt;/strong&gt;。MLA、MoE、FP8、DualPipe 的目标都是在保持性能的同时降低成本。&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;p&gt;Part 4 把我们从“怎么用大模型”带到了“怎么训练和优化大模型”的深处。对初级开发者来说，不必一次性掌握所有细节，但要建立几个核心直觉：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;推理模型的本质是&lt;strong&gt;用更多测试时计算换准确率&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;RL 训练的关键是&lt;strong&gt;奖励信号设计&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;DeepSeek-R1 的成功说明：&lt;strong&gt;SFT 冷启动 + 可验证奖励的 RL&lt;/strong&gt; 是一条务实的路径；&lt;/li&gt;
&lt;li&gt;大模型训练不只是算法问题，更是&lt;strong&gt;系统工程问题&lt;/strong&gt;（MLA、MoE、FP8、DualPipe 都在解决工程效率）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你能理解这些，就已经具备了参与大模型应用和训练工程的基本视野。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;参考：《生成式AI原理与实战 —— Part 4》，答案基于公开论文与工程实践整理。&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    <item>
      <title>生成式AI原理与实战（Part 3）学习笔记：嵌入模型、表示微调与生成模型微调</title>
      <link>https://ftmao.com/blog/posts/llm-interview-notes-part3/</link>
      <pubDate>Sun, 09 Nov 2025 16:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/llm-interview-notes-part3/</guid>
      <description>&lt;h1 id=&#34;生成式ai原理与实战part-3学习笔记嵌入模型表示微调与生成模型微调&#34;&gt;生成式AI原理与实战（Part 3）学习笔记：嵌入模型、表示微调与生成模型微调&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这是《生成式AI原理与实战》学习笔记的第三篇。Part 1 聊了大模型的“底层零件”，Part 2 聊了提示工程、Agent 和 RAG；Part 3 则进入“模型训练与微调”领域：怎么训练一个好的文本嵌入模型、怎么在数据少的情况下微调分类模型、怎么用 LoRA/DPO/PPO 把通用大模型变成业务模型。目标读者仍然是&lt;strong&gt;刚接触 AI 的初中级开发者&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面为什么开发者要懂微调&#34;&gt;写在前面：为什么开发者要懂微调？&lt;/h2&gt;
&lt;p&gt;调用 API 能解决 80% 的问题，但剩下的 20% 往往需要你接触模型本身：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;公司私有文档的检索效果差，要不要自己训练嵌入模型？&lt;/li&gt;
&lt;li&gt;标注数据只有几百条，能微调分类模型吗？&lt;/li&gt;
&lt;li&gt;想让大模型输出符合公司风格的文案，除了写 prompt 还能做什么？&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;一文本嵌入模型让语义变成可计算的向量&#34;&gt;一、文本嵌入模型：让“语义”变成可计算的向量&lt;/h2&gt;
&lt;p&gt;嵌入模型（Embedding Model）的作用，是把文本变成固定长度的向量。语义相近的文本，向量距离就小；语义不同的文本，向量距离就大。它是 RAG、语义搜索、推荐系统的核心组件。&lt;/p&gt;
&lt;h3 id=&#34;11-为什么对比学习需要负样本&#34;&gt;1.1 为什么对比学习需要负样本？&lt;/h3&gt;
&lt;p&gt;训练嵌入模型时，如果只告诉模型“这两句话很相似，向量要靠近”，模型可能偷懒：把所有文本都编码成同一个向量。这样无论输入什么，相似度都很高，模型就失去了区分能力。&lt;/p&gt;
&lt;p&gt;负样本的作用就是告诉模型：&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 LR
    subgraph 只有正样本
        P1[A] --&amp;gt; C[中心点]
        P2[B] --&amp;gt; C
        P3[C] --&amp;gt; C
    end

    subgraph 加入负样本
        N1[A] -.-&amp;gt;|拉近| P[正样本对]
        N2[B] -.-&amp;gt;|拉近| P
        N3[C] --&amp;gt;|推远| P
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;高质量训练的关键是&lt;strong&gt;难负样本（Hard Negatives）&lt;/strong&gt;：那些看起来很像正确答案、但实际不对的样本。比如问“北京在哪里”，错误答案“上海是中国城市”就是一个难负样本，它会让模型学会更细粒度的区分。&lt;/p&gt;
&lt;h3 id=&#34;12-双编码器-vs-交叉编码器&#34;&gt;1.2 双编码器 vs 交叉编码器&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 class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Q[查询] --&amp;gt; B[双编码器 Bi-Encoder]
    D[文档库] --&amp;gt; B
    B --&amp;gt; C[候选 Top-k]
    C --&amp;gt; X[交叉编码器 Cross-Encoder]
    X --&amp;gt; R[精排结果]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;/td&gt;
					&lt;td&gt;查询和文档分别编码成向量&lt;/td&gt;
					&lt;td&gt;查询和文档拼接后一起输入模型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;速度&lt;/td&gt;
					&lt;td&gt;快，文档向量可离线预计算&lt;/td&gt;
					&lt;td&gt;慢，需要实时成对计算&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;精度&lt;/td&gt;
					&lt;td&gt;较低，缺乏细粒度交互&lt;/td&gt;
					&lt;td&gt;高，能捕捉词级关系&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;用途&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;召回阶段&lt;/strong&gt;：从海量文档中快速找候选&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;精排阶段&lt;/strong&gt;：对少量候选做精确排序&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;对初级开发者的建议&lt;/strong&gt;：不要一上来就用交叉编码器处理百万文档，会慢得无法接受。标准做法是“双编码器召回 Top-100 + 交叉编码器精排”。&lt;/p&gt;
&lt;h3 id=&#34;13-训练嵌入模型的损失函数怎么选&#34;&gt;1.3 训练嵌入模型的损失函数怎么选？&lt;/h3&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;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;MNR（多负例排序）&lt;/td&gt;
					&lt;td&gt;适合对比学习，能利用批量内负样本&lt;/td&gt;
					&lt;td&gt;依赖高质量负样本，计算随负例增加&lt;/td&gt;
					&lt;td&gt;大规模检索、对比预训练&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;余弦相似度损失&lt;/td&gt;
					&lt;td&gt;方向敏感，计算轻量，适合归一化嵌入&lt;/td&gt;
					&lt;td&gt;对难负样本区分度不足&lt;/td&gt;
					&lt;td&gt;文本相似度、资源受限场景&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Softmax 损失&lt;/td&gt;
					&lt;td&gt;直接优化分类，输出有概率意义&lt;/td&gt;
					&lt;td&gt;嵌入通用性差，不适合检索&lt;/td&gt;
					&lt;td&gt;意图识别、明确分类任务&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;14-没标注数据怎么办tsdae-无监督预训练&#34;&gt;1.4 没标注数据怎么办？TSDAE 无监督预训练&lt;/h3&gt;
&lt;p&gt;TSDAE（Transformer-based Sequential Denoising Auto-Encoder）的思路是：把输入文本加噪声（如随机删词、替换），再让模型重建原文。模型为了重建，必须学会抓住句子的全局语义。&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
    I[原始句子] --&amp;gt; N[加噪声]
    N --&amp;gt; E[Encoder 编码]
    E --&amp;gt; D[Decoder 重建]
    D --&amp;gt; O[还原原始句子]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;TSDAE 用特殊词元（如 &lt;code&gt;[CLS]&lt;/code&gt;）作为句子表征，而不是平均池化。原因是：&lt;code&gt;[CLS]&lt;/code&gt; 在训练中被迫压缩全局信息以重建整个句子，信号更强；而平均池化会被无关词稀释。&lt;/p&gt;
&lt;h3 id=&#34;15-怎么评测嵌入模型&#34;&gt;1.5 怎么评测嵌入模型？&lt;/h3&gt;
&lt;p&gt;MTEB（Massive Text Embedding Benchmark）是比 STS-B 更全面的评测基准，包含 8 类任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语义文本相似度（STS）&lt;/li&gt;
&lt;li&gt;检索（Retrieval）&lt;/li&gt;
&lt;li&gt;重排序（Reranking）&lt;/li&gt;
&lt;li&gt;分类（Classification）&lt;/li&gt;
&lt;li&gt;聚类（Clustering）&lt;/li&gt;
&lt;li&gt;配对分类（Pair Classification）&lt;/li&gt;
&lt;li&gt;摘要评估（Summarization）&lt;/li&gt;
&lt;li&gt;双语文本挖掘（Bitext Mining）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你做的业务是问答检索，就不要只看 STS 分数，要看 Retrieval 和 Reranking 指标。&lt;/p&gt;
&lt;h3 id=&#34;16-增量学习模型需要与时俱进&#34;&gt;1.6 增量学习：模型需要“与时俱进”&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 class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[收集新数据] --&amp;gt; B{分布是否变化？}
    B --&amp;gt;|是| C[概念漂移检测]
    B --&amp;gt;|否| D[继续监控]
    C --&amp;gt; E{性能是否退化？}
    E --&amp;gt;|是| F[增量微调]
    E --&amp;gt;|否| D
    F --&amp;gt; G[更新模型]
    G --&amp;gt; A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;检测方法包括：监控 KL 散度、KS 检验、在线评估指标等。更新时可以用小步微调，而不是从头训练。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二表示模型微调把小数据用出大价值&#34;&gt;二、表示模型微调：把小数据用出大价值&lt;/h2&gt;
&lt;p&gt;很多时候我们只有少量标注数据，却想做一个不错的分类或 NER 模型。这就需要“表示微调”的技巧。&lt;/p&gt;
&lt;h3 id=&#34;21-微调时冻结哪些层&#34;&gt;2.1 微调时冻结哪些层？&lt;/h3&gt;
&lt;p&gt;BERT 这类预训练模型，底层学习通用语法和语义，高层学习任务相关特征。微调时可以根据自己的情况决定：&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
    I[输入] --&amp;gt; L1[低层 Transformer&amp;lt;br/&amp;gt;通用语法语义]
    L1 --&amp;gt; L2[高层 Transformer&amp;lt;br/&amp;gt;任务相关语义]
    L2 --&amp;gt; H[分类头]
    H --&amp;gt; O[输出]

    style L1 fill:#e1f5e1
    style L2 fill:#fff2cc
    style H fill:#f8cecc&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&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;/td&gt;
					&lt;td&gt;冻结底层，只微调高层 + 分类头&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据较多&lt;/td&gt;
					&lt;td&gt;全模型微调&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务与预训练差异大&lt;/td&gt;
					&lt;td&gt;多微调几层&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;资源有限&lt;/td&gt;
					&lt;td&gt;冻结更多层，节省显存&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;22-setfit几百条数据也能做文本分类&#34;&gt;2.2 SetFit：几百条数据也能做文本分类&lt;/h3&gt;
&lt;p&gt;SetFit 是专门做少样本文本分类的框架。它的核心思想是：&lt;strong&gt;先用对比学习微调 Sentence Transformer，再在它生成的向量上训练一个轻量分类器&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
    S[少量标注样本] --&amp;gt; P[构造正负样本对]
    P --&amp;gt; C[对比学习微调 Encoder]
    C --&amp;gt; E[生成文本嵌入]
    E --&amp;gt; CL[训练分类器&amp;lt;br/&amp;gt;SVM / Logistic Regression]
    CL --&amp;gt; M[最终分类模型]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;为什么有效？因为即使是每类只有 5 条样本，两两组合也能生成很多训练对。对比学习让同类样本靠近、不同类样本远离，相当于学到了一个“任务专属的嵌入空间”。&lt;/p&gt;
&lt;h3 id=&#34;23-继续预训练拿到领域知识但别丢了通用能力&#34;&gt;2.3 继续预训练：拿到领域知识，但别丢了通用能力&lt;/h3&gt;
&lt;p&gt;让通用 BERT 适应医疗、法律等垂直领域，常用做法是继续预训练。但直接在全领域数据上训练，可能让模型忘掉通用语言知识，这叫&lt;strong&gt;灾难性遗忘&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;缓解方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;混合训练&lt;/strong&gt;：领域数据 + 通用数据一起训练。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分阶段训练&lt;/strong&gt;：先用通用数据 warm-up，再逐步增加领域数据，最后再用少量通用数据巩固。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapter / LoRA&lt;/strong&gt;：只训练少量新增参数，保留主干模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EWC（弹性权重巩固）&lt;/strong&gt;：对重要参数加约束，防止大幅偏离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;知识蒸馏&lt;/strong&gt;：用原始通用模型当教师，保留其预测分布。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;24-垂直领域分类三种方案对比&#34;&gt;2.4 垂直领域分类：三种方案对比&lt;/h3&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;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;直接微调通用 BERT&lt;/td&gt;
					&lt;td&gt;成本低、稳定&lt;/td&gt;
					&lt;td&gt;领域术语理解弱&lt;/td&gt;
					&lt;td&gt;快速验证、术语不复杂的任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;继续预训练 BERT 再微调&lt;/td&gt;
					&lt;td&gt;领域适应性强&lt;/td&gt;
					&lt;td&gt;需要大量无标注领域数据&lt;/td&gt;
					&lt;td&gt;有资源、有数据的团队&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;从头预训练领域模型&lt;/td&gt;
					&lt;td&gt;最强领域定制&lt;/td&gt;
					&lt;td&gt;资源消耗巨大、风险高&lt;/td&gt;
					&lt;td&gt;超大规模语料和算力&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对大多数团队来说，&lt;strong&gt;方案（b）是性价比最高的&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;25-ner-中的子词标签对齐&#34;&gt;2.5 NER 中的子词标签对齐&lt;/h3&gt;
&lt;p&gt;BERT 用 WordPiece 分词，会把一个词拆成多个子词。例如 &amp;ldquo;playing&amp;rdquo; → &amp;ldquo;play&amp;rdquo; + &amp;ldquo;##ing&amp;rdquo;。但 NER 标签是按词标注的，这就需要对齐：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只标注第一个子词&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;：第一个子词用原标签，后续子词改成 &lt;code&gt;I-&lt;/code&gt; 或 &lt;code&gt;O&lt;/code&gt;，避免 BIO 格式混乱。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;26-嵌入式设备上的小模型多任务训练&#34;&gt;2.6 嵌入式设备上的小模型多任务训练&lt;/h3&gt;
&lt;p&gt;如果要在手机、IoT 设备上跑模型，需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选轻量模型：MiniLM、TinyBERT、DistilBERT。&lt;/li&gt;
&lt;li&gt;多任务学习：共享一个编码器，接不同任务头。&lt;/li&gt;
&lt;li&gt;模型压缩：量化（INT8）、剪枝、知识蒸馏。&lt;/li&gt;
&lt;li&gt;部署格式：ONNX、TFLite。&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
    I[输入文本] --&amp;gt; E[Shared Encoder]
    E --&amp;gt; C[分类头]
    E --&amp;gt; N[NER 头]
    E --&amp;gt; V[Embedding 头]
    C --&amp;gt; O1[分类结果]
    N --&amp;gt; O2[实体标签]
    V --&amp;gt; O3[语义向量]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;三生成模型微调让通用模型变成你的模型&#34;&gt;三、生成模型微调：让通用模型变成“你的模型”&lt;/h2&gt;
&lt;h3 id=&#34;31-sft监督微调是最常用的起点&#34;&gt;3.1 SFT：监督微调是最常用的起点&lt;/h3&gt;
&lt;p&gt;SFT（Supervised Fine-Tuning）就是准备好 &lt;code&gt;(prompt, response)&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-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    D[准备 prompt-response 数据] --&amp;gt; S[SFT 微调]
    S --&amp;gt; E[评估效果]
    E --&amp;gt;|不够好| A[补充/清洗数据]
    A --&amp;gt; D
    E --&amp;gt;|效果好| P[上线部署]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;数据量建议（QA 对）：&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;1B - 7B&lt;/td&gt;
					&lt;td&gt;记住有限文档知识&lt;/td&gt;
					&lt;td&gt;1k - 20k&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;13B - 30B&lt;/td&gt;
					&lt;td&gt;强记忆 + 通用指令&lt;/td&gt;
					&lt;td&gt;10k - 100k&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;70B+&lt;/td&gt;
					&lt;td&gt;企业问答 + 任务泛化&lt;/td&gt;
					&lt;td&gt;50k - 500k&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;32-lora-与-qlora大模型微调的省钱方案&#34;&gt;3.2 LoRA 与 QLoRA：大模型微调的省钱方案&lt;/h3&gt;
&lt;p&gt;全参数微调 70B 模型需要大量 GPU。LoRA 的核心思想是：&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 LR
    X[输入] --&amp;gt; W[原始权重 W]
    W --&amp;gt; O[输出]
    X --&amp;gt; A[低秩矩阵 A]
    A --&amp;gt; B[低秩矩阵 B]
    B --&amp;gt; O&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;LoRA 的参数量大约是全量微调的 &lt;code&gt;1 / (d / 2r)&lt;/code&gt; 倍。例如 d=12288，r=8，参数量减少约 768 倍。&lt;/p&gt;
&lt;p&gt;QLoRA 在此基础上做了&lt;strong&gt;分块量化&lt;/strong&gt;：把权重矩阵切成小块，每块独立量化，保留各自的 scale 和 zero-point。这样比全局量化更精确，能在消费级 GPU 上微调大模型。&lt;/p&gt;
&lt;h3 id=&#34;33-超参数设置与停止训练&#34;&gt;3.3 超参数设置与停止训练&lt;/h3&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;/td&gt;
					&lt;td&gt;1e-5 - 2e-4&lt;/td&gt;
					&lt;td&gt;LoRA 可用稍大学习率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;LoRA rank&lt;/td&gt;
					&lt;td&gt;4 - 64&lt;/td&gt;
					&lt;td&gt;小任务 8/16，复杂任务 32+&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;LoRA alpha&lt;/td&gt;
					&lt;td&gt;rank × 2 - rank × 8&lt;/td&gt;
					&lt;td&gt;控制 LoRA 对主模型的影响强度&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;什么时候停止？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;验证集 loss 连续 N 个 epoch 不下降就停。&lt;/li&gt;
&lt;li&gt;不要只看 loss，还要看具体指标（准确率、F1、BLEU、ROUGE）。&lt;/li&gt;
&lt;li&gt;生成任务最好加人工评估，loss 低不代表回答好。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;34-损失函数应该计算输入部分还是输出部分&#34;&gt;3.4 损失函数应该计算输入部分还是输出部分？&lt;/h3&gt;
&lt;p&gt;&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;输入部分是人类写好的 prompt，让模型预测它没有意义，还会引入噪声。&lt;/li&gt;
&lt;li&gt;计算量更小，训练更快。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;35-ppo-与-dpo让模型符合人类偏好&#34;&gt;3.5 PPO 与 DPO：让模型符合人类偏好&lt;/h3&gt;
&lt;p&gt;SFT 让模型“学会回答问题”，但不一定“回答得好”。RLHF（基于人类反馈的强化学习）就是解决这个问题。&lt;/p&gt;
&lt;h4 id=&#34;经典-rlhf-三阶段&#34;&gt;经典 RLHF 三阶段&lt;/h4&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
    S[SFT 模型] --&amp;gt; R[训练奖励模型&amp;lt;br/&amp;gt;Reward Model]
    R --&amp;gt; P[PPO 强化学习]
    P --&amp;gt; A[对齐后的模型]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SFT&lt;/strong&gt;：训练模型学会基本对话。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练奖励模型&lt;/strong&gt;：收集人类偏好数据，训练一个打分模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPO 强化学习&lt;/strong&gt;：用奖励模型指导策略模型优化。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;ppo-里的四个角色&#34;&gt;PPO 里的四个角色&lt;/h4&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
    Prompt --&amp;gt; A[Actor&amp;lt;br/&amp;gt;生成回答]
    A --&amp;gt; C[Critic&amp;lt;br/&amp;gt;评估状态价值]
    A --&amp;gt; R[Reward Model&amp;lt;br/&amp;gt;给回答打分]
    A --&amp;gt; Ref[Reference Model&amp;lt;br/&amp;gt;计算 KL 散度&amp;lt;br/&amp;gt;防止跑偏]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;Actor&lt;/td&gt;
					&lt;td&gt;生成回答的主模型&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Critic&lt;/td&gt;
					&lt;td&gt;估计价值，计算优势函数&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Reward Model&lt;/td&gt;
					&lt;td&gt;给回答质量打分&lt;/td&gt;
					&lt;td&gt;否（通常预训练好）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Reference Model&lt;/td&gt;
					&lt;td&gt;计算 KL 散度，防止策略偏离初始模型&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;ppo-vs-dpo&#34;&gt;PPO vs DPO&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比项&lt;/th&gt;
					&lt;th&gt;PPO&lt;/th&gt;
					&lt;th&gt;DPO&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;训练范式&lt;/td&gt;
					&lt;td&gt;强化学习（on-policy）&lt;/td&gt;
					&lt;td&gt;监督学习（off-policy）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;是否需要奖励模型&lt;/td&gt;
					&lt;td&gt;需要&lt;/td&gt;
					&lt;td&gt;不需要&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;实现复杂度&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据利用率&lt;/td&gt;
					&lt;td&gt;低，只能用当前策略生成的数据&lt;/td&gt;
					&lt;td&gt;高，历史偏好数据都能用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;稳定性&lt;/td&gt;
					&lt;td&gt;较敏感，容易 reward hacking&lt;/td&gt;
					&lt;td&gt;更稳定&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;数据少的时候优先用 DPO&lt;/strong&gt;，它只需要 &lt;code&gt;(prompt, chosen, rejected)&lt;/code&gt; 三元组；等数据量和工程能力都上来了，再考虑 PPO。&lt;/p&gt;
&lt;h3 id=&#34;36-dpo-的-beta-参数&#34;&gt;3.6 DPO 的 beta 参数&lt;/h3&gt;
&lt;p&gt;beta 控制模型对偏好差异的敏感程度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;beta 小：偏好信号平滑，训练稳定，但可能学不到足够强的偏好。&lt;/li&gt;
&lt;li&gt;beta 适中（0.5-1.0）：常用默认值。&lt;/li&gt;
&lt;li&gt;beta 大：偏好差异被放大，模型对偏好更敏感，但可能过拟合或不稳定。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;37-把用户行为变成-dpo-数据&#34;&gt;3.7 把用户行为变成 DPO 数据&lt;/h3&gt;
&lt;p&gt;如果你运营一个 ChatGPT 类网站，用户行为天然就是偏好信号：&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;DPO 用法&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;点赞&lt;/td&gt;
					&lt;td&gt;喜欢这个回答&lt;/td&gt;
					&lt;td&gt;当前回答为 chosen&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;点踩&lt;/td&gt;
					&lt;td&gt;不喜欢&lt;/td&gt;
					&lt;td&gt;当前回答为 rejected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;重新生成&lt;/td&gt;
					&lt;td&gt;否定当前，偏好新的&lt;/td&gt;
					&lt;td&gt;新回答为 chosen，旧的为 rejected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;复制/分享&lt;/td&gt;
					&lt;td&gt;非常满意&lt;/td&gt;
					&lt;td&gt;当前回答为 chosen&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于小红书这类图文混合平台，停留时长受图片影响大，需要结合点赞、收藏等行为综合判断；知乎这类长文本平台，停留时长、评论互动更能反映内容质量。&lt;/p&gt;
&lt;h3 id=&#34;38-对齐隐私与提示词注入&#34;&gt;3.8 对齐、隐私与提示词注入&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;对齐问题&lt;/strong&gt;：模型目标函数与人类真实意图不一致。解决办法包括 RLHF/DPO、安全微调、拒绝训练、输出审查等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;隐私保护&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;训练前脱敏、移除 PII。&lt;/li&gt;
&lt;li&gt;训练中使用差分隐私优化。&lt;/li&gt;
&lt;li&gt;训练后扫描模型是否记住了敏感信息。&lt;/li&gt;
&lt;li&gt;部署时加输出拦截和 prompt 注入检测。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;通过微调防御提示词注入&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在训练数据里加入大量注入攻击样本，标注正确拒答。&lt;/li&gt;
&lt;li&gt;对抗式微调：生成各种攻击变体让模型学习。&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;ol&gt;
&lt;li&gt;&lt;strong&gt;嵌入模型优先用现成的&lt;/strong&gt;。MTEB 上排名靠前的模型（如 BGE、E5、GTE）通常足够好用，不要自己从头训练。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据少时试试 SetFit&lt;/strong&gt;。几百条标注也能做出不错的分类器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;大模型微调先 LoRA/QLoRA&lt;/strong&gt;。全参数微调太贵，LoRA 是性价比之选。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RLHF 先 DPO 后 PPO&lt;/strong&gt;。DPO 实现简单、数据利用率高，适合起步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不要迷信排行榜&lt;/strong&gt;。榜单分数高不代表业务效果好，要结合实际场景评估。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评估指标要对齐业务目标&lt;/strong&gt;。分类看 F1，检索看 Recall@K，生成看人工评估，不要只看 loss。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;结语&#34;&gt;结语&lt;/h2&gt;
&lt;p&gt;Part 3 的内容从“怎么训练嵌入模型”讲到“怎么微调分类模型”，再到“怎么对齐生成模型”。对初级开发者来说，重点是理解这些技术的&lt;strong&gt;适用场景和 trade-off&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;嵌入模型：双编码器快但粗，交叉编码器慢但准；负样本决定对比学习效果。&lt;/li&gt;
&lt;li&gt;表示微调：数据少就用 SetFit，数据多就全量微调；领域适配要注意灾难性遗忘。&lt;/li&gt;
&lt;li&gt;生成模型微调：SFT 是起点，LoRA 省钱，DPO/PPO 对齐人类偏好。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;掌握这些，你就能从“会调用模型”进阶到“会根据业务需求选择和调整模型”。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;参考：《生成式AI原理与实战 —— Part 3》&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    <item>
      <title>生成式AI原理与实战（Part 2）学习笔记：提示工程、Agent 与 RAG 的通俗理解</title>
      <link>https://ftmao.com/blog/posts/llm-interview-notes-part2/</link>
      <pubDate>Sat, 08 Nov 2025 15:24:25 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/llm-interview-notes-part2/</guid>
      <description>&lt;h1 id=&#34;生成式ai原理与实战part-2学习笔记提示工程agent-与-rag-的通俗理解&#34;&gt;生成式AI原理与实战（Part 2）学习笔记：提示工程、Agent 与 RAG 的通俗理解&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这是《生成式AI原理与实战》学习笔记的第二篇。Part 1 聊了 Transformer、Token、Embedding、Attention、KV Cache 这些“底层零件”；Part 2 则进入“怎么用”的层面：怎么写提示词、怎么让模型完成复杂任务、怎么给模型外挂知识库。目标读者仍然是&lt;strong&gt;刚接触 AI 的初中级开发者&lt;/strong&gt;——读完之后，你不需要会训模型，但应该能清楚地说出提示工程、Agent、RAG 这几个热门词到底在解决什么问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面从调用-api到搭一个系统&#34;&gt;写在前面：从“调用 API”到“搭一个系统”&lt;/h2&gt;
&lt;p&gt;如果你只调过 ChatGPT API，可能会觉得大模型就是一个“输入问题、返回答案”的黑盒。但实际做项目时，很快会遇到这些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同样的 prompt，为什么每次回答不一样？&lt;/li&gt;
&lt;li&gt;模型怎么老是“一本正经地胡说八道”？&lt;/li&gt;
&lt;li&gt;想让模型输出 JSON，它却总带多余解释。&lt;/li&gt;
&lt;li&gt;对话轮数多了，模型就忘了用户是谁。&lt;/li&gt;
&lt;li&gt;公司私有文档模型不知道，怎么办？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Part 2 的内容，本质上就是回答这些问题。我会把它们分成三块：&lt;strong&gt;提示工程&lt;/strong&gt;（怎么写好 prompt）、&lt;strong&gt;Agent&lt;/strong&gt;（怎么让模型动起来）、&lt;strong&gt;RAG&lt;/strong&gt;（怎么给模型外挂知识）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一提示工程不是写文案而是设计接口&#34;&gt;一、提示工程：不是写文案，而是设计接口&lt;/h2&gt;
&lt;p&gt;很多人把提示工程当成“怎么哄 AI 开心”。其实对开发者来说，prompt 更像一个&lt;strong&gt;函数签名&lt;/strong&gt;：输入清楚、输出可控、边界明确。&lt;/p&gt;
&lt;h3 id=&#34;11-两个旋钮temperature-与-top_p&#34;&gt;1.1 两个旋钮：temperature 与 top_p&lt;/h3&gt;
&lt;p&gt;大模型生成下一个词时，不是“选择概率最高的词”就完事了。它有两个常用的“随机性旋钮”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;temperature&lt;/strong&gt;：控制采样的“大胆程度”。值越低越保守，接近“只选概率最高的词”；值越高越有创意，容易跳出常规。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;top_p（nucleus sampling）&lt;/strong&gt;：只从累计概率达到一定比例的候选词里挑。比如 top_p=0.9，就只在概率最高的那一小撮词里采样。&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
    A[模型输出概率分布] --&amp;gt; B{采样策略}
    B --&amp;gt;|temperature 低| C[集中在高概率词&amp;lt;br/&amp;gt;输出稳定]
    B --&amp;gt;|temperature 高| D[概率被拉平&amp;lt;br/&amp;gt;输出更多样]
    B --&amp;gt;|top_p 小| E[候选池小&amp;lt;br/&amp;gt;更聚焦]
    B --&amp;gt;|top_p 大| F[候选池大&amp;lt;br/&amp;gt;更发散]&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&gt;任务类型&lt;/th&gt;
					&lt;th&gt;temperature&lt;/th&gt;
					&lt;th&gt;top_p&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;/td&gt;
					&lt;td&gt;0.2 - 0.5&lt;/td&gt;
					&lt;td&gt;0.8 - 1.0&lt;/td&gt;
					&lt;td&gt;需要准确、可重复&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;创意写作&lt;/td&gt;
					&lt;td&gt;0.7 - 1.0&lt;/td&gt;
					&lt;td&gt;0.9 - 1.0&lt;/td&gt;
					&lt;td&gt;需要多样性和想象力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;头脑风暴&lt;/td&gt;
					&lt;td&gt;0.8 - 1.2&lt;/td&gt;
					&lt;td&gt;0.9 - 1.0&lt;/td&gt;
					&lt;td&gt;越跳出常规越好&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;验证参数好坏的方法&lt;/strong&gt;：人工看多轮输出是否稳定/有趣；对翻译用 BLEU/ROUGE；对创意任务用 distinct-n 看词汇多样性。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;小知识：有些模型 temperature=0 时输出仍不稳定，可能是因为用了**推测解码（Speculative Decoding）**等加速技术，候选生成阶段仍带随机性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;12-一个专业提示词长什么样&#34;&gt;1.2 一个专业提示词长什么样？&lt;/h3&gt;
&lt;p&gt;把 prompt 当成接口文档来设计，通常包含以下模块：&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[任务目标]
    B --&amp;gt; C[输入信息/上下文]
    C --&amp;gt; D[输出格式]
    D --&amp;gt; E[约束条件]
    E --&amp;gt; F[示例]
    F --&amp;gt; G[模型输出]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;/td&gt;
					&lt;td&gt;限定语气、专业范围&lt;/td&gt;
					&lt;td&gt;“你是一位严谨的学术助手。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务目标&lt;/td&gt;
					&lt;td&gt;消除歧义&lt;/td&gt;
					&lt;td&gt;“请把下面这段话翻译成英文。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;输入信息&lt;/td&gt;
					&lt;td&gt;限制回答依据&lt;/td&gt;
					&lt;td&gt;“仅根据以下材料回答。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;输出格式&lt;/td&gt;
					&lt;td&gt;便于解析&lt;/td&gt;
					&lt;td&gt;“输出 JSON，包含结论和依据。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;约束条件&lt;/td&gt;
					&lt;td&gt;降低风险&lt;/td&gt;
					&lt;td&gt;“不要编造，不知道就说不知道。”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;示例&lt;/td&gt;
					&lt;td&gt;快速对齐预期&lt;/td&gt;
					&lt;td&gt;给 1-2 个输入输出样例&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;为什么角色定义很重要？&lt;/strong&gt; 大模型在训练时见过无数种文体和身份。明确角色，相当于激活了模型内部对应的知识路径和语气风格，也能让它更谨慎，减少胡说八道的概率。&lt;/p&gt;
&lt;h3 id=&#34;13-怎么减少模型幻觉&#34;&gt;1.3 怎么减少模型“幻觉”？&lt;/h3&gt;
&lt;p&gt;幻觉（Hallucination）就是模型一本正经地编造不存在的信息。常用防御手段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;限定信息源&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;：让模型说明答案出处。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制输出格式&lt;/strong&gt;：用 JSON、表格等结构化输出，减少自由发挥。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低 temperature&lt;/strong&gt;：减少随机编造。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;14-怎么防止提示词注入攻击&#34;&gt;1.4 怎么防止提示词注入攻击？&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 class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[用户输入] --&amp;gt; B[结构化隔离&amp;lt;br/&amp;gt;JSON/YAML/字段分离]
    B --&amp;gt; C[系统层过滤&amp;lt;br/&amp;gt;正则/规则/小模型守门]
    C --&amp;gt; D[明确指令优先级&amp;lt;br/&amp;gt;禁止修改角色与规则]
    D --&amp;gt; E[函数调用输出&amp;lt;br/&amp;gt;固定 schema]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结构化输入&lt;/strong&gt;：不要把用户输入直接拼进自然语言 prompt，用 JSON 等格式隔离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;明确边界&lt;/strong&gt;：系统提示里写明“不可改变角色”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数调用&lt;/strong&gt;：让模型按固定 schema 输出，减少被操控空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统层检测&lt;/strong&gt;：用规则或小模型识别异常输入（如突然要求“忽略之前指令”）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;15-让模型先思考再回答cotself-consistencytot&#34;&gt;1.5 让模型“先思考再回答”：CoT、Self-Consistency、ToT&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 class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    subgraph 思维链 CoT
        Q1[问题] --&amp;gt; R1[一步一步推理] --&amp;gt; A1[答案]
    end

    subgraph 自洽性 Self-Consistency
        Q2[问题] --&amp;gt; R2a[采样推理 1]
        Q2 --&amp;gt; R2b[采样推理 2]
        Q2 --&amp;gt; R2c[采样推理 N]
        R2a --&amp;gt; V[投票/多数共识]
        R2b --&amp;gt; V
        R2c --&amp;gt; V
        V --&amp;gt; A2[最终答案]
    end

    subgraph 思维树 ToT
        Q3[问题] --&amp;gt; B1[分支 1]
        Q3 --&amp;gt; B2[分支 2]
        Q3 --&amp;gt; B3[分支 3]
        B1 --&amp;gt; E[评估/回溯]
        B2 --&amp;gt; E
        B3 --&amp;gt; E
        E --&amp;gt; A3[最优答案]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;CoT&lt;/td&gt;
					&lt;td&gt;简单有效，兼容多数模型&lt;/td&gt;
					&lt;td&gt;可能产生幻觉推理步骤&lt;/td&gt;
					&lt;td&gt;数学、逻辑题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Self-Consistency&lt;/td&gt;
					&lt;td&gt;稳定，减少随机波动&lt;/td&gt;
					&lt;td&gt;计算开销大&lt;/td&gt;
					&lt;td&gt;精度要求高&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ToT&lt;/td&gt;
					&lt;td&gt;多路径探索，适合长规划&lt;/td&gt;
					&lt;td&gt;实现复杂&lt;/td&gt;
					&lt;td&gt;解谜、策略任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;反思 Reflection&lt;/td&gt;
					&lt;td&gt;可自我纠错&lt;/td&gt;
					&lt;td&gt;依赖初始回答质量&lt;/td&gt;
					&lt;td&gt;代码调试、文本润色&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;16-怎么保证输出格式&#34;&gt;1.6 怎么保证输出格式？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;明确格式要求&lt;/strong&gt;：在 prompt 里清楚说明想要的结构。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;给 few-shot 示例&lt;/strong&gt;：1-2 个例子比千言万语管用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制随机性&lt;/strong&gt;：JSON 输出常用 temperature=0。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用 API 的 JSON Mode / Function Calling&lt;/strong&gt;：从接口层面约束输出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后处理校验&lt;/strong&gt;：用 &lt;code&gt;json.loads()&lt;/code&gt; 等工具兜底。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;17-分类任务怎么保证只输出指定类别&#34;&gt;1.7 分类任务怎么保证只输出指定类别？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;提示词里写明“只能输出以下类别之一”。&lt;/li&gt;
&lt;li&gt;用 API 的 &lt;code&gt;logit_bias&lt;/code&gt; 强行禁止非法 token。&lt;/li&gt;
&lt;li&gt;Function Calling 限定返回枚举值。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二agent让大模型从回答问题到完成任务&#34;&gt;二、Agent：让大模型从“回答问题”到“完成任务”&lt;/h2&gt;
&lt;p&gt;提示工程解决的是“单次问答怎么做好”；Agent 解决的是“怎么让模型自主完成一个多步骤任务”。&lt;/p&gt;
&lt;h3 id=&#34;21-agent-的工作循环&#34;&gt;2.1 Agent 的工作循环&lt;/h3&gt;
&lt;p&gt;一个典型的 Agent 长这样：&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;gt; B[思考 Thought]
    B --&amp;gt; C[行动 Action]
    C --&amp;gt; D[调用工具/搜索/查库]
    D --&amp;gt; E[观察 Observation]
    E --&amp;gt; F{任务完成了吗？}
    F --&amp;gt;|否| B
    F --&amp;gt;|是| G[输出最终答案]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这就是 ReAct 模式的核心：&lt;strong&gt;想一步、做一步、看结果、再决定下一步&lt;/strong&gt;。比如你要做一个“调研 GPT-5 最新消息”的 Agent，它的循环可能是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分析目标 → 提取关键词。&lt;/li&gt;
&lt;li&gt;生成搜索关键词。&lt;/li&gt;
&lt;li&gt;调用搜索引擎。&lt;/li&gt;
&lt;li&gt;浏览网页，抽取信息。&lt;/li&gt;
&lt;li&gt;更新记忆，避免重复搜索。&lt;/li&gt;
&lt;li&gt;判断是否需要继续，直到满意。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;22-多-agent-协作一个复杂任务拆给多个专员&#34;&gt;2.2 多 Agent 协作：一个复杂任务拆给多个“专员”&lt;/h3&gt;
&lt;p&gt;当任务复杂、提示词过长时，可以把一个 Agent 拆成多个子 Agent：&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
    U[用户请求] --&amp;gt; R[Router Agent&amp;lt;br/&amp;gt;识别意图]
    R --&amp;gt; F[航班 Agent]
    R --&amp;gt; H[酒店 Agent]
    R --&amp;gt; I[行程 Agent]
    F --&amp;gt; P[Planner Agent&amp;lt;br/&amp;gt;整合结果]
    H --&amp;gt; P
    I --&amp;gt; P
    P --&amp;gt; O[返回用户]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Router Agent&lt;/strong&gt;：根据用户意图决定调用谁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;子 Agent&lt;/strong&gt;：各自处理专业领域。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Planner Agent&lt;/strong&gt;：汇总输出，生成统一回复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;子 Agent 之间通过共享上下文对象、向量数据库等方式传递信息。&lt;/p&gt;
&lt;h3 id=&#34;23-记忆模型不会自动记住你&#34;&gt;2.3 记忆：模型不会自动记住你&lt;/h3&gt;
&lt;p&gt;大模型本身没有长期记忆。对话轮数多了，它会“忘”掉 earlier 的关键信息。解决办法：&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[滑动窗口&amp;lt;br/&amp;gt;保留最近 N 轮]
    B --&amp;gt; C[摘要压缩&amp;lt;br/&amp;gt;生成关键状态]
    C --&amp;gt; D[外部记忆存储&amp;lt;br/&amp;gt;Redis/向量库]
    D --&amp;gt; E[需要时检索注入 Prompt]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;显式重复&lt;/strong&gt;：把关键信息重新塞进 prompt。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;摘要压缩&lt;/strong&gt;：每 N 轮生成一次对话摘要。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;外部存储&lt;/strong&gt;：用 Redis、向量数据库保存用户画像和历史事件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KV 缓存持久化&lt;/strong&gt;：把历史对话的 Key-Value 缓存存起来，下一轮直接复用，减少重复计算和延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;24-异步工具调用别让一个慢工具卡住整个对话&#34;&gt;2.4 异步工具调用：别让一个慢工具卡住整个对话&lt;/h3&gt;
&lt;p&gt;如果某个工具（比如查航班 API）要几秒才返回，Agent 不应该傻等。可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把工具调用做成异步任务。&lt;/li&gt;
&lt;li&gt;给用户一个中间状态回复：“正在查询，请稍等。”&lt;/li&gt;
&lt;li&gt;同时处理其他事情，工具返回后再继续。&lt;/li&gt;
&lt;li&gt;用请求 ID 追踪每个调用，确保结果能匹配回上下文。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三rag给大模型外接一个知识库&#34;&gt;三、RAG：给大模型外接一个“知识库”&lt;/h2&gt;
&lt;p&gt;大模型训练数据有截止日期，也不会包含你的私有文档。RAG（Retrieval-Augmented Generation，检索增强生成）的思路是：&lt;strong&gt;在生成答案前，先从外部知识库检索相关内容，把检索结果作为上下文喂给模型&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;31-rag-的基本流程&#34;&gt;3.1 RAG 的基本流程&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
    Q[用户问题] --&amp;gt; R[检索模块]
    D[文档库] --&amp;gt; C[文档分块]
    C --&amp;gt; V[向量数据库]
    V --&amp;gt; R
    R --&amp;gt; M[Top-k 相关片段]
    M --&amp;gt; L[大模型]
    Q --&amp;gt; L
    L --&amp;gt; A[带依据的答案]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;32-为什么要把文档切成块&#34;&gt;3.2 为什么要把文档切成块？&lt;/h3&gt;
&lt;p&gt;直接拿整篇文档做向量，效果不好，原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;检索精度低&lt;/strong&gt;：用户只关心其中一两段，整篇文档的向量会被不相关部分稀释。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;嵌入模型有长度限制&lt;/strong&gt;：BERT、MiniLM 等通常只能处理 512 token 左右。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;细粒度匹配更好&lt;/strong&gt;：小片段更容易和查询语义对齐。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但切块也会带来&lt;strong&gt;上下文缺失&lt;/strong&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;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;滑动窗口 + 重叠&lt;/td&gt;
					&lt;td&gt;相邻块有重叠区域&lt;/td&gt;
					&lt;td&gt;保留局部上下文&lt;/td&gt;
					&lt;td&gt;存储冗余&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;带标题分块&lt;/td&gt;
					&lt;td&gt;每个块附带章节标题&lt;/td&gt;
					&lt;td&gt;增强结构感&lt;/td&gt;
					&lt;td&gt;对无结构文档效果有限&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;检索时扩展&lt;/td&gt;
					&lt;td&gt;召回相邻块一起送给模型&lt;/td&gt;
					&lt;td&gt;上下文完整&lt;/td&gt;
					&lt;td&gt;需要系统支持&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;多粒度索引&lt;/td&gt;
					&lt;td&gt;同时建“摘要级”和“原文级”索引&lt;/td&gt;
					&lt;td&gt;兼顾梗概与细节&lt;/td&gt;
					&lt;td&gt;实现复杂&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;33-向量检索不够还要混合检索和重排序&#34;&gt;3.3 向量检索不够，还要混合检索和重排序&lt;/h3&gt;
&lt;p&gt;向量检索擅长“语义相似”，但不擅长“精确关键词匹配”；传统关键词检索（如 BM25）正好反过来。所以生产环境常用&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 LR
    Q[用户查询] --&amp;gt; A[向量检索&amp;lt;br/&amp;gt;Dense Retrieval]
    Q --&amp;gt; B[关键词检索&amp;lt;br/&amp;gt;BM25/TF-IDF]
    A --&amp;gt; F[候选结果]
    B --&amp;gt; F
    F --&amp;gt; R[Rerank&amp;lt;br/&amp;gt;Cross-Encoder]
    R --&amp;gt; K[Top-k 最相关片段]
    K --&amp;gt; L[大模型生成]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;向量检索&lt;/strong&gt;：找语义相近的文档。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关键词检索&lt;/strong&gt;：补全精确匹配能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rerank（重排序）&lt;/strong&gt;：用更强的 Cross-Encoder 模型对召回结果精排。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;34-为什么查询要改写&#34;&gt;3.4 为什么查询要改写？&lt;/h3&gt;
&lt;p&gt;用户提问往往口语化、不完整，直接拿去检索效果差。Query Rewriting 的目标是把问题改写成“更适合嵌入模型的语义表达”。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原问题：“他出生在哪？”&lt;/li&gt;
&lt;li&gt;改写后：“Barack Obama was born in ?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方法包括：LLM 改写、同义词扩展、模板化改写、指令式嵌入（如 E5 模型的 &lt;code&gt;query:&lt;/code&gt; 前缀）。&lt;/p&gt;
&lt;h3 id=&#34;35-检索到冲突或过时的信息怎么办&#34;&gt;3.5 检索到冲突或过时的信息怎么办？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;检索前&lt;/strong&gt;：做数据源筛选、时效性过滤。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检索中&lt;/strong&gt;：多阶段 reranking，提升相关性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成前&lt;/strong&gt;：在 prompt 里加防御性约束，比如“如果来源冲突，请说明”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成时&lt;/strong&gt;：要求模型标注来源，输出可信度分数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成后&lt;/strong&gt;：用一致性校验或外部验证器判断答案是否忠实于来源。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;36-rag-的可解释性&#34;&gt;3.6 RAG 的可解释性&lt;/h3&gt;
&lt;p&gt;想让用户信任答案，最好告诉它“这个答案来自哪”。做法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保留文档 ID、URL、时间戳。&lt;/li&gt;
&lt;li&gt;做生成-来源对齐（Attribution），把生成内容逐句回溯到文档片段。&lt;/li&gt;
&lt;li&gt;输出置信度分数：检索相似度、生成概率、验证器分数等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;37-多模态-rag-与长期记忆&#34;&gt;3.7 多模态 RAG 与长期记忆&lt;/h3&gt;
&lt;p&gt;RAG 不限于文本。可以扩展到图像、视频：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用 CLIP 等模型把图像、文本映射到统一向量空间。&lt;/li&gt;
&lt;li&gt;文档里的图表提取为图像块，保留位置信息。&lt;/li&gt;
&lt;li&gt;视频按时间分段，提取关键帧 + ASR 文本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI 伴侣、企业知识库这类长期记忆场景，则需要：每日摘要、事件图谱、多层次召回、时间感知检索、经验版本控制（避免新经验覆盖旧经验）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四从面试题到工程实践给初级开发者的建议&#34;&gt;四、从面试题到工程实践：给初级开发者的建议&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先跑通端到端，再优化局部&lt;/strong&gt;。不要一上来就追求最先进的 reranker 或 Agent 框架，先用最简单的方式验证需求是否成立。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;把 prompt 当代码管&lt;/strong&gt;。纳入 Git，做版本控制，写回归测试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评估比调参更重要&lt;/strong&gt;。没有指标，就不知道改进是否有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文质量 &amp;gt; 上下文长度&lt;/strong&gt;。塞太多无关信息，反而让模型抓不到重点。&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;p&gt;Part 2 的内容从“怎么写 prompt”一路延伸到“怎么搭 Agent、做 RAG”。对初级开发者来说，最重要的不是记住每个参数的具体数值，而是理解这些技术背后的&lt;strong&gt;工程思想&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提示工程 = 设计人与模型的接口协议；&lt;/li&gt;
&lt;li&gt;Agent = 把单次调用扩展成有状态、有工具、有记忆的循环；&lt;/li&gt;
&lt;li&gt;RAG = 用外部知识库补齐模型能力的缺口。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;掌握这三块，你就已经能从“会调 API”进阶到“能搭 AI 应用”了。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;参考：《生成式AI原理与实战 —— Part 2》&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    <item>
      <title>生成式AI原理与实战（Part 1）学习笔记：给初级开发者的 LLM 入门图解</title>
      <link>https://ftmao.com/blog/posts/llm-interview-notes-part1/</link>
      <pubDate>Fri, 07 Nov 2025 15:18:31 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/llm-interview-notes-part1/</guid>
      <description>&lt;h1 id=&#34;生成式ai原理与实战part-1学习笔记给初级开发者的-llm-入门图解&#34;&gt;生成式AI原理与实战（Part 1）学习笔记：给初级开发者的 LLM 入门图解&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;读完《生成式AI原理与实战 —— Part 1》后，我把 58 个问题整理成这篇文章。目标读者是&lt;strong&gt;刚接触 AI 的初中级开发者&lt;/strong&gt;：你不用会推反向传播，但读完后应该能清楚地说出大模型是怎么“看”文本、怎么生成文本、以及怎么在实际任务里用它。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面为什么开发者要懂这些&#34;&gt;写在前面：为什么开发者要懂这些？&lt;/h2&gt;
&lt;p&gt;如果你只是调用 API，可能会觉得大模型就像一个“黑盒 HTTP 服务”。但真到做项目时，很多问题都和底层机制有关：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么同样的中文输入，不同模型算出来的 Token 数差很多？&lt;/li&gt;
&lt;li&gt;为什么上下文不能无限长？&lt;/li&gt;
&lt;li&gt;为什么模型做数学题会错？&lt;/li&gt;
&lt;li&gt;RAG、Agent、微调这些词到底在解决什么问题？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文章会用“概念 + 图 + 生活化类比”来回答。每张图都是帮助你建立直觉，而不是背公式。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一大模型不是单一结构三种-transformer-架构&#34;&gt;一、大模型不是单一结构：三种 Transformer 架构&lt;/h2&gt;
&lt;p&gt;大模型基本都基于 Transformer。Transformer 最初有&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;graph LR
    subgraph 仅编码器模型
        A1[输入文本] --&amp;gt; E1[Encoder&amp;lt;br/&amp;gt;双向 Self-Attention]
        E1 --&amp;gt; O1[理解结果/分类]
    end

    subgraph 仅解码器模型
        A2[前缀文本] --&amp;gt; D2[Decoder&amp;lt;br/&amp;gt;Masked Self-Attention]
        D2 --&amp;gt; O2[逐字生成&amp;lt;br/&amp;gt;自回归]
    end

    subgraph 编码器-解码器模型
        A3[输入文本] --&amp;gt; E3[Encoder]
        E3 --&amp;gt; D3[Decoder&amp;lt;br/&amp;gt;Cross-Attention]
        D3 --&amp;gt; O3[翻译/摘要]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;th&gt;典型用途&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;仅编码器&lt;/td&gt;
					&lt;td&gt;BERT、RoBERTa&lt;/td&gt;
					&lt;td&gt;双向（整句一起看）&lt;/td&gt;
					&lt;td&gt;分类、检索、文本匹配&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;仅解码器&lt;/td&gt;
					&lt;td&gt;GPT、LLaMA、Mistral&lt;/td&gt;
					&lt;td&gt;单向（只能看左边）&lt;/td&gt;
					&lt;td&gt;续写、对话、代码生成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;编码器-解码器&lt;/td&gt;
					&lt;td&gt;T5、BART&lt;/td&gt;
					&lt;td&gt;编码器双向 + 解码器单向&lt;/td&gt;
					&lt;td&gt;翻译、摘要、复杂生成&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;GPT 和原始 Transformer 的最大区别&lt;/strong&gt;：GPT 把解码器单独拿出来，训练目标是“给定前文，预测下一个 token”，也就是&lt;strong&gt;自回归语言建模&lt;/strong&gt;。这让 GPT 系列天然适合生成任务。&lt;/p&gt;
&lt;h3 id=&#34;11-为什么-transformer-比-rnnattention-强&#34;&gt;1.1 为什么 Transformer 比 RNN+Attention 强？&lt;/h3&gt;
&lt;p&gt;早期 LSTM/GRU 需要一步一步处理序列，计算是串行的。Transformer 的自注意力可以一次性看到整句话，所有位置并行计算。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;并行&lt;/strong&gt;：训练速度大幅提升。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长距离依赖&lt;/strong&gt;：RNN 对很远距离的信息容易“遗忘”，自注意力让任意两个 token 直接建立联系。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结构统一&lt;/strong&gt;：没有复杂的循环状态，更容易扩展成超大模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代价是计算复杂度为 &lt;code&gt;O(n²)&lt;/code&gt;，n 是序列长度。这也是上下文窗口不能无限长的根本原因。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二从文本到向量token-与-embedding&#34;&gt;二、从文本到向量：Token 与 Embedding&lt;/h2&gt;
&lt;p&gt;大模型看不懂“字”，它只能处理数字。所以第一步是&lt;strong&gt;分词（Tokenization）&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
    T[原始文本] --&amp;gt; Token[Tokenizer 切分]
    Token --&amp;gt; ID[Token ID]
    ID --&amp;gt; Emb[Embedding 向量]
    Emb --&amp;gt; PE[加位置编码]
    PE --&amp;gt; In[输入 Transformer]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;21-大模型分词器-vs-传统中文分词&#34;&gt;2.1 大模型分词器 vs 传统中文分词&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比&lt;/th&gt;
					&lt;th&gt;大模型 Tokenizer&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;/td&gt;
					&lt;td&gt;给神经网络高效编码&lt;/td&gt;
					&lt;td&gt;切出符合语言学的“词”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;粒度&lt;/td&gt;
					&lt;td&gt;子词、字符、字节，视词表而定&lt;/td&gt;
					&lt;td&gt;一般是词&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OOV 处理&lt;/td&gt;
					&lt;td&gt;拆成子词/字节，几乎不会失败&lt;/td&gt;
					&lt;td&gt;拆成单字或按规则处理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;例子&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;hello&amp;rdquo; → [&amp;ldquo;hell&amp;rdquo;, &amp;ldquo;o&amp;rdquo;]&lt;/td&gt;
					&lt;td&gt;&amp;ldquo;人工智能&amp;rdquo; → [&amp;ldquo;人工&amp;rdquo;, &amp;ldquo;智能&amp;rdquo;]&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;给定一个词表，分词结果通常是唯一的&lt;/strong&gt;。因为现代 Tokenizer 大多采用贪心最长匹配（BPE、WordPiece、Unigram 等），优先匹配最长的子词。&lt;/p&gt;
&lt;h3 id=&#34;22-字节级-bpe-为什么更通用&#34;&gt;2.2 字节级 BPE 为什么更通用？&lt;/h3&gt;
&lt;p&gt;GPT-4、Llama 等模型使用 &lt;strong&gt;byte-level BPE&lt;/strong&gt;：先把文本转成 UTF-8 字节序列，再在字节上做 BPE。&lt;/p&gt;
&lt;p&gt;好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任何语言、Emoji、乱码、代码都能被编码，&lt;strong&gt;没有 OOV&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;不需要为每种语言设计特殊预处理。&lt;/li&gt;
&lt;li&gt;不同平台对 UTF-8 字节表示一致，迁移更稳定。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;23-大模型怎么区分用户说的和ai-说的&#34;&gt;2.3 大模型怎么区分“用户说的”和“AI 说的”？&lt;/h3&gt;
&lt;p&gt;靠&lt;strong&gt;特殊 Token&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;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;|user|&amp;gt; 今天天气怎么样？ &amp;lt;|assistant|&amp;gt; 今天天气很好，晴朗温暖。 &amp;lt;|end|&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;模型在训练过程中学会了：看到 &lt;code&gt;&amp;lt;|assistant|&amp;gt;&lt;/code&gt; 就知道要切换成回答模式。实际调用 ChatGPT、Claude 的 API 时，&lt;code&gt;role: user/assistant/system&lt;/code&gt; 也是同样的道理。&lt;/p&gt;
&lt;h3 id=&#34;24-工具调用时输出怎么和文本回复区分&#34;&gt;2.4 工具调用时，输出怎么和文本回复区分？&lt;/h3&gt;
&lt;p&gt;模型通过&lt;strong&gt;输出格式约定&lt;/strong&gt;区分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;普通回复：生成自然语言文本。&lt;/li&gt;
&lt;li&gt;工具调用：生成结构化的 JSON / Function Call Schema。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务端拿到输出后，检查结构：如果是 JSON，就执行工具；如果是文本，就直接返回给用户。训练阶段会通过 RLHF 告诉模型“该调用工具时不要废话，直接输出 JSON”。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三静态-vs-上下文相关-embedding&#34;&gt;三、静态 vs 上下文相关 Embedding&lt;/h2&gt;
&lt;h3 id=&#34;31-word2vec-的负例有什么用&#34;&gt;3.1 word2vec 的负例有什么用？&lt;/h3&gt;
&lt;p&gt;word2vec 有两种训练方式：CBOW 和 Skip-gram。Skip-gram + Negative Sampling 中，负例让训练从“对整个词表做 softmax”变成“对少量正例 + 负例做二分类”。&lt;/p&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;学到区分性表示&lt;/strong&gt;：正确搭配拉近，错误搭配推远。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;32-静态-embedding-和上下文相关-embedding&#34;&gt;3.2 静态 Embedding 和上下文相关 Embedding&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;静态词嵌入（word2vec/GloVe）&lt;/th&gt;
					&lt;th&gt;上下文相关嵌入（BERT/GPT）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;向量&lt;/td&gt;
					&lt;td&gt;每个词一个固定向量&lt;/td&gt;
					&lt;td&gt;每个词每次出现都不同&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;例子&lt;/td&gt;
					&lt;td&gt;“bank” 永远是一个向量&lt;/td&gt;
					&lt;td&gt;在 “river bank” 和 “investment bank” 中向量不同&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;结构&lt;/td&gt;
					&lt;td&gt;浅层神经网络&lt;/td&gt;
					&lt;td&gt;深层 Transformer&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;能力&lt;/td&gt;
					&lt;td&gt;捕捉共现关系&lt;/td&gt;
					&lt;td&gt;理解语义、消歧、语法&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;静态 Embedding 仍然有价值&lt;/strong&gt;：轻量、快速、可解释、适合小数据和边缘设备。很多推荐系统、搜索召回场景仍然用 Embedding 模型。&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 静态词嵌入
        W1[bank] --&amp;gt; V1[固定向量]
    end
    subgraph 上下文相关嵌入
        S1[&amp;#34;river bank&amp;#34;] --&amp;gt; C1[向量A]
        S2[&amp;#34;investment bank&amp;#34;] --&amp;gt; C2[向量B]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;四llm-的内部机制&#34;&gt;四、LLM 的内部机制&lt;/h2&gt;
&lt;h3 id=&#34;41-模型怎么知道该停下来了&#34;&gt;4.1 模型怎么知道该停下来了？&lt;/h3&gt;
&lt;p&gt;训练数据每段文本末尾都有一个特殊 token，通常叫 &lt;code&gt;&amp;lt;eos&amp;gt;&lt;/code&gt;（End of Sequence）。模型的训练目标是预测下一个 token，所以它会自然学会：当回答完整时，输出 &lt;code&gt;&amp;lt;eos&amp;gt;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;推理时还有辅助规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;达到最大生成长度。&lt;/li&gt;
&lt;li&gt;输出 &lt;code&gt;&amp;lt;eos&amp;gt;&lt;/code&gt; 立即停止。&lt;/li&gt;
&lt;li&gt;检测到重复循环时停止。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;42-训练时怎么防止偷看未来&#34;&gt;4.2 训练时怎么防止偷看未来？&lt;/h3&gt;
&lt;p&gt;用 &lt;strong&gt;Causal Mask（因果掩码）&lt;/strong&gt;。它是一个上三角矩阵，遮住当前位置右边的 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;graph TD
    subgraph 序列
        T1[token1]
        T2[token2]
        T3[token3]
        T4[token4]
    end
    T1 --&amp;gt; T1
    T2 --&amp;gt; T1
    T2 --&amp;gt; T2
    T3 --&amp;gt; T1
    T3 --&amp;gt; T2
    T3 --&amp;gt; T3
    T4 --&amp;gt; T1
    T4 --&amp;gt; T2
    T4 --&amp;gt; T3
    T4 --&amp;gt; T4&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;箭头表示“能看到”。token3 看不到 token4，这就是自回归的核心。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;43-self-attention-到底在算什么&#34;&gt;4.3 Self-Attention 到底在算什么？&lt;/h3&gt;
&lt;p&gt;每个 token 都有三个向量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Q（Query）&lt;/strong&gt;：我想找什么信息？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;K（Key）&lt;/strong&gt;：我是什么信息？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;V（Value）&lt;/strong&gt;：我的实际内容是什么？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;计算步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Q 和 K 做点积，得到注意力分数。&lt;/li&gt;
&lt;li&gt;除以 &lt;code&gt;√d_k&lt;/code&gt;，防止数值过大导致 softmax 太尖锐。&lt;/li&gt;
&lt;li&gt;softmax 得到权重。&lt;/li&gt;
&lt;li&gt;用权重对 V 做加权求和。&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
    X[输入 X] --&amp;gt; Q[Query]
    X --&amp;gt; K[Key]
    X --&amp;gt; V[Value]
    Q --&amp;gt; DOT[Q × K^T]
    K --&amp;gt; DOT
    DOT --&amp;gt; SCALE[÷ √d]
    SCALE --&amp;gt; SOFT[softmax]
    SOFT --&amp;gt; MUL[× V]
    V --&amp;gt; MUL
    MUL --&amp;gt; OUT[输出]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么要除以 &lt;code&gt;√d_k&lt;/code&gt;？&lt;/strong&gt; 因为维度越高，点积值越容易变大，softmax 会趋向“只有一个位置是 1，其他都是 0”的极端分布，梯度变小，训练不稳定。&lt;/p&gt;
&lt;h3 id=&#34;44-为什么需要多头注意力&#34;&gt;4.4 为什么需要多头注意力？&lt;/h3&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果只用一个头，模型只能学一种注意模式，表达能力受限。&lt;/p&gt;
&lt;h3 id=&#34;45-kv-cache让生成变快的关键&#34;&gt;4.5 KV Cache：让生成变快的关键&lt;/h3&gt;
&lt;p&gt;生成文本时，模型是逐 token 生成的。如果没有 KV Cache，每生成一个新 token，都要重新计算前面所有 token 的 Attention，复杂度是 &lt;code&gt;O(L²)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;有了 KV Cache：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;已经生成过的 token 的 K 和 V 被缓存下来。&lt;/li&gt;
&lt;li&gt;每次只需要计算新 token 的 Q，再和缓存中的 K、V 做 Attention。&lt;/li&gt;
&lt;li&gt;复杂度变成 &lt;code&gt;O(L)&lt;/code&gt;。&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 TB
    subgraph 无 KV Cache
        A1[生成 token1] --&amp;gt; A2[生成 token2&amp;lt;br/&amp;gt;重算 token1]
        A2 --&amp;gt; A3[生成 token3&amp;lt;br/&amp;gt;重算 token1, token2]
    end

    subgraph 有 KV Cache
        B1[生成 token1&amp;lt;br/&amp;gt;缓存 K1,V1] --&amp;gt; B2[生成 token2&amp;lt;br/&amp;gt;只算 Q2 + 读取 K1,V1]
        B2 --&amp;gt; B3[生成 token3&amp;lt;br/&amp;gt;只算 Q3 + 读取 K1~V2]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么只缓存 K 和 V，不缓存 Q？&lt;/strong&gt; 因为 K、V 来自“已经生成的历史”，是固定的；Q 来自“当前要生成的这个新 token”，每次都要重新算。&lt;/p&gt;
&lt;h3 id=&#34;46-残差连接layernormffn-各有什么用&#34;&gt;4.6 残差连接、LayerNorm、FFN 各有什么用？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;残差连接（Residual Connection）&lt;/strong&gt;：把子层输入直接加回输出，缓解深层网络梯度消失，让训练更稳定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LayerNorm&lt;/strong&gt;：对每个样本内部做归一化，不依赖 batch 大小，适合 NLP。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RMSNorm&lt;/strong&gt;：Llama-3 使用，去掉减均值步骤，计算更快更稳定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FFN（前馈神经网络）&lt;/strong&gt;：Attention 负责“看哪里”，FFN 负责“怎么理解”。两者缺一不可。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;47-为什么大模型做数学题经常不准&#34;&gt;4.7 为什么大模型做数学题经常不准？&lt;/h3&gt;
&lt;p&gt;大模型本质是&lt;strong&gt;概率模式匹配器&lt;/strong&gt;，不是计算器：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;优化目标是“下一个 token 看起来合理”，不是“答案精确”。&lt;/li&gt;
&lt;li&gt;训练数据里的数学推导质量参差不齐。&lt;/li&gt;
&lt;li&gt;多步推理会累积误差。&lt;/li&gt;
&lt;li&gt;没有内建算术引擎。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;改善方法：提示工程、CoT（Chain-of-Thought）链式推理、调用外部计算器工具。但无法根治。&lt;/p&gt;
&lt;h3 id=&#34;48-扩展上下文长度会带来的问题&#34;&gt;4.8 扩展上下文长度会带来的问题&lt;/h3&gt;
&lt;p&gt;把 8K 模型扩展到 32K，KV Cache 大小会变成 4 倍。同时 Attention 计算量和内存带宽需求也同步增加。&lt;/p&gt;
&lt;p&gt;常用做法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;位置编码外推&lt;/strong&gt;：RoPE 可以通过插值扩展范围。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;继续训练&lt;/strong&gt;：在长文本上继续训练一段时间，让模型适应新的长度分布。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;打包训练 + Attention Mask&lt;/strong&gt;：把多个短样本拼成一条长序列，用块对角掩码阻止它们互相看到。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;49-flash-attention-为什么能加速&#34;&gt;4.9 Flash Attention 为什么能加速？&lt;/h3&gt;
&lt;p&gt;Flash Attention 没有减少总计算量，但大幅减少了对 HBM（GPU 显存）的访问。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把 Attention 拆成小块，在片上 SRAM 完成计算。&lt;/li&gt;
&lt;li&gt;融合多个 kernel，减少数据搬运。&lt;/li&gt;
&lt;li&gt;用 online softmax 增量维护最大值和归一化因子。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;410-rope-比绝对位置编码强在哪&#34;&gt;4.10 RoPE 比绝对位置编码强在哪？&lt;/h3&gt;
&lt;p&gt;原始 Transformer 把位置编码加到 Embedding 上，是&lt;strong&gt;加法&lt;/strong&gt;的。RoPE（旋转位置编码）通过旋转 Q、K 向量把位置信息&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;p&gt;挑战：超长上下文下，旋转角度增长过快，可能出现周期折叠和数值精度问题。&lt;/p&gt;
&lt;h3 id=&#34;411-推测解码用小模型加速大模型&#34;&gt;4.11 推测解码：用小模型加速大模型&lt;/h3&gt;
&lt;p&gt;思路：让小模型快速猜一串 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;sequenceDiagram
    participant User
    participant Small as 小模型
    participant Large as 大模型

    User-&amp;gt;&amp;gt;Small: 请生成候选 token
    Small-&amp;gt;&amp;gt;Large: 提交候选序列
    Large-&amp;gt;&amp;gt;Large: 一次性验证多个 token
    alt 全部正确
        Large--&amp;gt;&amp;gt;User: 直接返回候选结果
    else 第 k 个错误
        Large--&amp;gt;&amp;gt;User: 前 k-1 个接受，从 k 开始重新生成
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;推测解码没有减少总计算量，但减少了“慢的大模型”的运行次数，从而降低延迟。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五预训练--微调两步范式&#34;&gt;五、预训练 + 微调：两步范式&lt;/h2&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
    PT[预训练&amp;lt;br/&amp;gt;海量无标注文本] --&amp;gt;|获得通用能力| FT[微调&amp;lt;br/&amp;gt;指令/人类偏好数据]
    FT --&amp;gt;|对齐人类价值观| Model[可用模型]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;51-预训练让模型获得什么&#34;&gt;5.1 预训练让模型获得什么？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;语言理解与生成能力。&lt;/li&gt;
&lt;li&gt;世界知识和常识。&lt;/li&gt;
&lt;li&gt;基本的推理和归纳能力。&lt;/li&gt;
&lt;li&gt;跨任务泛化能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;52-微调做什么&#34;&gt;5.2 微调做什么？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;指令遵循&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;：减少有害、偏见、违法内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这也是 Llama-3 8B 能比 Llama-1 70B 更强的关键原因之一：更好的数据、更优的训练方法、更系统的微调和对齐。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六文本分类embedding-还是生成&#34;&gt;六、文本分类：Embedding 还是生成？&lt;/h2&gt;
&lt;h3 id=&#34;61-embedding--分类头&#34;&gt;6.1 Embedding + 分类头&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 class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    T[文本] --&amp;gt; M[Embedding 模型]
    M --&amp;gt; V[向量]
    V --&amp;gt; C[分类头&amp;lt;br/&amp;gt;Linear/MLP]
    C --&amp;gt; L[标签]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;优点：推理快、成本低、类别可以很多、精度通常稳定。&lt;/p&gt;
&lt;h3 id=&#34;62-生成模型直接分类&#34;&gt;6.2 生成模型直接分类&lt;/h3&gt;
&lt;p&gt;把分类任务写成 prompt，让模型直接输出类别文本。例如：&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;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;你是情感分析专家。请判断下面电影评论是 positive 还是 negative，只返回标签：
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;评论：这部电影太精彩了！&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;优点：零样本、少样本能力强，加新类别不用重新训练。
缺点：推理慢、对 prompt 敏感、类别多时容易出错。&lt;/p&gt;
&lt;h3 id=&#34;63-没有标注数据怎么办&#34;&gt;6.3 没有标注数据怎么办？&lt;/h3&gt;
&lt;p&gt;可以把分类变成&lt;strong&gt;文本相似度检索&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;给每个类别写一段自然语言描述。&lt;/li&gt;
&lt;li&gt;用 Embedding 模型把描述和待分类文本都变成向量。&lt;/li&gt;
&lt;li&gt;计算余弦相似度，选最相似的类别。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;标签描述的技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用具体场景描述，而不是抽象词。&lt;/li&gt;
&lt;li&gt;写成完整短句。&lt;/li&gt;
&lt;li&gt;包含领域关键词。&lt;/li&gt;
&lt;li&gt;长度适中（10-20 字左右）。&lt;/li&gt;
&lt;li&gt;类别之间要有区分度。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;64-transformer-为什么比朴素贝叶斯强&#34;&gt;6.4 Transformer 为什么比朴素贝叶斯强？&lt;/h3&gt;
&lt;p&gt;朴素贝叶斯假设：给定类别后，每个词都是条件独立的。这忽略了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;词语之间的相关性（如“银行”和“贷款”）。&lt;/li&gt;
&lt;li&gt;语序信息（“这部电影不好看” vs “这部电影好看”）。&lt;/li&gt;
&lt;li&gt;否定词、修饰语的语义反转。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Transformer 通过自注意力建模上下文关系，没有强独立性假设，因此表现更好。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七文本聚类与主题建模&#34;&gt;七、文本聚类与主题建模&lt;/h2&gt;
&lt;h3 id=&#34;71-为什么有了生成式大模型还需要-embedding-模型&#34;&gt;7.1 为什么有了生成式大模型，还需要 Embedding 模型？&lt;/h3&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;推荐系统&lt;/strong&gt;就是典型例子：先把商品/用户变成向量，再用向量数据库做近邻搜索，效率高、成本低。&lt;/p&gt;
&lt;h3 id=&#34;72-从文档到主题的流程&#34;&gt;7.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
    Docs[大量文档] --&amp;gt; Prep[预处理]
    Prep --&amp;gt; Vec[向量化&amp;lt;br/&amp;gt;TF-IDF 或 Embedding]
    Vec --&amp;gt; Cluster[聚类&amp;lt;br/&amp;gt;KMeans / HDBSCAN]
    Cluster --&amp;gt; Topic[主题提取&amp;lt;br/&amp;gt;TF-IDF / c-TF-IDF / LLM]
    Topic --&amp;gt; Label[人工命名/标签]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;73-词袋法-vs-文档嵌入&#34;&gt;7.3 词袋法 vs 文档嵌入&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;词袋法 / TF-IDF&lt;/th&gt;
					&lt;th&gt;文档嵌入（BERT/SBERT）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;表示&lt;/td&gt;
					&lt;td&gt;稀疏向量&lt;/td&gt;
					&lt;td&gt;稠密向量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;上下文&lt;/td&gt;
					&lt;td&gt;不考虑&lt;/td&gt;
					&lt;td&gt;考虑&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;一词多义&lt;/td&gt;
					&lt;td&gt;不能处理&lt;/td&gt;
					&lt;td&gt;能处理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;资源&lt;/td&gt;
					&lt;td&gt;快速轻量&lt;/td&gt;
					&lt;td&gt;需要模型和算力&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;可解释性&lt;/td&gt;
					&lt;td&gt;强&lt;/td&gt;
					&lt;td&gt;弱&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;词袋法在很多简单任务上仍是有效的基线，别急着上深度学习。&lt;/p&gt;
&lt;h3 id=&#34;74-c-tf-idf-改进在哪&#34;&gt;7.4 c-TF-IDF 改进在哪？&lt;/h3&gt;
&lt;p&gt;BERTopic 里的 c-TF-IDF 把统计单位从“文档”改成“主题（簇）”。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TF&lt;/strong&gt;：某个词在主题内所有文档合并后的频率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IDF&lt;/strong&gt;：&lt;code&gt;log(K / df)&lt;/code&gt;，K 是主题总数，df 是包含该词的主题数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样提取出来的关键词更能代表整个主题的共性，而不是单篇文档的特例。&lt;/p&gt;
&lt;h3 id=&#34;75-聚类算法怎么选&#34;&gt;7.5 聚类算法怎么选？&lt;/h3&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;th&gt;适合&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;K-Means&lt;/td&gt;
					&lt;td&gt;快、可扩展&lt;/td&gt;
					&lt;td&gt;需指定 K、对噪声敏感、只能找球形簇&lt;/td&gt;
					&lt;td&gt;大规模、簇形状规则&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DBSCAN/HDBSCAN&lt;/td&gt;
					&lt;td&gt;自动识别噪声、任意形状&lt;/td&gt;
					&lt;td&gt;高维稀疏空间效果差、HDBSCAN 较慢&lt;/td&gt;
					&lt;td&gt;中小规模、噪声多&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;76-为什么把聚类和主题表示分开更好&#34;&gt;7.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;解释性&lt;/strong&gt;：先聚类再从每簇提关键词，比联合模型更直观。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;降噪&lt;/strong&gt;：聚类只关心语义相似度，主题提取专注于代表性关键词。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;77-主题关键词重叠怎么办&#34;&gt;7.7 主题关键词重叠怎么办？&lt;/h3&gt;
&lt;p&gt;可以尝试：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用 c-TF-IDF 提升每个主题的代表词独特性。&lt;/li&gt;
&lt;li&gt;去掉停用词和高频无意义词。&lt;/li&gt;
&lt;li&gt;合并过细的小簇后重新提取关键词。&lt;/li&gt;
&lt;li&gt;用 MMR（Maximal Marginal Relevance）兼顾相关性和多样性。&lt;/li&gt;
&lt;li&gt;换更好的语义嵌入模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;78-bertopic-离群点太多怎么办&#34;&gt;7.8 BERTopic 离群点太多怎么办？&lt;/h3&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;code&gt;min_cluster_size&lt;/code&gt; 设置过大。&lt;/li&gt;
&lt;li&gt;语料本身主题分散。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;调整方法：减小 &lt;code&gt;min_cluster_size&lt;/code&gt;、换 &lt;code&gt;cluster_selection_method=&#39;leaf&#39;&lt;/code&gt;、使用更适合短文本的嵌入模型（如 SimCSE、MiniLM）。&lt;/p&gt;
&lt;h3 id=&#34;79-检测新兴主题&#34;&gt;7.9 检测新兴主题&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;滑动窗口 + 动态聚类&lt;/strong&gt;：按时间切分数据，追踪主题演化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;频率突变监测&lt;/strong&gt;：统计词频增长率，发现突然火起来的词。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embedding 演化分析&lt;/strong&gt;：新聚类中心远离旧中心，说明出现新主题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;710-推荐系统冷启动怎么做&#34;&gt;7.10 推荐系统冷启动怎么做？&lt;/h3&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;/td&gt;
					&lt;td&gt;内容理解&lt;/td&gt;
					&lt;td&gt;TF-IDF + KMeans / BERTopic&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;初始推荐&lt;/td&gt;
					&lt;td&gt;主题/相似内容&lt;/td&gt;
					&lt;td&gt;用户兴趣引导 + 主题中心匹配&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;有行为数据&lt;/td&gt;
					&lt;td&gt;协同过滤 + 内容&lt;/td&gt;
					&lt;td&gt;ItemCF / UserCF + 向量相似度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据丰富&lt;/td&gt;
					&lt;td&gt;CTR 预估&lt;/td&gt;
					&lt;td&gt;FM / DNN / DSSM&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八写在最后&#34;&gt;八、写在最后&lt;/h2&gt;
&lt;p&gt;这篇笔记覆盖了《生成式AI原理与实战 —— Part 1》的 5 个章节。对初级开发者来说，最重要的不是记住每个公式，而是建立下面几个直觉：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;大模型 = 分词 + 向量 + Transformer + 生成概率&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transformer 的核心是 Attention：看哪里（QK）和拿什么信息（V）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成模型靠自回归逐 token 预测，每次只能看过去，靠 KV Cache 加速&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预训练给通识，微调给方向，对齐给安全&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embedding 模型在检索、推荐、聚类场景仍然不可替代&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果你能把这些讲给一位没做过 AI 的后端同事听明白，说明这篇文章的目的就达到了。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;参考资料：《生成式AI原理与实战 —— Part 1》&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    <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>
