第一篇章:RLHF 的地基 —— 这里的“反馈”到底是什么?

在进入复杂的公式之前,我们必须先对齐一个最底层的认知:为什么仅仅靠“训练数据”是不够的?

1. 核心直觉:鹦鹉 vs. 导盲犬

要理解 RLHF,你首先要理解现在的 AI(LLM)面临的根本矛盾:

  • 预训练(Pre-training)出来的模型是“鹦鹉”: 它读了互联网上所有的书。它知道下一词填什么概率最高,但它不知道什么叫“对”,什么叫“错”。如果你问它“如何制造毒药?”,它会很高兴地预测出毒药的配方,因为在训练数据里,问题后面通常紧跟答案。

  • 我们想要的是“导盲犬”: 它不仅要懂指令,还要懂人类的价值观(安全、有用、诚实)。

RLHF 的本质,就是把一只“博学但混乱的鹦鹉”,训练成一只“懂规矩的导盲犬”。

2. 地基知识 A:语言模型的本质(Next Token Prediction)

一切的起点是 GPT(Generative Pre-trained Transformer)。在 RLHF 介入之前,模型只做一件事:最大化似然估计(Maximum Likelihood Estimation)

数学原理

假设一个句子由序列 $x = (x_1, x_2, ..., x_T)$ 组成。模型的训练目标是最大化以下概率:

$P(x) = \prod_{t=1}^{T} P(x_t | x_1, ..., x_{t-1})$

在训练时,我们使用交叉熵损失函数(Cross-Entropy Loss)

$Loss = - \sum_{t=1}^{T} \log P(x_t | x_{<t})$

它的局限性(为什么需要 RLHF?)

这个 Loss 只能告诉模型:“在这个语境下,这也是人说过的某个词”。它无法告诉模型:

  • 这句话是粗鲁的。

  • 这句话是错误的。

  • 这句话虽然语法通顺,但是没有任何逻辑。

结论: 传统的监督学习(Supervised Learning)只能教模型“像人一样说话”,不能教模型“像好人一样说话”。

3. RLHF 的第一步:有监督微调 (SFT - Supervised Fine-Tuning)

在直接上强化学习之前,我们需要让模型先入个门。这一步叫 SFT(冷启动阶段)

  • 原理: 既然预训练模型太发散,我们就人工写一批完美的问答对(Prompt + Answer)。

  • 做法: 还是用上面的“交叉熵损失函数”,让模型死记硬背这些高质量的回答。

  • 目的: 让模型从“续写模式”切换到“问答模式”。

注意: 到这一步,模型还是不知道哪个更好,它只是在模仿人类的句式。SFT 模型通常被称为 Policy Model ($\pi_{SFT}$)

4. RLHF 的第二步:奖励模型 (Reward Model, RM) —— 这里的核心数学

这是 RLHF 中最关键的“地基”。如果不能定义“什么是好”,就无法进行强化学习。

我们不可能让真人盯着模型每一步的输出去打分(效率太低)。所以,我们需要训练一个 AI(奖励模型)来模仿人类的评分标准

核心难题:人类很难给出绝对分数

如果你问人:“这句话得几分(1-10)?”

  • 张三可能觉得是 7 分。

  • 李四心情不好,觉得是 4 分。

  • 绝对分数噪声极大,无法用于训练。

解决方案:Bradley-Terry 模型(成对比较)

我们不让打分,而是让做选择题。

给定一个问题 $x$,模型生成两个回答 $y_1$$y_2$。让人类标注员选:哪个更好?(假设$y_w$ 是胜者,$y_l$是败者)。

我们假设,一个回答比另一个回答好的概率,取决于它们潜在得分(Reward)的差值

$P(y_w > y_l | x) = \sigma(r_\theta(x, y_w) - r_\theta(x, y_l))$

其中:

  • $r_\theta(x, y)$ 是我们要训练的奖励模型给出的分数(这是一个标量,Scalar)。

  • $\sigma$Sigmoid 函数,把分差映射到 (0, 1)的概率区间:\sigma(z) = \frac{1}{1 + e^{-z}}

奖励模型的损失函数 (Ranking Loss)

我们要训练奖励模型$r_\theta$,使得它给 $y_w$(胜者)的分数尽可能比 $y_l$(败者)高。

根据最大似然估计,我们要最小化以下 Loss:

$Loss_{RM}(\theta) = - \mathbb{E}_{(x, y_w, y_l) \sim D} [\log(\sigma(r_\theta(x, y_w) - r_\theta(x, y_l)))]$

$r_\theta(x, y_w)$$r_\theta(x, y_l)$:奖励模型给胜者和败者分别打了个分,比如胜者得 5 分,败者得 2 分。

差值 (5 - 2) = 3:分差越大,说明胜者越明显。

$\sigma(3) \approx 0.95$:经过 Sigmoid,说明模型认为 $y_w$ 胜出的概率是 95%。

$\log(0.95) \approx -0.05$:取对数。

$-(-0.05) = 0.05$:取负号,Loss 很小。

反之: 如果奖励模型眼瞎了,给败者打 5 分,胜者打 2 分。

  1. 差值 $-3$

  2. $\sigma(-3) \approx 0.05$

  3. $\log(0.05) \approx -3$

  4. -Loss  = 3。Loss 巨大!模型会被狠狠惩罚,被迫调整参数。

第一篇章总结

到目前为止,我们还没开始“强化学习”,我们只是做好了准备工作:

  1. SFT 模型: 一个模仿了人类高质量回答,但不知道背后逻辑的“演员”。

  2. Reward 模型: 一个学会了人类喜好,能通过对比两个答案,精准判断哪个更好的“裁判”。

接下来的挑战: 既然有了裁判(Reward Model),为什么不直接用梯度上升去优化 LLM,让它生成 Reward 最高的词呢?

  • 因为 LLM 的输出是离散的(Token),离散数据不可导,无法直接反向传播 Reward 的梯度给 LLM。

  • 这就是为什么我们需要 PPO(Proximal Policy Optimization) 这种强化学习算法介入的原因。

在 RLHF 中,奖励模型(Reward Model, RM)是裁判。裁判不会去评价“概率”,裁判只评价“结果”。

请看这个断裂的计算图

  1. LLM 输出 Logits: [0.1, 0.8, 0.05, ...](对应词表里的词)。

  2. Softmax 变成概率: 还是连续的数值。

  3. 关键动作 —— 生成 (Generation):

    为了把这些概率变成一段话喂给奖励模型,模型必须做一个决定:选哪个词?

    • 要么 Argmax(选概率最大的)。

    • 要么 Sampling(按概率随机采样)。

  4. 奖励模型 (RM) 输入: RM 接收的是具体的 token ID(比如单词 "cat"),而不是 "cat" 的概率值。

  5. RM 输出: 5 分。

奖励模型给出的分数(Reward),被“生成具体的词”这个动作挡住了,梯度传不回去给 LLM 的参数。

怎么办?这就需要“策略梯度”(Policy Gradient)

既然链式法则(Chain Rule)在“生成”这一步断了,我们就不能用标准的梯度下降。

我们需要一种算法,它不需要知道“这一步具体该怎么微调”,它只需要知道: “刚才这次尝试(Sampling),结果是好的(Reward高)。既然是好的,那就增加‘刚才那个动作’出现的概率!”

这就是 Reinforcement Learning 的魔法。它不是通过误差反向传播来直接修改参数,而是通过调整概率来间接优化策略。

$\nabla J(\theta) \propto \mathbb{E} [ \text{Reward} \cdot \nabla \log P(\text{action}) ]$

这个公式的意思是:

  • 我不关心 Reward 怎么对 Action 求导(因为不可导)。

  • 我只把 Reward 当作一个权重(Weight)

  • 如果 Reward 是正的,我就增大 $\log P(\text{action})$ 的梯度(让这个词下次出现概率更高)。

  • 如果 Reward 是负的,我就减小它。

你不能直接输出 Reward 最高的词,是因为:

  1. Reward Model 需要具体的词(Token)作为输入,而不是概率。

  2. 从概率到具体的词(Sampling/Argmax)是一个“离散化”过程,在数学上不可导(梯度阻断)。

这就是为什么我们需要引入 PPO 这样的强化学习算法,而不是简单地把它当作一个 Loss 函数来跑 SGD。

第二篇章:强化学习的核心 —— 越过不可导的悬崖

1. 核心思想:我不求导,我改概率

既然我不能计算 $\frac{\partial \text{Reward}}{\partial \text{Model}}$,那我就换个思路。

我们回顾一下目标:我们希望 Reward 高的动作(词),出现的概率(Probability)变大。

在数学上,我们的目标函数 $J(\theta)$ 是期望回报(Expected Reward)最大化:

$J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} [R(\tau)]$

其中:

  • $\pi_\theta$是我们的 LLM(策略网络)。

  • $\tau$ 是生成的轨迹(一句话,Trajectory)。

  • $R(\tau)$ 是这句话得到的奖励分数。

魔法:对数导数技巧 (Log-Derivative Trick)

我们想要求 $J(\theta)$ 关于参数 $\theta$ 的梯度 $\nabla_\theta J(\theta)$

这里的推导请紧跟:

展开期望公式(积分/求和):

$J(\theta) = \sum_{\tau} P(\tau|\theta) R(\tau)$

(期望 = 概率 $\times$ 分数)

求梯度(梯度符号 $\nabla$ 可以穿过求和符号,因为 $R(\tau)$ 对于当前参数来说是固定的标量值,真正受 $\theta$ 影响的是概率 $P(\tau|\theta)$):

$\nabla_\theta J(\theta) = \sum_{\tau} \nabla_\theta P(\tau|\theta) R(\tau)$

引入恒等变换: 根据高中数学导数公式 $(\ln x)' = \frac{1}{x} \Rightarrow (\ln x)' \cdot x = 1$,我们可以推出 $\nabla_\theta P = P \cdot \frac{\nabla_\theta P}{P} = P \cdot \nabla_\theta \log P$。 把这个代入上式:

$\nabla_\theta J(\theta) = \sum_{\tau} P(\tau|\theta) \cdot \nabla_\theta \log P(\tau|\theta) \cdot R(\tau)$

变回期望形式:

$\nabla_\theta J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} [\nabla_\theta \log P(\tau|\theta) \cdot R(\tau)]$

这就是策略梯度定理 (Policy Gradient Theorem)。

这个公式告诉了我们什么?
  • $\nabla_\theta \log P(\tau|\theta)$:这是 LLM 自身输出概率的梯度(这是完全可导的!就是常规的反向传播)。

  • $R(\tau)$:这是奖励模型给的一个数字(标量)。

  • 结论:我们不需要对 R求导。我们只需要把 R 当作一个权重系数

    • 如果 R 是正的大数 $\rightarrow$这里的梯度权重很大 $\rightarrow$ 猛烈更新参数,让这个 token 概率变大。

    • 如果 R 是负数 $\rightarrow$梯度反向 $\rightarrow$ 降低这个 token 的概率。

2. 进阶:为什么要引入 Critic (AC 架构)?

上面的公式有一个大问题:方差(Variance)极大。

有些句子虽然写得烂,但运气好碰巧某些词用对了,Reward 可能是正的;有些句子写得好,但运气不好,Reward 低。如果直接用原始 $R$去乘梯度,训练会像心电图一样乱跳,根本收敛不了。

解决方案:引入基准线 (Baseline) 与优势函数 (Advantage)

我们不应该看“绝对得分”,应该看“相对得分”。 比如,考试考了 60 分。

  • 如果平均分是 30 分,那你很棒(Reward 正向)。

  • 如果平均分是 90 分,那你很差(Reward 负向)。

我们需要一个模型来预测这个“平均分”。这个模型就是 Value Model (Critic),记作 $V(s)$。 它不生成文本,它只负责读入当前的上文,预测:“按照现在的局势,这一把大概能得多少分?”

我们用 优势函数 (Advantage Function) 来代替原始 Reward:

$A(s, a) = Q(s, a) - V(s)$

(实际 PPO 中通常使用 GAE: Generalized Advantage Estimation)

简单理解:

  • $Q(s, a)$:实际执行动作 $a$ 后拿到的真实回报(现实)。

  • $V(s)$:Critic 预测的回报(预期)。

  • $A$ (优势)现实 - 预期

    • $A > 0$:惊喜!表现超乎预期,增加该动作概率。

    • $A < 0$:失望!表现不如预期,降低该动作概率。

3. 终极形态:PPO (Proximal Policy Optimization)

有了策略梯度和 Advantage,我们其实已经可以用 TRPO (Trust Region Policy Optimization) 等算法训练了。但 TRPO 计算太复杂(涉及海森矩阵的逆)。

OpenAI 提出了 PPO,用最简单的数学实现了稳扎稳打的训练。后面的DEEPSEEK又推出了GRPO,但是我们还是先从PPO开始吧

PPO 解决的核心痛点:步子大了容易混乱

在强化学习中,数据是“由当前的策略”生成的(On-Policy)。 如果你一次更新把参数改猛了,策略变了,原来采集的数据就全部作废了。而且如果策略变差了,下次采的数据会更差,导致模型直接崩盘,再也救不回来。

PPO 的核心:限制更新幅度。

PPO 的 Loss 函数 (Clip 版本)

我们定义一个概率比率 $r_t(\theta)$

$r_t(\theta) = \frac{\pi_{\theta_{new}}(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}$

  • 如果 $r_t = 1$,说明新老策略一样。

  • 如果 $r_t > 1$,说明新策略提高了该动作的概率。

PPO 的目标函数是取下面两项的最小值

$L^{CLIP}(\theta) = \mathbb{E} [ \min( r_t(\theta) \hat{A}_t, \text{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon) \hat{A}_t ) ]$

让我们像拆解代码一样拆解这个公式(假设 $\epsilon = 0.2$):

情况一:动作是好的 ($\hat{A}_t > 0$)

  • 我们需要提高概率,也就是让 $r_t > 1$

  • 第一项 $r_t \hat{A}_t$ 想让 $r_t$ 无限变大。

  • 第二项 clip 限制了 $r_t$ 最大只能是 1.2。

  • 取最小值 $\min$如果 $r_t$ 超过 1.2,Loss 就不再增加了(梯度消失)。

  • 含义: 只要你把概率提高一点点(20%)我就满意了,不要改得太夸张!

情况二:动作是坏的 ($\hat{A}_t < 0$)

  • 我们需要降低概率,也就是让$r_t < 1$

  • clip 限制了 $r_t$ 最小只能是 $0.8$

  • 取最小值(这里因为$A$ 是负数,其实是看谁更负):如果 $r_t$ 低于 0.8,也不再惩罚了。

  • 含义: 只要你把概率降低一点点我就放过你,别把模型改废了。

第二篇章总结

在这一章,我们解决了一切数学障碍:

  1. 策略梯度 (Policy Gradient): 利用 $\nabla \log P$ 绕过了采样不可导的问题,把 Reward 变成了梯度权重的系数。

  2. Critic (Value Model): 引入“预期管理”,计算 Advantage,减少方差,让训练更稳定。

  3. PPO Clipping: 给模型带上“手铐”,限制每次参数更新的幅度,防止模型在强化学习的深渊中“步子太大”导致崩溃。

现在的架构里有了四个东西在跑:

  1. Actor (生成模型,我们需要训练的)

  2. Critic (价值模型,辅助训练的)

  3. Reward Model (给分的裁判,冻结的)

  4. Reference Model (SFT模型,作为对照组,冻结的 —— 为什么需要它?)

这里埋下了一个伏笔:Reference Model。 即使有了 PPO 的 Clip,模型还是可能会为了高分去“作弊”(Reward Hacking),比如一直重复说“谢谢谢谢”(如果裁判模型喜欢礼貌的话)。 我们需要一个东西来约束它:KL 散度(KL Divergence)

在前两章中,我们造出了一个懂人类喜好的“裁判”(Reward Model),并且找到了训练不可导模型的数学工具(PPO)。

现在的最大风险是:模型变坏(Reward Hacking)

如果你只告诉模型“得分越高越好”,模型很快就会发现 Reward Model 的漏洞。比如,Reward Model 可能稍微倾向于长的句子,模型就会开始输出几千字的废话;或者 Reward Model 觉得“我不知道”很安全,模型就对所有问题都回答“我不知道”。

第三篇章:RLHF 的完整闭环 —— KL 约束与代码实现逻辑

1. 地基知识 B:KL 散度 (Kullback-Leibler Divergence)

在 RLHF 中,我们不希望强化学习训练后的模型(Actor)偏离原来的 SFT 模型(Reference)太远。因为 SFT 模型虽然不够“好”,但它至少通顺、符合语法

我们不仅要“分高”,还要“不忘初心”。

数学定义

KL 散度用于衡量两个概率分布 $P$$Q$ 之间的差异:

$D_{KL}(P || Q) = \sum_{x} P(x) \log \frac{P(x)}{Q(x)}$

利用对数性质 $\log(a/b) = \log a - \log b$,公式可以写成:

$D_{KL}(P || Q) = \sum_{x} P(x) (\log P(x) - \log Q(x))$

在 RLHF 中的实际意义:

  • $P(x)$:当前的强化学习模型(Actor)生成某个 token 的概率。

  • $Q(x)$:原始的 SFT 模型(Reference Model)生成同一个 token 的概率。

  • $\log P(x) - \log Q(x)$:这就是我们要计算的差值。

修正后的总奖励 (Total Reward)

我们在训练 PPO 时,不再只给模型 Reward Model 的打分,而是给一个组合分:

$R_{total} = R_{RM}(x) - \beta \cdot D_{KL}(\pi_{\theta} || \pi_{ref})$

  • $R_{RM}$:裁判给的分(比如 5 分)。

  • $\beta$:惩罚系数(比如 0.1)。

  • $KL$:如果你生成的词,SFT 模型觉得“很离谱”(概率很低),KL 值就会很大,你的总分就会被狠狠扣除。

2. RLHF 的“四马车”架构

在代码实现层面(例如 DeepSpeed-Chat 或 TRL 库),当你按下“开始训练”按钮时,显存里同时跑着 4 个神经网络。这是一场消耗显存的盛宴:

模型名称 角色 状态 作用
Actor (Policy) 演员 训练中 我们要优化的 LLM,负责生成文本。
Critic (Value) 评论家 训练中 预测每个状态的价值 (Value),用于计算 Advantage。
Reward Model 裁判 冻结 给生成的文本打分。
Reference Model 老师 冻结 原始的 SFT 模型,用于计算 KL 散度,防止 Actor 跑偏。

显存优化提示: 通常 Reference Model 和 Reward Model 不需要计算梯度,可以进行量化(Int8/FP16)或者在推理完后卸载到 CPU(Offload)以节省显存。

3. 完整的 RLHF 训练循环 (The Loop)

请仔细阅读这个流程,这是所有 RLHF 代码(如 TRL / DeepSpeed)的核心骨架。我们将训练过程分为两个阶段:采样(Rollout)更新(Update)

阶段一:采样 (Make Experience)

我们需要先让模型去“玩”一下,收集数据。

  1. 取 Prompt: 从数据集中拿一个问题,比如 "如何做红烧肉?"

  2. 生成 (Generate):Actor 生成回答 "先把肉切块..."。

  3. 打分 (Reward): 把“问题+回答”喂给 Reward Model,得到分数 $R_{score}$(比如 0.8)。

  4. 计算约束 (KL):

    • 把同样的“问题+回答”喂给 Reference Model

    • 计算 Actor 和 Reference 在每个 Token 上的概率对数差:log_prob_actor - log_prob_ref

    • 计算修正后的奖励:$R_{step} = - \beta \cdot (\text{log\_prob\_actor} - \text{log\_prob\_ref})$

    • 在最后一个 Token 加上 $R_{score}$

  5. 价值预测 (Value):Critic 预测每一步的价值 $V(s)$

此时,我们手里有了一堆数据(Trajectory):状态、动作、概率、奖励、价值。这些数据存入 Replay Buffer

阶段二:更新 (PPO Update)

现在用收集的数据来更新 Actor 和 Critic 的参数。

  1. 计算优势 (GAE): 使用 $R_{total}$$V(s)$ 计算优势函数$Advantage$(这一步其实比预期好多少)。

  2. PPO Loss 计算:

    • 从 Buffer 中取出数据。

    • Actor Loss: 计算新旧策略的比率 $r_t$,用 clip 方法限制更新幅度,最大化优势。

    • Critic Loss: 计算 Critic 预测的 $V$和真实回报的均方误差 (MSE),让 Critic 预测更准。

  3. 梯度反向传播: (Actor_Loss + Critic_Loss).backward()

  4. 更新参数: optimizer.step()

4. 代码级逻辑 (Python 伪代码)

为了让你完全看懂,我去掉所有复杂的工程细节,只保留最核心的逻辑流:

# 初始化四个模型
actor = GPT2_Policy()       # 可训练
critic = GPT2_Value()       # 可训练
reward_model = GPT2_RM()    # 冻结
ref_model = GPT2_Policy()   # 冻结 (这是Actor的初始副本)

optimizer = AdamW(actor.parameters() + critic.parameters())

# 训练循环
for epoch in range(total_epochs):
    # -------------------------------------------------------
    # 步骤 1: 采样 (Rollout) - 不计算梯度
    # -------------------------------------------------------
    with torch.no_grad():
        prompt = get_batch_prompt() # "今天天气"
        
        # Actor 生成回答
        response_seq, old_log_probs = actor.generate(prompt) 
        # Output: "今天天气不错"
        
        # Reference Model 计算原始概率 (用于 KL)
        ref_log_probs = ref_model.forward(prompt + response_seq)
        
        # Reward Model 打分
        score = reward_model.forward(prompt + response_seq) # scalar: 5.0
        
        # Critic 预测价值
        old_values = critic.forward(prompt + response_seq)

    # -------------------------------------------------------
    # 步骤 2: 计算 奖励 和 优势 (Process Rewards)
    # -------------------------------------------------------
    # 计算 KL 惩罚 (逐个 Token 的惩罚)
    # KL = log P_actor - log P_ref
    kl_divergence = old_log_probs - ref_log_probs
    
    # 组合奖励 = 最后的评分 - 过程中的KL惩罚
    rewards = -beta * kl_divergence
    rewards[-1] += score # 只在最后一个 token 加上真正的 RM 分数
    
    # 使用 GAE (Generalized Advantage Estimation) 计算优势
    advantages, returns = compute_gae(rewards, old_values)
    
    # -------------------------------------------------------
    # 步骤 3: PPO 更新 (Optimize) - 计算梯度
    # -------------------------------------------------------
    for _ in range(ppo_epochs): # 同一批数据可以重复利用几次
        # 重新计算当前概率和价值 (因为参数在变)
        new_log_probs = actor.forward_log_probs(prompt + response_seq)
        new_values = critic.forward(prompt + response_seq)
        
        # --- Actor Loss (PPO Clip) ---
        ratio = torch.exp(new_log_probs - old_log_probs)
        surr1 = ratio * advantages
        surr2 = torch.clamp(ratio, 1-eps, 1+eps) * advantages
        actor_loss = -torch.min(surr1, surr2).mean() # 负号因为要做梯度下降
        
        # --- Critic Loss (MSE) ---
        critic_loss = (new_values - returns).pow(2).mean()
        
        # 总 Loss
        loss = actor_loss + 0.5 * critic_loss
        
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

print("训练完成!现在的 Actor 既懂人话,又懂规矩。")

我们设定一个极简场景:

举例

  • Prompt (题目): "你好" (2个字)

  • Response (回答): "开心" (2个字)

  • 总长度: 4个字。

现在,请想象这 4 个字正在传送带上流动。

第一阶段:生产线(生成数据)

这时候,只有**Actor(学生)**在工作,其他模型在后面盯着。

1. 初始状态

  • 传送带上只有:["你", "好"]

2. 第一步生成 (T=2)

  • Actor (学生): 看到 ["你", "好"]

    • 它想说 "开"

    • 它心里对 "开" 的自信程度(概率)是 0.6

    • 记录数据: Token: "开", Old_Prob: 0.6

  • Critic (助教): 看到 ["你", "好"]

    • 它预测:这局大概能得 0.2 分。

    • 记录数据: Value: 0.2

3. 第二步生成 (T=3)

  • Actor (学生): 看到 ["你", "好", "开"]

    • 它想说 "心"

    • 它心里对 "心" 的自信程度(概率)是 0.8

    • 记录数据: Token: "心", Old_Prob: 0.8

  • Critic (助教): 看到 ["你", "好", "开"]

    • 它预测:这局大概能得 0.9 分(因为它觉得"开"后面接"心"是个好词,胜算大了)。

    • 记录数据: Value: 0.9

4. 结束生成

  • 句子结束。现在传送带上有完整的:["你", "好", "开", "心"]

5. 老师和裁判入场 现在拿着这完整的句子,给另外两个冻结的模型看:

  • Ref (老师): 看着 ["你", "好", "开", "心"]

    • 老师想:如果要我写,"开" 的概率是 0.5"心" 的概率是 0.9

    • 记录数据: Ref_Prob: [0.5, 0.9]

  • Reward Model (裁判): 看着 ["你", "好", "开", "心"]

    • 裁判觉得这句话很礼貌,给个高分。

    • 记录数据: Final_Score: 3.0


第二阶段:贴标签(计算奖励流)

这是最关键的一步。我们要给 "开""心" 这两个字分别贴上“好坏标签”。

1. 算 KL 惩罚 (是不是说人话?)

  • "开": 学生概率 0.6,老师概率 0.5。差别不大。

    • KL 惩罚 ≈ -0.01(微小的扣分)。

  • "心": 学生概率 0.8,老师概率 0.9。差别也不大。

    • KL 惩罚 ≈ -0.01。

2. 算总奖励 (Reward分配) 这里就是数据的“流动”点:Final Score 只加在最后一个字上!

  • "开" 的奖励: 只有 KL 惩罚 = -0.01

  • "心" 的奖励: KL 惩罚 + 裁判大分 = -0.01 + 3.0 = 2.99

3. 算优势 (Advantage - 也就是倒推功劳) 这是 RL 的灵魂。

  • 对于字 "心":

    • 实际拿到 2.99 分。

    • Critic 刚才预测只有 0.9 分。

    • 优势 (Advantage): 2.99 - 0.9 = +2.09

    • 结论: 这是一个巨大的惊喜!"心" 这个字选得太棒了!

  • 对于字 "开":

    • 虽然 "开" 自己只拿了 -0.01 分。

    • 但是!它后面紧跟着一个拿了超级高分的 "心"

    • 优势 (Advantage): 根据 GAE 算法,未来的好事也要算在前人头上。

    • 结论: "开" 也是个好动作,因为它引出了后面的好结果。优势也是 正的(比如 +1.5)。


第三阶段:修改大脑(反向传播)

现在,数据流向了 Actor 和 Critic 的参数。

1. 修改 Actor (学生)

  • 回顾数据:

    • "开" 的优势是 +1.5 (正)。 -> 指令: 下次把 "开" 的概率从 0.6 提上去!

    • "心" 的优势是 +2.09 (大正)。-> 指令: 下次把 "心" 的概率从 0.8 狠狠提上去!

2. 修改 Critic (助教)

  • 回顾数据:

    • "开" 的时候,你预测 0.2,实际后面拿了 3.0。你太保守了!-> 指令: 下次把这里的预测值调高。

    • "心" 的时候,你预测 0.9,实际拿了 2.99。你还是太保守了!-> 指令: 调高!


总结:数据流动的全景图

把这个过程想象成一条河流:

  1. 源头 (Actor): 流出了 "开"(0.6) -> "心"(0.8)

  2. 支流 (Critic): 伴随着流出了 0.2 -> 0.9 的预测。

  3. 入海口 (Reward): 在终点 "心" 处,裁判注入了 3.0 的染料(分数)。

  4. 回流 (Backprop):

    • 3.0 的染料染红了 "心",告诉它“你很棒”。

    • 3.0 的染料逆流而上,染红了 "开",告诉它“你铺垫得好”。

  5. 河床变形 (Update): 河道(参数)被染料改变了形状,下次水流(概率)就会流向分数高的地方。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐