01 / 三种方法究竟学了什么
从 Q(s,a) 转到 π(a|s)
| 方法 | 训练对象 | 行动时 | 本课程位置 |
|---|---|---|---|
| 表格 Q-learning | 每个状态—动作的 Q 表 | 查表,再选最大 Q 或 ε 探索 | 第十五节 |
| DQN | 神经网络 Qθ(s,a) | 网络给出所有动作 Q,再选动作 | 第十六节 |
| 策略梯度 | 策略 πθ(a|s) | 网络直接给出动作概率并采样 | 本节 |
仍使用同一张小网格,并保留第十六节的 10% 动作随机重抽:S 向右到 C 可立即得 +2;向下经过 A、B、D 到 G 才得 +10。策略网络输入当前状态 one-hot (6,),输出四个 logits (4,),softmax 后是右、下、上、左的概率。
6 个数→策略网络
4 个 logits→softmax
四个概率和为 1→采样动作 a
与环境互动
输入所在位置
训练后实际动作概率
训练时按这些概率采样,较小概率的动作仍可能被试到;“选最大概率动作”是另外一种确定性评估方式。概率高不代表环境一定照做,因为动作随机重抽独立存在。
02 / 不必对环境求导
给好结果的动作增加概率
设一条轨迹是 s₀,a₀,r₀,s₁,a₁,r₁,…,从时刻 t 往后的折扣回报是 Gₜ=rₜ+γrₜ₊₁+…。目标是提高从起点算的期望折扣回报。对轨迹概率使用 ∇p=p∇log p,再利用“t 时刻的动作不影响之前的奖励”,得到下面的得分函数估计:
这里 γᵗ 是从起点到 t 的折扣,Gₜ 是从 t 往后的回报;两者不能随意混成一个因子。环境的转移和奖励不需要可微,梯度只穿过策略网络算出的 log π。
真实训练轨迹:末尾奖励怎样传回起点
trajectory = collect(policy, environment_seed) # 当前策略采样的一整回合
for t, (state, log_prob, G_t) in enumerate(trajectory):
loss_terms.append(-gamma**t * log_prob * G_t)
loss = sum(loss_terms) / 8
loss.backward()
optimizer.step()代码里一次更新汇总 8 条新轨迹;这段是未加基线的核心表达式,完整实现还包含梯度裁剪和可选基线。
03 / 数学上不改方向,采样时能改波动
从 Gₜ 减去一个与当前动作无关的基线
把 Gₜ 换成 Gₜ − b(sₜ)。因为固定状态下 Σₐ π(a|s)∇logπ(a|s)=Σₐ∇π(a|s)=0,一个不依赖当前动作的 b(s) 不改变期望策略梯度。它改变每条采样轨迹的更新大小与正负,因此可能降低方差;基线选得不合适也可能让方差变大。
先看一个与网格训练分开的单次双路线例子:选 G 的概率为 p,拿 10;选 C 的概率为 1−p,拿 2。设 p=σ(z),直接微分得 dJ/dz=8p(1−p)。调节 p 和 b,观察两个采样梯度的值、它们的加权平均和方差。
两种样本的梯度
加权平均与方差
实际代码里 b(s) 是上一批以前的同状态回报移动平均。当前批次先用旧 b 计算损失,再更新 b 给下一批使用;它不是会求导的价值网络。Actor-Critic 则常用一个单独训练的价值网络作基线。
04 / 同一环境的六次实际训练
看多种子结果,不只看一条曲线
基础 REINFORCE 与加状态基线各用 3 个训练种子,各训练 1200 回合,每 8 回合更新一次。检查点用同一组 60 个环境种子、按策略概率采样评估;最终另外用 150 回合,分别按概率采样和选最大概率动作评估。随机策略用 300 回合。
三个训练种子的采样策略评估均值
只在标记的回合数评估;点之间的线仅辅助阅读。每个点基于 60 个评估回合,训练期的平均回报包含策略探索。
当前检查点
最终评估
“采样评估”保留策略本身的概率;“贪心评估”总选最大概率动作。两者都关闭训练过程中的参数更新,但环境的 10% 动作随机重抽仍存在。这里的基线是减小梯度采样波动的手段,不保证每次训练表现更好。仅凭三个种子也不能判断普遍优势。
05 / REINFORCE 的后续思路
Actor-Critic 估价值;PPO 约束更新幅度
Actor-Critic 的分工
π(a|s)→采样动作
V(s)→估优势
Actor 决定动作概率;Critic 学习状态价值,帮助估计优势。常见一步 TD 优势近似是 r+γV(s′)−V(s);它可以更早更新,但会引入价值估计误差。本节代码训练的是 REINFORCE,没有实现 Actor-Critic。
PPO 剪裁的直觉
用旧策略收集数据后,比较新旧策略对同一动作的概率比 ρ=π新(a|s)/π旧(a|s)。裁剪目标会在“朝着有利方向变化得太多”时停止继续奖励这种变化。
06 / 把生成看成一串动作
语言模型输出下一个 Token,也是在执行策略
给定提示词和已经生成的前缀,语言模型给出下一 Token 的概率分布。可以把“已有上下文”当状态信息,把采样的 Token 当动作;生成结束后才得到的偏好评分会影响整段生成的更新。下面只是概念序列,字块不代表真实 tokenizer 的切分。
提示词:“请用一句话说明张量。”
这里的“状态”是否充分取决于可见上下文;真实模型的上下文长度有限。一个较高的模型评分也不等于回答事实正确。
07 / 同一份偏好数据,两条训练路线
典型 RLHF 与 DPO 的位置
以下是教学中的典型流程,不是所有语言模型训练都必须按此顺序执行。先有预训练模型,再用示范回答做监督微调(SFT)。之后让人比较同一提示下的两个回答,例如偏好 A 胜过 B。
人选更好者
RLHF:先学奖励,再做 RL
估评分→采样新回答→优化策略
例:PPO
奖励模型把偏好转为训练信号;策略模型生成回答并接受这个信号。常加参考模型约束,减少策略偏离原有模型过多。最后仍要用独立人工或任务评估检查结果。
DPO:直接用偏好对更新策略
比较相对概率→偏好损失
直接优化
原始 DPO 方法无需单独训练显式奖励模型,也不需要在其偏好优化步骤中在线采样回答再跑 RL 循环。它依赖偏好数据和参考策略;这不表示它没有目标函数、没有参考模型,或能免除偏好数据质量问题。
| 要问的问题 | 典型 RLHF(奖励模型 + PPO) | 原始 DPO |
|---|---|---|
| 偏好数据用在哪? | 训练显式奖励模型 | 直接构造策略偏好损失 |
| 该训练阶段需要在线采样新回答吗? | 策略优化时通常需要 | 偏好优化阶段不需要 |
| 需要单独的显式奖励模型吗? | 需要 | 不需要 |
| 输出的是什么? | 改进后的语言模型策略 | 改进后的语言模型策略 |
08 / 学会质疑优化目标
高代理评分不一定是真正的好回答
假设评估器喜欢“看起来很详细”。下面的分数完全是虚构的教学数字:回答 A 简短且正确,人类质量 9;回答 B 冗长但有事实错误,人类质量 2。调整代理评分对篇幅的权重,看它什么时候错误地更偏好 B。
真实奖励模型可能误读事实、格式或提示意图;策略会倾向于利用评分器的缺陷。最终要用与训练奖励不同的证据检查正确性、帮助程度与失败案例。
09 / 实现、比较、画流程
动手练习与自测
配套代码:lesson-17-policy-gradient.py。在项目根目录运行 uv run python lessons/lesson-17-policy-gradient.py;它使用项目已有的 CPU PyTorch 和本地网格,不下载语言模型或数据。运行结果保存到 lessons/lesson-17-output/results.json。
- 在代码中找到
Categorical(logits=...)、log_prob、倒序计算 Gₜ 的函数和最终 loss。手算奖励[0,0,0,10]、γ=0.8 时每个 Gₜ。 - 解释为什么式子里同时出现
γᵗ和Gₜ。把状态基线开关前后的三种子结果并排记录,别把一组实验当作通用定律。 - 自己画出典型 RLHF 以及 DPO 的训练流,指出奖励模型、参考模型和策略模型分别在哪。
- 用自己的话回答:Q-learning、DQN 与 REINFORCE 分别学什么?如果奖励模型喜欢冗长但错误的答案,你会怎样评估和修正?