日期:2026-08-31 · 运行:sao-qwen35-35b-a3b-3nodes(3 节点,单 rollout GAE + value model)
配置文件:scripts/train/configs/sao_3nodes_qwen35_35b_a3b_dynbsz_warmcritic.env(r7)
对照:r6 = sao_3nodes_qwen35_35b_a3b_dynbsz.env 直跑,step ~130 崩溃
critic 始终没有收敛 → 单 rollout GAE 退化成无基线的 REINFORCE → 一个对奖励中性的 "think 工具调用"习惯被迷信式强化 → 滚雪球至 72% 的工具调用都是 think,策略瘫痪。
CRITIC_GRAD_CLIP=1.0,而实际 critic/grad_norm 常年在
7-68 之间——每一次更新都被缩小 7-70 倍,配置的 CRITIC_LR 形同虚设。结果:
vf_explained_var 在 130 步里始终 0~0.3,价值基线从未成型。GAE_WHITEN_ADVANTAGES=False,2026-08-13 的决定,当时假设 critic 会提供基线)。
未白化的批优势均值在 ±0.25 之间大幅漂移——整批全正/全负的更新时有发生。模型在轨迹中反复、连续地调用 think 工具(一步多次、无实质内容),挤掉真实的 编辑/执行动作;num_turns 上升而有效动作密度下降,最终任务通过率崩塌。
| # | 配置项 | r6 | r7 | 针对哪一环 |
|---|---|---|---|---|
| 1 | GAE_WHITEN_ADVANTAGES |
False | True | 批白化重新居中优势,杜绝"全负批";即使 critic 弱,也有批相对基线兜底 |
| 2 | CRITIC_GRAD_CLIP |
1.0 | 10 | 停止饿死 critic:让典型梯度(5-30)不再被缩,critic LR 恢复真实含义 |
| 3 | CRITIC_MODEL_PATH |
随 actor 初始化(value head 随机) | r6@step100 的暖启动 critic(合并后的 HF 检查点) | 价值冷启动是主要瓶颈(论文 3.2 节);r6 critic 的训练数据(样本 0-6400)完全早于 spam 爆发,"弱而不歪" |
| 4 | CRITIC_WARMUP |
0 | 20 | actor 冻结 20 步,让暖启动 critic 先在基础策略上重新校准,校准期 actor 不可能被伤害 |
实现在 verl/trainer/ppo/core_algos.py 的 compute_gae_advantage_return
(GAE_WHITEN_ADVANTAGES 映射到其 whiten_advantages 参数),两步:
δ_t = r_t + γ·V_{t+1} − V_t,
A_t = δ_t + γλ·A_{t+1}(observation token 被 response_mask 跳过,V 和 TD 误差
都只在模型自己生成的 token 上传播);A ← (A − μ_batch) / √(σ²_batch + ε),其中 μ/σ² 是 64 条轨迹 ×
各自数千 response token 汇总的标量均值/方差(带 Bessel 修正),输出严格零均值、
单位方差。关键细节:critic 的回归目标(returns = 原始 A + V)在白化之前构建,白化只作用于 喂给 actor 的优势——所以它不污染价值学习,只改变策略梯度的中心和尺度。
代价与回退条件(为什么 2026-08-13 曾把它关掉):单 rollout 下没有组内对照, 白化的"批相对基线"叠在 critic 的价值基线之上,理论上是重复居中——批里其他 prompt 的难度会混进本 prompt 的优势里,引入跨任务噪声。当时假设 critic 会承担基线职责, r6 用实测(ev 常年 <0.3)推翻了这个假设。配置里写明的交还条件:ev 连续 ~20 步 保持 >0.4 后,后续 run 可以再试 False——即"critic 证明自己之前,白化不下岗"。
配套但非本质的:CRITIC_PPO_EPOCHS=2(critic 比 actor 更新快)、
ROLLOUT_IS_THRESHOLD=0.2_4.0、故意不加 scaffold 侧 think 限制(隔离 RL 侧修复
的因果贡献,用监控线 think-frac>0.15 兜底代替)。
按训练阶段各采样 N=80 条轨迹做的分类统计(早期 vs 后期):
| 行为指标 | 早期 | 后期 | 判读 |
|---|---|---|---|
| 编辑后回读该文件(read-back-after-edit) | ~65-70% | ~65-70% | 稳定,验证习惯保持 |
| 每轨迹编辑次数 | 4.7 | 8.0 | 上升:更多的迭代修改 |
| 每轨迹运行完整测试套件(pytest 等) | 88.8% | 57.0% | 下降,但见下行 |
python -c 内联执行(次数,全采样窗口) |
691 | 1018 | 大幅上升 |
| 任意代码执行(测试套件 ∪ 内联执行)占轨迹比 | 97.5% | 93.7% | 基本持平 |
核心结论:验证行为没有消失,而是换了形态——从"跑整套 pytest"迁移为"用
python -c / heredoc 做快速定点验证"。这是效率优化方向的漂移,不是验证习惯的
退化。唯一的关注项:最后四分之一阶段测试套件运行率降到 46.8%,如果 val 再次
进入平台期,这是第一个要检查的假设(是否在丢失回归测试的习惯)。
GRPO 腿的表现:num_turns 与 response length 双双上涨,CoT 长度 +30%, read-back 和测试套件运行比例上升。r7(SAO)的对照:
checkpoint.load_contents='[model,optimizer]'
跳过 scheduler,新建的 scheduler 会按配置 LR 生效(已验证:权重增量比值 1.954≈2)。