PPO 微调的本质:它不是在教模型“更聪明”
<h2 id="ppo-难不是因为算法复杂而是因为它在干一件反直觉的事">PPO 难,不是因为算法复杂,而是因为它在干一件反直觉的事</h2><p>如果你第一次接触 PPO 微调,大概率会有一种强烈的挫败感。</p>
<p>你可能已经:</p>
<ul>
<li>看过 PPO 的算法图</li>
<li>看过 reward / value / policy 的关系</li>
<li>甚至跑过一次训练</li>
</ul>
<p>但只要你认真问自己一个问题:</p>
<blockquote>
<p>“PPO 到底在改模型的哪一部分?”</p>
</blockquote>
<p>你很可能说不清楚。</p>
<p>你只知道:</p>
<ul>
<li>reward 在涨</li>
<li>loss 在变</li>
<li>输出风格在变化</li>
</ul>
<p>但这些变化<strong>为什么会发生</strong>,<br>
发生在模型的哪一层逻辑上,<br>
你并没有一个“工程上能落地的解释”。</p>
<p>而这,正是 PPO 最容易被误解的地方。</p>
<h2 id="一个必须先说清楚的前提ppo-微调不是能力学习而是行为选择">一个必须先说清楚的前提:PPO 微调不是“能力学习”,而是“行为选择”</h2>
<p>这是理解 PPO 的第一道门槛。</p>
<p>在 SFT(监督微调)里,模型学的是:</p>
<blockquote>
<p>“在这个输入下,<strong>正确答案长这样</strong>。”</p>
</blockquote>
<p>但 PPO 学的不是“正确答案”,<br>
而是:</p>
<blockquote>
<p>“在这个输入下,<strong>我更应该选择哪种回答方式</strong>。”</p>
</blockquote>
<p>这是一个<strong>策略选择问题</strong>,而不是知识学习问题。</p>
<p>PPO 从来不关心模型“会不会”,<br>
它关心的是:<br>
<strong>模型在多个可能回答中,选哪个更好。</strong></p>
<p><br>
SFT vs PPO 学习目标对比图</p>
<h2 id="为什么-ppo-一定要引入奖励而不是直接算-loss">为什么 PPO 一定要引入“奖励”,而不是直接算 loss</h2>
<p>这是很多人第一次看 PPO 时最困惑的地方。</p>
<p>你会问:<br>
既然已经有 loss,为什么还要 reward?</p>
<p>原因非常简单,但非常关键:</p>
<blockquote>
<p><strong>loss 只能衡量“像不像训练数据”,<br>
reward 才能衡量“你想不想要这种行为”。</strong></p>
</blockquote>
<p>在 PPO 里,你想优化的往往是一些<strong>不可直接写成标签的东西</strong>:</p>
<ul>
<li>回答是否谨慎</li>
<li>是否拒绝不该回答的问题</li>
<li>是否遵循偏好顺序</li>
<li>是否避免某类风险</li>
</ul>
<p>这些东西,很难通过“正确答案”来定义,<br>
但可以通过“好 / 不好”来判断。</p>
<p>于是,reward 出现了。</p>
<h2 id="ppo-里的核心角色其实只有一个policy策略">PPO 里的核心角色,其实只有一个:Policy(策略)</h2>
<p>在 PPO 的论文图里,你会看到很多模块:</p>
<ul>
<li>Policy</li>
<li>Reference</li>
<li>Reward</li>
<li>Value</li>
</ul>
<p>但如果从工程视角看,<br>
<strong>真正被更新的,只有 Policy。</strong></p>
<p>Policy 本质上是什么?</p>
<blockquote>
<p><strong>就是你正在微调的那个模型。</strong></p>
</blockquote>
<p>其它模块,全部都是为了一件事服务的:<br>
<strong>限制、引导、校正 Policy 的更新方向。</strong></p>
<h2 id="ppo-的核心问题模型想变但不能乱变">PPO 的核心问题:模型“想变”,但不能乱变</h2>
<p>这是 PPO 名字里“Proximal”的真正含义。</p>
<p>PPO 要解决的问题,不是:</p>
<blockquote>
<p>“怎么让模型变得更符合 reward”</p>
</blockquote>
<p>而是:</p>
<blockquote>
<p>“怎么让模型在不偏离原模型太远的情况下,<br>
慢慢朝 reward 指向的方向移动”</p>
</blockquote>
<p>为什么要这样?</p>
<p>因为在大模型里,<strong>一次“走太远”的更新,几乎一定会带来灾难性副作用</strong>。</p>
<h2 id="kl-约束ppo-里真正的安全带">KL 约束:PPO 里真正的“安全带”</h2>
<p>很多人第一次看到 PPO,会觉得 KL 是个“技术细节”。</p>
<p>但在大模型微调里,<br>
<strong>KL 约束是 PPO 能用的前提条件。</strong></p>
<p>KL 在这里干的事情只有一件:</p>
<blockquote>
<p><strong>惩罚模型“和原来太不一样”。</strong></p>
</blockquote>
<p>你可以把它理解成:</p>
<ul>
<li>reward 在踩油门</li>
<li>KL 在踩刹车</li>
</ul>
<p>没有 reward,模型不知道往哪走;<br>
没有 KL,模型会直接冲出赛道。</p>
<p><br>
reward 与 KL 的拉扯关系示意图</p>
<h2 id="为什么-ppo-会改风格却不一定变聪明">为什么 PPO 会“改风格”,却不一定“变聪明”</h2>
<p>这是很多人 PPO 调完后最困惑的点。</p>
<p>你会发现:</p>
<ul>
<li>模型回答更谨慎了</li>
<li>更会拒绝问题</li>
<li>更符合偏好</li>
<li>但并没有学到新知识</li>
</ul>
<p>这是因为 PPO 的更新信号<strong>根本不是知识型的</strong>。</p>
<p>PPO 优化的是:</p>
<blockquote>
<p>在已有能力空间中,<br>
哪些输出更值得被选择。</p>
</blockquote>
<p>它不会扩展模型的知识边界,<br>
只会重排“行为概率”。</p>
<h2 id="ppo-训练流程用工程语言重新走一遍">PPO 训练流程,用“工程语言”重新走一遍</h2>
<p>下面我们不用论文语言,而用工程视角,重新走一遍 PPO。</p>
<h3 id="第一步policy-生成多个候选输出">第一步:Policy 生成多个候选输出</h3>
responses = policy_model.generate(prompt, n=4)
<p>这一步非常关键:<br>
PPO 需要<strong>选择空间</strong>,而不是单一答案。</p>
<h3 id="第二步reward-model-给每个输出打分">第二步:Reward Model 给每个输出打分</h3>
rewards = reward_model.score(prompt, responses)
<p>注意:<br>
reward 是<strong>相对信号</strong>,不是绝对真理。</p>
<h3 id="第三步计算-policy-更新方向带-kl-约束">第三步:计算 Policy 更新方向(带 KL 约束)</h3>
loss = -reward + kl_coef * kl(policy, reference)
<p>你可以把 PPO loss 理解成一句话:</p>
<blockquote>
<p>“我想要高 reward,但不想和原模型差太远。”</p>
</blockquote>
<h3 id="第四步更新-policy而不是-reward">第四步:更新 Policy(而不是 Reward)</h3>
loss.backward()
optimizer.step()
<p>整个 PPO 过程中,<br>
<strong>唯一被训练的,始终是 Policy。</strong></p>
<h2 id="为什么-ppo-一定需要-reference-model">为什么 PPO 一定需要 Reference Model</h2>
<p>很多人会问:<br>
“既然我已经有 policy,为什么还要 reference?”</p>
<p>答案是:<br>
<strong>因为你需要一个‘不会动的锚点’。</strong></p>
<p>Reference model 通常是:</p>
<ul>
<li>SFT 后的模型</li>
<li>或 PPO 初始模型</li>
</ul>
<p>它的作用只有一个:</p>
<blockquote>
<p>告诉你:你现在离“原来的自己”有多远。</p>
</blockquote>
<p>没有 reference,KL 就失去了意义。</p>
<h2 id="ppo-在大模型微调中真正改变的是概率分布形状">PPO 在大模型微调中,真正改变的是“概率分布形状”</h2>
<p>这是一个非常关键、但极少被讲清楚的点。</p>
<p>PPO 不会:</p>
<ul>
<li>新增 token</li>
<li>改变词表</li>
<li>加新知识</li>
</ul>
<p>它只是在做一件事:</p>
<blockquote>
<p><strong>重新拉伸或压缩输出分布。</strong></p>
</blockquote>
<p>某些回答方式概率被放大,<br>
某些被压低。</p>
<p>于是你看到的“行为变化”,<br>
本质上是概率变化的结果。</p>
<p><br>
PPO 前后输出分布变化示意图</p>
<h2 id="为什么-ppo-对边界行为影响最大">为什么 PPO 对“边界行为”影响最大</h2>
<p>你会发现一个现象:</p>
<p>PPO 调完后,<br>
模型在“模糊、边界、灰色问题”上的变化最大。</p>
<p>原因很简单:</p>
<ul>
<li>确定性强的问题,分布本来就集中</li>
<li>边界问题,分布本来就发散</li>
</ul>
<p>PPO 的 reward,恰恰最容易在这些地方起作用。</p>
<h2 id="ppo-为什么风险高但又不可替代">PPO 为什么“风险高”,但又“不可替代”</h2>
<p>PPO 风险高,是因为:</p>
<ul>
<li>reward 本身可能有偏</li>
<li>模型可能走捷径</li>
<li>行为变化难以预测</li>
</ul>
<p>但它又不可替代,是因为:</p>
<blockquote>
<p><strong>你无法用 SFT 教会模型“偏好”。</strong></p>
</blockquote>
<p>偏好,本质上是比较、权衡、取舍。</p>
<p>而 PPO,正是为这类问题而生的。</p>
<h2 id="一个非常重要的结论ppo-是行为对齐工具不是性能优化工具">一个非常重要的结论:PPO 是“行为对齐工具”,不是“性能优化工具”</h2>
<p>如果你把 PPO 用来:</p>
<ul>
<li>提升准确率</li>
<li>学新知识</li>
<li>纠正事实错误</li>
</ul>
<p>那你几乎一定会失望。</p>
<p>但如果你用它来:</p>
<ul>
<li>调整风格</li>
<li>强化安全边界</li>
<li>对齐人类偏好</li>
</ul>
<p>那 PPO 会非常强大。</p>
<p>另外一个很实际的点是:PPO 的“对齐效果”好不好,很多时候要靠对照评估集反复测试、对比不同 checkpoint 的输出风格。这个过程如果全靠本地脚本手动切版本,很容易把精力耗在搬运和对比上。用 LLaMA-Factory online 做快速版本对照和小规模迭代验证,会比你一开始就重工程投入更容易把方向跑正。</p>
<h2 id="总结理解-ppo关键不在算法而在你到底想改什么">总结:理解 PPO,关键不在算法,而在“你到底想改什么”</h2>
<p>写到这里,其实可以把整篇文章浓缩成一句话:</p>
<blockquote>
<p><strong>PPO 不是在教模型新东西,<br>
而是在告诉模型:你已经会的东西里,哪种更值得选。</strong></p>
</blockquote>
<p>一旦你用“行为选择”而不是“参数优化”来理解 PPO,<br>
你会发现:</p>
<ul>
<li>reward 的意义清晰了</li>
<li>KL 的必要性清晰了</li>
<li>风险从哪里来,也清晰了</li>
</ul>
<p>而这,正是后面所有 PPO 实战、调参、评估、踩坑的基础。</p><br>来源:程序园用户自行投稿发布,如果侵权,请联系站长删除<br>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 谢谢分享,辛苦了 感谢发布原创作品,程序园因你更精彩 新版吗?好像是停更了吧。 很好很强大我过来先占个楼 待编辑 yyds。多谢分享 感谢分享,下载保存了,貌似很强大 yyds。多谢分享 不错,里面软件多更新就更好了 这个有用。 谢谢分享,试用一下 谢谢楼主提供! 感谢分享,下载保存了,貌似很强大
页:
[1]