机器学习:从数据里把规律「试」出来
模型不是被人写死规则的。它只是一堆可以调整的数字,靠着「猜错了就往回改一点」这个循环,慢慢逼近数据里的规律。
亲手训练一条直线
拖动滑块手动调,或者点「训练一步」让梯度下降自己调。右边的误差曲面会告诉你现在离谷底有多远。
上面的可视化用的学习率 η = 0.02。真实的大模型把参数从 2 个换成几千亿个,这个循环本身一模一样。
数学页有推导:C1 导数与梯度
一条直线切开不了弯的世界。
神经网络:一条直线不够,就把它们叠起来
上一章那条直线只能切开线性可分的数据。真实世界的规律是弯的。解决办法很朴素:把很多「线性变换 + 一次弯折」串起来,堆到足够深,就能拟合任意复杂的边界。
看它学会分开两团点
这是一个真正在你浏览器里跑的小神经网络。背景色是它当前认为的分类边界,随着训练实时变化。
把神经元调到 1 个再训练,你会看到它退化成一条直线,怎么也切不开同心圆。
上面这个网络是 2 → H → 1 结构,隐藏层 tanh,输出层 sigmoid,损失是二元交叉熵,优化器是最朴素的 SGD。
网络只认数字。下一步:把字变成坐标。
文字变数字:分词与词向量
神经网络只吃数字。所以第一步是把一句话切成小块(token),每块查表换成一串数字(向量)。这串数字不是随便编的,它在训练中被调整成能表达语义的坐标。
分词器在怎么切你的句子
随便改改输入框。注意生僻词和英文单词会被切成更碎的片段,常见词则整块保留。
词向量:语义变成了坐标
把高维词向量压到二维。意思相近的词自然聚在一起。点任意一个词看它的近邻。
RoPE 的妙处在于旋转后的内积只依赖相对距离 m-n,而不是绝对位置,所以模型能外推到训练时没见过的更长序列。实际嵌入维度 d 通常是 768(BERT-base)到 12288(GPT-3)。
数学页有演示:A1 向量与内积
词有了坐标,但还互相看不见。
注意力机制:整个模型的心脏
读到「它饿了」的「它」,你会自动回头看前面的「小猫」。注意力机制就是把这个动作变成了矩阵乘法:让每个词去问所有词「你跟我有多相关」,然后按相关度把信息汇总过来。
注意力矩阵:把鼠标放到任意一格上
行是「谁在提问」,列是「在看谁」。格子越亮,注意力权重越大。切换不同的头,会看到它们学到了完全不同的关注模式。
一步一步走完注意力的计算
点击每一步,看数据的形状怎么变化。
除以 √d_k 是因为若 q、k 各分量独立且方差为 1,点积的方差就是 d_k,不缩放会把 softmax 推到饱和区、梯度趋近于 0。复杂度是 O(n²·d):序列长度翻倍,计算量变四倍,这正是长上下文昂贵的根本原因。
数学页有演示:A1 内积 · P3 Softmax
注意力是一块砖。下面把它砌进整栋楼。
完整架构:一个 token 的立体旅程
下面是一个真正的三维模型。每一块代表一个张量,宽度对应特征维度,纵深对应序列长度。拖动旋转,滚轮缩放,点任意一块看它在做什么。
从 token id 到下一个词的概率
点「送一个 token 进去」会自下而上依次点亮每个环节,右侧同步显示该步的张量形状和数学定义。
楼盖好了。怎么从一堆分数里写出一个字?
它到底是怎么写出下一个字的
模型最后吐出的不是一个字,而是词表里每个字的分数。怎么从这堆分数里挑一个,决定了输出是死板还是有灵气。
调三个旋钮,看候选词的概率怎么变
输入是「今天天气真」,下面是模型给出的候选。灰掉的表示被采样策略排除了。
T → 0 时分布退化成 argmax(贪心),T → ∞ 时退化成均匀分布。Top-K 是硬截断,Top-P 是动态截断:候选集大小随分布尖锐程度自适应,所以实践中通常用 T 配合 Top-P。
数学页有演示:P3 Softmax · P1 概率基础
会写一个词,不等于会说话。
预训练:模型是怎么「学会说话」的
上一章让模型能写出一个词,但它还没「见过世面」。真正让它懂语言、懂常识、会推理的,是预训练——在海量文本上反复做一件最简单的事:预测下一个词。这件单调的事重复几万亿次,语言能力就涌现出来了。
看着它「学会」预测下一个词
这是同一个训练循环的缩小版——从预测越来越准。拖「训练步数」滑块、或点「自动训练」,看左边的预测概率分布越来越自信、右边 loss 曲线一路下滑。
数学页有推导:P4 最大似然 · P5 交叉熵与 KL
它已经懂语言了。现在把它改成专才。
微调:把通用模型改造成专才
预训练模型什么都懂一点,但不一定懂你的业务。微调就是拿你的数据继续训练它。问题是全量微调要更新几百亿参数,显存扛不住。LoRA 用一个很巧的办法绕开了。
LoRA:用两个瘦矩阵代替一个胖矩阵
原权重 W 冻结不动,只训练旁边那两个小矩阵 A 和 B。拖动秩 r,看可训练参数量的变化。
A 用高斯初始化、B 初始化为全 0,训练开始时 BA = 0,模型行为与原模型完全一致。缩放因子 α/r 让你改变 r 时不必重调学习率。推理时可把 BA 合并回 W,零额外延迟。核心假设是 ΔW 的本征秩很低,信息集中在少数方向上。
为什么低秩够用:A4 SVD 奇异值分解
什么时候用微调
- 需要固定的输出格式或语气
- 领域术语密集,提示词教不会
- 想把长提示词的成本固化进模型
什么时候用 RAG 就够了
- 知识需要经常更新
- 要求答案可溯源到原文
- 数据量小,不足以训练
会写,不等于写得合人心意。
强化学习:从策略梯度到 DPO 的完整推导
预训练让模型学会说话,但没教它什么该说。「这个回答好不好」写不成可导的损失函数,于是要绕一条路:把人类偏好变成奖励,再用策略梯度去优化。这一章把每一步都推出来。
RLHF 三段式流程
点击每个阶段查看它的输入输出。第二阶段可以亲手标一次偏好数据。
9.1 符号约定
| 符号 | 名称 | 含义 |
|---|---|---|
| $\pi_\theta$ | 策略 | 参数为 θ 的语言模型,给定提示 x 输出回答 y 的条件分布 $\pi_\theta(y\mid x)$ |
| $\pi_{\text{ref}}$ | 参考策略 | SFT 之后冻结的那份模型,用来拴住优化不跑偏 |
| $\tau$ | 轨迹 | 一条完整的生成序列 $(x, y_1, y_2, \dots, y_T)$ |
| $r(x,y)$ | 奖励 | 奖励模型给整条回答打的标量分数 |
| $V(s)$ | 状态价值 | 从状态 s 出发,未来期望能拿到的总回报 |
| $A(s,a)$ | 优势 | $Q(s,a)-V(s)$,这个动作比平均水平好多少 |
| $\gamma$ | 折扣因子 | 未来奖励的衰减率,$\gamma\in[0,1]$ |
| $\beta$ | KL 系数 | 控制允许偏离参考策略多远 |
9.2 目标函数与策略梯度定理
强化学习要最大化的是期望回报。难点在于:期望是对策略自己产生的轨迹分布求的,而这个分布本身依赖 θ,不能直接换序求导。
写出目标
目标是让策略生成的回答期望奖励最高:
$$J(\theta)=\mathbb{E}_{\tau\sim\pi_\theta}\big[R(\tau)\big]=\int \pi_\theta(\tau)\,R(\tau)\,d\tau$$对参数求导,把梯度移进积分
R(τ) 不含 θ,所以只对概率密度求导:
$$\nabla_\theta J(\theta)=\int \nabla_\theta \pi_\theta(\tau)\,R(\tau)\,d\tau$$对数导数技巧
这是整个推导的关键一步。利用恒等式 $\nabla_\theta \pi = \pi\,\nabla_\theta\log\pi$,把梯度重新变回一个可采样的期望:
$$\nabla_\theta \pi_\theta(\tau)=\pi_\theta(\tau)\,\nabla_\theta\log\pi_\theta(\tau)$$ $$\nabla_\theta J(\theta)=\mathbb{E}_{\tau\sim\pi_\theta}\big[\nabla_\theta\log\pi_\theta(\tau)\cdot R(\tau)\big]$$展开轨迹概率,环境项消失
轨迹概率是初始分布、策略、转移概率的连乘。取对数变成求和后,只有策略项含 θ,环境动态被消掉了 —— 这就是为什么策略梯度不需要知道环境模型:
$$\log\pi_\theta(\tau)=\log p(s_0)+\sum_{t}\Big[\log\pi_\theta(a_t\mid s_t)+\log p(s_{t+1}\mid s_t,a_t)\Big]$$ $$\nabla_\theta\log\pi_\theta(\tau)=\sum_{t}\nabla_\theta\log\pi_\theta(a_t\mid s_t)$$REINFORCE
合起来得到最基础的策略梯度估计量:
$$\nabla_\theta J=\mathbb{E}\left[\sum_{t=0}^{T}\nabla_\theta\log\pi_\theta(a_t\mid s_t)\,G_t\right], \qquad G_t=\sum_{k=t}^{T}\gamma^{k-t}r_k$$直观理解:如果一条轨迹回报高,就提高它上面每个动作的对数概率;回报低就压低。
减基线降方差
REINFORCE 方差极大。减去一个只依赖状态、不依赖动作的基线 b(s),期望不变但方差显著下降:
$$\mathbb{E}\big[\nabla_\theta\log\pi_\theta(a\mid s)\,b(s)\big] = b(s)\,\nabla_\theta\!\!\sum_a \pi_\theta(a\mid s)=b(s)\,\nabla_\theta 1=0$$取 $b(s)=V(s)$ 就得到优势函数,这就是 Actor-Critic 的由来:
$$A(s,a)=Q(s,a)-V(s)$$9.3 奖励模型:Bradley-Terry
人类没法给回答打绝对分,但能比较两个回答哪个更好。Bradley-Terry 模型假设「A 胜过 B」的概率由两者潜在分数之差的 sigmoid 决定。
注意奖励只由差值决定,所以 r 有一个全局平移的自由度,实践中通常再加一项把奖励均值归零。$y_w$ 是被选中的回答(winner),$y_l$ 是被淘汰的(loser)。
9.4 PPO:为什么要裁剪
直接用策略梯度更新一大步会让策略崩掉。TRPO 用信赖域约束解决,但要算二阶量。PPO 用一个更粗暴但极其有效的办法:把重要性采样比例硬裁剪在 1 附近。
重要性采样比例
用旧策略采的数据更新新策略,需要做重要性修正:
$$\rho_t(\theta)=\frac{\pi_\theta(a_t\mid s_t)}{\pi_{\theta_{\text{old}}}(a_t\mid s_t)}$$裁剪目标
取裁剪前后的较小值,构成一个悲观下界。当优势为正时,比例涨到 1+ε 就不再给奖励;优势为负时,跌到 1-ε 就不再加惩罚:
$$L^{\text{CLIP}}(\theta)=\mathbb{E}_t\Big[\min\big(\rho_t A_t,\ \ \text{clip}(\rho_t,\,1-\epsilon,\,1+\epsilon)\,A_t\big)\Big]$$典型取 ε = 0.2。
加上 KL 惩罚
在 RLHF 里还要防止模型为了刷奖励而胡言乱语(reward hacking),所以在奖励里直接减去与参考模型的 KL 散度:
$$\max_\theta\ \mathbb{E}_{x\sim\mathcal{D},\,y\sim\pi_\theta} \Big[r_\phi(x,y)\Big]-\beta\,\mathbb{D}_{\text{KL}}\big[\pi_\theta(y\mid x)\,\Vert\,\pi_{\text{ref}}(y\mid x)\big]$$GAE 优势估计
优势用广义优势估计在偏差和方差之间取平衡:
$$\hat A_t^{\text{GAE}}=\sum_{l=0}^{\infty}(\gamma\lambda)^l\,\delta_{t+l}, \qquad \delta_t=r_t+\gamma V(s_{t+1})-V(s_t)$$λ = 0 退化成单步 TD(低方差高偏差),λ = 1 退化成蒙特卡洛(高方差无偏)。
9.5 DPO:把强化学习消掉
DPO 的洞见是:上面那个 KL 约束的最大化问题存在闭式最优解,把它反解出来代回偏好似然,强化学习那一整套就消失了,只剩一个普通的有监督损失。
KL 约束优化的闭式解
目标 $\max_\pi \mathbb{E}[r] - \beta\mathbb{D}_{\text{KL}}[\pi\Vert\pi_{\text{ref}}]$ 是一个带熵正则的线性泛函,其最优解是玻尔兹曼分布形式:
$$\pi^{*}(y\mid x)=\frac{1}{Z(x)}\,\pi_{\text{ref}}(y\mid x)\,\exp\!\Big(\tfrac{1}{\beta}r(x,y)\Big)$$ $$Z(x)=\sum_{y}\pi_{\text{ref}}(y\mid x)\exp\!\Big(\tfrac{1}{\beta}r(x,y)\Big)$$反解出奖励
把上式两边取对数整理,奖励可以用策略本身表达出来:
$$r(x,y)=\beta\log\frac{\pi^{*}(y\mid x)}{\pi_{\text{ref}}(y\mid x)}+\beta\log Z(x)$$配分函数被消掉
关键:Bradley-Terry 只关心奖励之差,而 $\beta\log Z(x)$ 对同一个 x 下的所有 y 都相同,相减时直接抵消。这就绕开了配分函数不可计算的难题:
$$r(x,y_w)-r(x,y_l)=\beta\log\frac{\pi_\theta(y_w\mid x)}{\pi_{\text{ref}}(y_w\mid x)} -\beta\log\frac{\pi_\theta(y_l\mid x)}{\pi_{\text{ref}}(y_l\mid x)}$$DPO 损失
代回偏好似然,得到一个可以直接用梯度下降优化的监督损失:
$$\mathcal{L}_{\text{DPO}}=-\,\mathbb{E}_{(x,y_w,y_l)}\left[\log\sigma\!\left( \beta\log\frac{\pi_\theta(y_w\mid x)}{\pi_{\text{ref}}(y_w\mid x)}- \beta\log\frac{\pi_\theta(y_l\mid x)}{\pi_{\text{ref}}(y_l\mid x)}\right)\right]$$不需要奖励模型,不需要采样,不需要价值网络。只要一份偏好数据和两份模型权重。
梯度的直观含义
对 θ 求导后可以看出它在做什么:
$$\nabla_\theta\mathcal{L}_{\text{DPO}}=-\beta\,\mathbb{E}\Big[ \underbrace{\sigma(\hat r_l-\hat r_w)}_{\text{估错得越离谱权重越大}} \big(\nabla_\theta\log\pi_\theta(y_w)-\nabla_\theta\log\pi_\theta(y_l)\big)\Big]$$提高好回答的概率,压低坏回答的概率,而且当前模型判断错得越厉害,这一对样本的权重越大。
PPO
需要奖励模型 + 在线采样 + 价值网络。显存四份权重,超参敏感,但上限高、可持续在线改进。
DPO
离线、稳定、实现简单。受限于偏好数据的覆盖范围,无法探索数据分布之外的更优回答。
GRPO
去掉价值网络,用同一提示下一组样本的组内均值当基线。DeepSeek 系列在用,显存开销介于两者之间。
单次问答办不了复杂的事。
LangChain 与 LangGraph:让模型学会办事
一次问答解决不了复杂任务。需要模型能查资料、调工具、判断结果好不好、不行就重来。LangChain 把这些步骤串成链,LangGraph 则把它升级成了可以有循环和分支的图。
链 vs 图:点「运行」看执行路径
左边是固定顺序的链,走完就结束。右边是带条件边的图,可以判断、回头、重试。
{
"question": "",
"docs": [],
"answer": "",
"attempts": 0
}
用链就够
- 步骤固定,比如「检索然后总结」
- 不需要重试或分支
- 调试成本敏感
需要图
- 要调工具并根据结果决定下一步
- 需要自我检查和重试
- 多个 Agent 协作
- 需要中途暂停等人审批
回头看一遍,从头到尾只有一条线。
回头看:一个 token 的一以贯之
把前面各章连起来看,其实从头到尾只有一件事:一个词进来,被拆成数字,在层层张量里不断变换和汇聚,最后变成一个概率分布。点「重走一遍」让这条线在你眼前完整地流一遍。
重走一个 token 的全程
每一站对应前面某一章。粒子沿着管线流动,右侧同步显示这一步在做什么、以及它的数学表达。
点「重走一遍」开始。每一步都是前面某一章里见过的那块砖。
三个能带走的心智模型
- 一次只做一件事。每个 token 每层只更新自己的向量,自注意力让它「看见上下文」,前馈网络让它「想清楚」。单论一步,数学都很朴素。
- 上下文是注意力算出来的。「I」在句子里指谁,不是写死的,是模型用点积算权重、加权所有词得到的——所以换一句语境,同样的词指的对象会变。
- 所有能力都是「猜对的概率」。预训练学的是「下一个词是什么最合理」,微调对齐的是「人更希望它说什么」。从头到尾只有这一个机制。
拿这张图去解释给别人
- 想一句话讲清 Transformer:「把一句话变成一堆向量,让每个词看看别人、自己想一想,重复几十层,最后输出下一个词最可能是哪个。」
- 想讲清为什么能堆 96 层:因为每一层的输入输出形状都一样,样板无限复制。
- 想讲清 Agent:就是在主干外面套了「工具调用 + 判断重试」的循环,核心还是那条线。