斯坦福 CS336 从零构建大模型 (2025 春) - 第十七讲:强化学习与自对齐 (Alignment - RL 2)

斯坦福 CS336 第十七讲(Alignment - RL 2)是整个课程的最后一讲。在上一讲介绍了“基于可验证奖励的强化学习”的宏观概念后,本讲选择“向下深钻”,深入拆解了策略梯度(Policy Gradient)与 GRPO 算法的底层数学机制、代码实现细节以及系统工程挑战。

以下是本讲不遗漏任何核心知识点的全景深度总结,并在文末为您完整还原了课堂上的 Q&A 问答实录:


一、 大模型强化学习的独特设定 (RL Setup for LLMs)

在将大模型放入强化学习(RL)框架时,必须先明确基本元素的定义:

  • 状态 (State):当前的 Prompt 加上模型迄今为止已生成的回复(Tokens)。
  • 动作 (Action):生成下一个 Token。
  • 奖励 (Reward):评估回复的好坏。本讲聚焦于结果奖励(Outcome rewards),且是可通过确定性代码或脚本计算的可验证奖励(Verifiable rewards)(如判断数学题是否做对),而非依赖人类打分。
  • 状态转移与系统特性:在语言模型中,环境的“转移机制”极其简单,就是单纯的字符串拼接(Append)。这种已知且确定的转移机制使得我们可以在大模型上进行**“规划(Planning / Test-time compute)”**,这是传统机器人 RL 领域梦寐以求的特性。此外,由于“状态”本质上只是模型生成的文本,模型可以自由地利用“草稿本(Scratchpad)”来创造中间状态,而不受物理现实的物理约束。

二、 策略梯度与稀疏奖励的困境 (Policy Gradient & Sparse Rewards)

策略梯度算法的底层逻辑非常直观:你想最大化期望奖励,那就对它求导。

  • 朴素策略梯度 (Naive Policy Gradient):利用对数导数技巧(Log-derivative trick),梯度的计算等价于:“用奖励值 (Reward) 去加权对数概率的梯度”。如果奖励是正的,就提高该输出的概率;如果是负的或零,就不提高。
  • 致命的稀疏奖励问题:假设奖励只有 0(错误)和 1(正确)。如果初始模型非常糟糕,它生成的回复几乎全错,奖励全是 0。代入公式后你会发现,梯度完全变成了 0。这意味着如果模型弱到连一道题都蒙不对,它就根本无法进行任何梯度更新,直接卡死在原地。
  • 动态数据集:与监督微调(SFT)不同,RL 中的“训练数据”是模型自己实时生成的。只要模型偶尔蒙对了几道简单的题并获得了梯度更新,它的能力就会提升,接下来生成的数据集的平均奖励就会越来越高,形成正向循环。

三、 基线 (Baselines) 与方差缩减的数学魔法 (Variance Reduction)

朴素策略梯度存在极高的方差(High noise and variance)。讲师通过一个简单的“两状态玩具实验”证明:仅仅因为某些困难题目的绝对分数较低,朴素梯度可能会错误地降低正确答案的概率。

  • 引入基线 (Baseline):为了降低方差,我们可以从奖励中减去一个基线函数 B(S)。在数学上,只要 B(S) 仅仅依赖于状态 S,而不依赖于当前采取的动作 A,减去它就绝不会改变期望梯度的方向,但能极大降低方差。
  • 最优基线与优势函数 (Advantage):理论上最好的启发式基线是“给定状态下的期望奖励”。当我们用实际奖励减去期望奖励时,得到的值就是优势函数 (Advantage Function)。它衡量的是:“采取这个动作,比盲目随机采取一个平均动作要好多少?”。

四、 GRPO 算法的代码实现剖析 (GRPO Implementation Details)

为什么 GRPO 算法在大语言模型中如此流行?因为语言模型的特性完美契合了基线的需求:对于同一个 Prompt(问题),模型可以轻松生成一组(Group)多个不同的回复。这组回复的平均得分,天然构成了一个极好的经验基线 B(S),从而彻底免去了训练庞大价值模型(Value Model)的麻烦。

讲师用一个简单的“对 N 个数字进行排序”的 Toy Task 演示了代码逻辑:

  • 奖励塑形 (Reward Shaping):如果只给 0 和 1(全对才给分),模型很难学。我们可以给“部分学分(Partial credit)”——只要数字在 Prompt 中出现就给 1 分,每出现一对相邻且排序正确的数字再给 1 分。
  • 计算 Delta (更新步长):拿到一组回复的奖励后,有三种处理方式:
    1. 直接使用(Naive)
    2. 中心化 (Centered):减去组内均值。即使所有回复得分都很高,低于均值的也会得到负的 Delta,促使模型向组内相对更好的方向更新。
    3. 标准化 (Normalized):减去均值并除以标准差(GRPO 的做法)。
  • 计算损失与 PPO 截断 (Clipping):代码中需要计算当前模型策略与“旧模型策略 ( P o l d P_{old} Pold)”的概率比率。为了防止策略更新步子太大导致崩溃,将比率截断在 [ 1 − ϵ , 1 + ϵ ] [1-\epsilon, 1+\epsilon] [1ϵ,1+ϵ] 范围内,再乘以优势 Delta,最后取负值作为 Loss。

五、 关键技术细节:KL 惩罚与系统复杂性 (KL Penalty & System Complexity)

  • 低方差的 KL 散度估算公式: 为了防止模型为了刷分而偏离人类正常语言太远,我们会加入针对参考模型(Reference Model)的 KL 惩罚。方差更低的无偏估计技巧是使用: Q / P − log ⁡ ( Q / P ) − 1 Q/P - \log(Q/P) - 1 Q/Plog(Q/P)1。由于 Q / P Q/P Q/P 的期望为 1,减去 1 后期望仍等价于原始 KL,但由于结合了重要性权重的抵消,它的方差更小。
  • RL 系统的工程噩梦: 搭建 RL 训练框架远比预训练要复杂。你需要同时兼顾:
    • 运行执行生成的推理引擎(Inference worker)。
    • 显存里需要同时驻留多达三个模型:当前正在训练的策略模型 (Policy)、用于 KL 约束的参考模型 (Reference Model),以及用于计算概率比率的旧模型 (Old Policy)(虽然旧模型可以通过只保存 Log-probs 来省显存)。
    • 如果用 PPO,还需要一个与语言模型同样庞大的价值模型 (Critic) 以及奖励模型。所有这些需要在分布式节点上并行并时刻同步。

六、 核心概念问答 (Q&A)

Q1:为什么在训练时数据集是一直在变化的?

回答:因为你在优化的目标是一个迭代过程。每次梯度更新后,你的模型参数都变了。下一次你再用这个新模型去采样生成回复时,它生成的文本分布已经不同于上一步了。因此,随着策略变得越来越好,你用于训练的生成数据也会自动包含越来越高分的回复。

Q2:如果稀疏奖励下,得 0 分就不更新参数,那我们能不能干脆把 0 分改成 -1 分?

回答:这是一个好主意。但这其实在引入“基线(Baselines)”之后会自动发生。当我们用实际奖励减去这批回答的平均分(比如平均分是 0.1 分)时,原本得 0 分的回答对应的 Delta 就变成了 -0.1。这样算法就自然会产生负向的梯度,将模型推离那些错误的回答。

Q3:在定义基线 B(S) 时,能不能直接把 B(S) 设为上一轮刚刚冻结(Frozen)的那个旧模型策略?

回答:绝对可以。这正是强化学习工程中经常做的事情。只要你在计算当前的梯度时,对这个旧策略使用了 torch.no_grad(),在数学上它就是一个合法的、不依赖当前实时策略的常量基线。

Q4:为什么在结果奖励(Outcome Rewards)中不使用折扣因子(Discounting)?

回答:强化学习中最难的问题就是“信用分配(Credit assignment)”。虽然最后的结论很重要,但实际上早期做出的宏观规划和策略方向往往才是决定最终能不能做对的核心。因此,最简单的做法就是把功劳或惩罚均匀地“涂抹(Smear)”在生成这串回复的所有 Token 上。

Q5:在代码中,计算截断比例时,如果你对一个 Tensor 去做 no_grad(),再求导会有什么陷阱?

回答:这是一个经典的 PyTorch 陷阱。在计算 P / P o l d P/P_{old} P/Pold 时,如果你不把 P o l d P_{old} Pold 放入 no_grad() 中,PyTorch 会尝试对分母也求导。如果你用当前的 P P P 去除以当前的 P P P,比例永远是 1,对常数 1 求导梯度永远是 0,你就什么也学不到。

Q6:在最内层的优化循环中,第一步迭代时 P o l d P_{old} Pold 和当前的 P θ P_\theta Pθ 完全相等,Clipping 有意义吗?

回答:在第一次微调步中, P o l d P_{old} Pold P θ P_\theta Pθ 的比率正好是 1,绝对处于截断范围内。所以此时的算法其实就是执行了一次标准的、没有受到截断限制的策略梯度更新,这在逻辑上是完全自洽的。


七、 第十七讲复习题 (Lecture 17: Alignment - RL 2)

一、 强化学习在语言模型中的独特设定

  1. 基础定义:当我们将强化学习应用于大语言模型时,状态(State)、动作(Action)以及环境的转移机制(Transition dynamics)分别是如何定义的?这种转移机制给语言模型带来了什么优势?
  2. 信用分配 (Credit Assignment):在仅使用最终的结果奖励(Outcome rewards)时,我们为什么通常不使用时间折扣因子(Discounting)来让离结果更近的 Token 获得更多奖励?

二、 策略梯度的痛点与基线 (Baselines)

  1. 稀疏奖励的死锁:如果一个糟糕的初始语言模型在面对难题时生成的所有答案都是错的(得分为 0)。在“朴素策略梯度”算法下,这会导致什么极其严重的训练后果?
  2. 引入基线的数学意义:为了解决策略梯度的高方差问题,我们会在奖励中减去一个基线函数 B(S)。在数学上,什么样的基线是合法的?理论上最优的启发式基线(Heuristic baseline)是什么?
  3. GRPO 的天然优势:为什么像 GRPO 这样“通过一组回复的平均分来作为基线”的算法,特别合大语言模型,而难以直接应用于传统的控制类强化学习任务中?

三、 奖励塑形与代码实现细节

  1. 奖励塑形 (Reward Shaping):在“对 N 个数字进行排序”的玩具实验中,如果只给全对的答案 1 分,模型很难收敛。讲师是如何通过“奖励塑形”来给予部分学分(Partial credit)的?
  2. 中心化奖励 (Centered Rewards):在计算梯度步长(Delta)时,如果将当前回复的奖励“减去组内平均分(中心化)”,这相比直接使用原始奖励有什么优化上的好处?
  3. KL 散度的低方差估计:在计算当前策略与参考模型之间的 KL 散度惩罚时,常用的简单估计是 log ⁡ ( Q / P ) \log(Q/P) log(Q/P)。课程中介绍了一种方差更低的无偏估计技巧,请问这个公式是什么?
  4. PyTorch 中的梯度陷阱:在代码实现中计算模型概率比率( P / P o l d P/P_{old} P/Pold)以进行截断(Clipping)时,如果不显式地把 P o l d P_{old} Pold 放入 torch.no_grad() 中,会导致什么致命错误?

四、 RL 系统的工程挑战

  1. 多模型共存的噩梦:在一般的 RL 系统显存中,通常需要同时保留哪三个关键模型(假设不使用需要庞大价值模型的 PPO)?

八、 💡 参考答案与知识点解析

  1. 基础定义与转移机制?

    • 答案:状态是“提示词加上模型迄今为止生成的回复”。动作是“生成下一个 Token”。环境的转移机制是单纯的“字符串拼接(Append)”。这种确定性使得我们可以在大模型上进行前向“规划(Planning / Test-time compute)”。
  2. 信用分配 (Credit Assignment)?

    • 答案:虽然结论 Token 离奖励最近,但早期的宏观规划才是对错的核心。因此最简单的做法是不做折扣,把功劳均匀地“涂抹(Smear)”在所有生成 Token 上。
  3. 稀疏奖励的死锁?

    • 答案:在策略梯度公式中,参数更新梯度等于对数概率梯度乘以奖励。如果奖励全为 0,梯度也全为 0,模型根本无法进行任何参数更新,直接在糟糕状态下“卡死”。
  4. 引入基线的数学意义?

    • 答案:只要基线函数 B(S) 仅依赖于当前状态 S 而不依赖于动作 A,减去它在期望上就不会改变梯度方向。理论最优基线是“给定该状态下的期望奖励, E [ R ∣ S ] E[R|S] E[RS]”。
  5. GRPO 的天然优势?

    • 答案:语言模型可以并行生成一组多个回复,提供完美的横向对比基准。而传统机器人环境每次采样的轨迹都不同,缺乏这种天然结构。
  6. 奖励塑形 (Reward Shaping)?

    • 答案:奖励塑形就是给予部分学分。在排序中,数字每出现一次给 1 分,且每一对相邻且排序正确的数字再给 1 分。
  7. 中心化奖励 (Centered Rewards)?

    • 答案:中心化可以将低于平均分的奖励转换为负数(即使得分是正的),从而产生负向梯度更新,将策略推离那些相对较差的回答。
  8. KL 散度的低方差估计?

    • 答案:方差更低的无偏估计公式是 Q / P − log ⁡ ( Q / P ) − 1 Q/P - \log(Q/P) - 1 Q/Plog(Q/P)1。它有效地作为控制变量降低了整体方差。
  9. PyTorch 中的梯度陷阱?

    • 答案:如果不将 P o l d P_{old} Pold 放入 torch.no_grad(),PyTorch 会尝试对分母求导。在第一步迭代时, P / P P/P P/P 永远是 1,梯度永远是 0,模型学不到任何东西。
  10. 多模型共存的噩梦?

    • 答案:1) 正在优化的当前策略模型 (Policy);2) 用于 KL 散度约束的参考模型 (Reference Model);3) 用于计算截断比率的旧策略模型 (Old Policy)。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐