执行摘要
- 一句话:验证集 dump 加入 uid 字段并按 uid 排序
- 推荐动作:值得合并。作为数据可追溯性的必要修复,与训练路径保持行为一致。建议后续补充单元测试。
功能与动机
PR body 指出:validation JSONL 文件缺少 uid 字段,导致无法将 dump 结果追溯回源样本;而训练/rollout 路径已支持 uid 并按 uid 排序。该 PR 使验证路径与之一致。
实现拆解
- 排序索引构建:在
verl/trainer/main_ppo_sync.py 的 _validate 方法中,调用 _dump_generations 之前,使用 sorted(range(len(sample_uids)), key=lambda i: sample_uids[i]) 生成基于 uid 的排序索引。
- 数据重排:根据排序索引重新排列 inputs、outputs、gts、scores 和 reward_extra_infos_dict。
- 注入 uid:将 uid 字段加入 reward_extra_infos_dict。
- 调用 dump:将重排后的数据传给
_dump_generations。
关键文件:
verl/trainer/main_ppo_sync.py(模块 训练器;类别 source;类型 core-logic;符号 _validate): 核心变更文件,修改 _validate 方法,增加 uid 注入和排序逻辑。
关键符号:_validate
关键源码片段
verl/trainer/main_ppo_sync.py
核心变更文件,修改 _validate 方法,增加 uid 注入和排序逻辑。
# 在 _validate 方法中,dump 前添加排序和 uid 注入
val_data_dir = self.config.trainer.get("validation_data_dir", None)
if val_data_dir:
# 按 uid 排序,使同一样本的多条结果连续
sorted_indices = sorted(range(len(sample_uids)), key=lambda i: sample_uids[i])
dump_inputs = [sample_inputs[i] for i in sorted_indices]
dump_outputs = [sample_outputs[i] for i in sorted_indices]
dump_gts = [sample_gts[i] for i in sorted_indices]
dump_scores = [sample_scores[i] for i in sorted_indices]
# 重排 reward_extra_infos_dict 并加入 uid
dump_extra = {k: [v[i] for i in sorted_indices] for k, v in reward_extra_infos_dict.items()}
dump_extra["uid"] = [sample_uids[i] for i in sorted_indices]
self._dump_generations(
inputs=dump_inputs,
outputs=dump_outputs,
gts=dump_gts,
scores=dump_scores,
reward_extra_infos_dict=dump_extra,
dump_path=val_data_dir,
)
评论区精华
代码审查由 gemini-code-assist[bot] 完成,无反馈意见;仓库维护者 wuxibin89 直接批准。无实质性讨论。
风险与影响
- 风险:低风险。改动局限于
_validate 方法中向 dump 传参的部分,仅影响 dump 输出的顺序和额外字段,不影响指标计算或模型训练。但缺少测试覆盖。
- 影响:对用户:当设置了
trainer.validation_data_dir 时,生成的文件将包含 uid 并按 uid 排序,方便追溯和分析。对系统:无性能影响,排序操作在 CPU 上进行,数据量通常不大。
- 风险标记:缺少测试覆盖
关联脉络
- PR #6227 [trainer] fix: dump all outputs in validation in main_ppo_sync: 同一文件(main_ppo_sync.py)的验证阶段输出相关修复。
参与讨论