<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>大模型训练 on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E8%AE%AD%E7%BB%83/</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/tags/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E8%AE%AD%E7%BB%83/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>
    
  </channel>
</rss>
