Conversation
|
@claude review |
|
Claude: Summary本 PR 将 RL 训练的 pack 规划( ProduceBatchResult impact: not affected —— RoutedExperts impact: affected —— padding 侧 routed-experts 构造从 controller 移入 Ray concurrency impact: not affected —— Main Flowchart after this PRflowchart TD
A[BaseRLTrainer._prepare_train_data<br/>产出 WorkerInputItem<br/>advantages 改为 Tensor] --> B[TrainingController.fit]
B --> C[提取 data_lengths]
C --> D[RLDataPacker.pack<br/>仅索引规划 + padding 统计]
D --> E[ray.put 整个 data_batches<br/>嵌套 ObjectRef 下发]
E --> F[TrainingWorker.fit<br/>ray.get 全量 batch]
F --> G[_materialize_packs<br/>按索引选样本]
G --> H[_single_pack<br/>SequenceContext.cat + 拼接]
H --> I[_create_padding_item<br/>全 padding 分支 routed-experts 出错]
I --> J[按 packed_batch_num_per_step 执行 optimizer step]
B --> K[返回 TrainingLogInfo<br/>pack_time / train_time / padding_tokens]
style D fill:#cde4ff
style G fill:#cde4ff
style E fill:#ffe4b5
style I fill:#ffb3b3
核心原理实现与单测
抽象与信息隐藏评估
单测建议
其他 IssuesCritical
Warning
VerdictREQUEST_CHANGES |
| if pad_len == self.config.pack_max_length: | ||
| pad_rand_index = torch.randint(low=0, high=1, size=(1, 1, 1)) | ||
| else: | ||
| pad_rand_index = torch.randint(low=0, high=self._pack_n_routed_experts, size=(pad_len, 1, 1)) |
There was a problem hiding this comment.
Claude: [正确性] [复杂] 全 padding pack(pack_indices 为空,由 _align_pack_count 与 greedy 的 total_pack_indices.extend([[] ...]) 产生)仍沿用旧的 size=(1,1,1) dummy。
旧代码里这个 dummy 就是该 item 自身的 seq_ctx,_add_rollout_routed_experts 走 tensor 分支并扩展到 pack_max_length;现在 padding item 一定会经过 SequenceContext.cat(worker.py:640),而 cat 把 rollout_routed_experts 收集成 list(sequence_context.py:356-357),于是 fit 走 list 分支只生成 size=(1, num_hidden_layers, num_experts_per_tok),随后 worker.py:559-561 的 rollout_routed_experts.size(0) == input_ids.size(1) 断言必然失败,开启 routed-experts 的 MoE RL 训练会崩溃。
建议去掉该特判,统一按 pad_len 构造:
| if pad_len == self.config.pack_max_length: | |
| pad_rand_index = torch.randint(low=0, high=1, size=(1, 1, 1)) | |
| else: | |
| pad_rand_index = torch.randint(low=0, high=self._pack_n_routed_experts, size=(pad_len, 1, 1)) | |
| pad_rand_index = torch.randint(low=0, high=self._pack_n_routed_experts, size=(pad_len, 1, 1)) |
RoutedExperts impact: 全 padding pack 的 routed-experts 张量长度与 input_ids 不一致,训练直接中断。
| @@ -286,7 +285,7 @@ def test_rl_train_with_sft(self): | |||
| train_controller.onload(target="all") | |||
| log_infos = train_controller.fit(data_batches, pack_max_length=1024, rollout_idx=1) | |||
There was a problem hiding this comment.
Claude: [测试] 该测试的 train_worker_cfg 用的是 pack_max_length=2048(本文件 L135),但 L280/286/316 仍传 pack_max_length=1024,会被 controller 新增的一致性校验(controller.py:81-84)直接抛 ValueError,测试必然失败。
…troller - AgentLoop.canonicalize_train_fields (base + localhost/sandbox overrides) builds the unified full-sequence train fields (input_ids/labels/logprobs) at generation time; semantic holes are baked into labels by the loops. - RolloutState drops response_mask; labels become the only supervision carrier. agent_loop_type records the producing loop class name and AGENTIC_AGENT_LOOP_TYPES discriminates agentic full-sequence samples. - TrainingController.fit accepts list[list[RolloutState]] and absorbs validation, session-clustered advantages, shift/tensorization, seq_ctx, teacher fields and data_info; BaseRLTrainer._prepare_train_data is gone. - calculate_group_effective_response_masks now bakes token staleness into labels in place (monotone, convergent) and its agentic exclusion uses agent_loop_type instead of the input_ids/labels presence heuristic.
…ut conversion - response_ids now denotes the contiguous suffix of input_ids after the prompt (env/tool tokens included) in every loop; localhost/sandbox export input_ids[len(prompt_ids):] so response_model_steps stay aligned with the full response region. - Token staleness baking becomes branch-free: effective mask = semantic mask (labels != -100 on the suffix) * per-token staleness mask; the zero-prompt suffix state becomes eligible and agent_loop_type plus AGENTIC_AGENT_LOOP_TYPES are removed. - data_info stats: prompt_len reports the original prompt length and response_len the supervised (LLM-generated) token count; env/tool injected tokens count in neither. - _rollout_groups_to_colate_items is phase-split into session reward clustering, group advantage estimation, per-state ColateItem conversion and data_info summarization.
3fb0dda to
35784b6
Compare
概述
本 PR 将 RL 训练数据准备重构为 controller 只做规划、worker 只做物化 的两层结构,并把数据准备与 agent loop 侧 meta-ready 的
RolloutState契约打通:controller 全程只读写write_train_meta元数据(长度、flag),不接触任何张量;TrainingWorker.fit按三段流水线完成张量构造与训练。总数据流:TrainingController.fit pipeline
各阶段输入输出:
_prepare_rollout_itemsrollout_groups: list[list[RolloutState]](只读 write_train_meta)_PreparedBatch:{rollout_items, advantages, batch_attr, cluster_rewards, distillation_reward_observations}_build_pack_planrollout_items(只读num_tokens)、advantages、worker_cfg、data_replicate_size_PackPlan:{dp_dispatches: dict[dp_rank, _DPRankDispatch], plan_log: dict[str, float]}dp_dispatches[dp_rank]worker.fit.remote(rollout_item_refs, advantages, pack_plan, batch_attr)_build_trainer_log_info_PreparedBatch+_PackPlan+log_infos: list[WorkerLogItem]data_info: dict[str, float](packing/*、advantages/*、rewards/*、worker 耗时 max)跨 Ray 边界的 worker 入参契约:
rollout_item_refs: list[ray.ObjectRef]:第 0 个元素是本 DP rank 的list[RolloutState],由data_replicate_size(= tp_size × sp_size)个 replica 共享,每 batch 只序列化一次advantages: list[float]:与解引用后的 state 列表逐一对齐pack_plan: DPRankPackIndices:本地[optimizer_step][pack][sample_index]索引计划,索引寻址解引用后的 state 列表batch_attr: TrainBatchAttr:{rollout_idx, use_3d_position_ids, pack_loss_keys, has_routed_experts};batch 内所有 worker 看到同一份,保证跨 rank collective 形状对称TrainingWorker.fit pipeline
各阶段输入输出:
list[RolloutState]+advantages+batch_attrlist[(seq_ctx: SequenceContext, loss_ctx: BaseRLLossContext)],全部 CPUpack_plan+batch_attrlist[list[(seq_ctx, loss_ctx)]],外层下标 = optimizer step,内层 = pack(空 pack 物化为全 padding pack)_fitrollout_idxWorkerLogItem(entropy、mismatch/IS metrics、train_metrics、packing_conversion_time_s/packing_pack_time_s)生命周期约定:loss_ctx 与 seq_ctx 同步流转 —— convert / pack 阶段都在 CPU 上构建,只有
_fit统一做.to(DEVICE)与sp_split(sp_mesh.size() > 1时);MTP ctx 必须用 sp 切分前的 device labels + 切分后的 seq_ctx 构建。其他改动
BaseRLLossConfig.build/DistillationLossConfig.build新增device参数(默认行为不变),支撑 CPU 侧构建 loss_ctx。XTUNER_DETERMINISTICgate)下沉到_legacy_pack/_greedy_pack各自实现内,RLDataPacker.pack()入口不再感知策略细节。RLTrainItem/RLLossInputs/data.py中间 proto;数据 proto 只剩 worker 公开的TrainBatchAttr和 controller 私有的_DPRankDispatch/_PackPlan/_PreparedBatch。测试
tests/rl/test_pack.py:四种 pack 策略与XTUNER_DETERMINISTICgate 行为tests/rl/test_rollout_to_train_item.py:convert 阶段布局/对齐/advantage 广播/teacher targets contracttests/rl/test_training_worker_rank.py:pack 阶段拼接、padding 值表、模板键、空 pack 与 CPU loss_ctx contracttests/rl/test_prepare_train_data.py:controller 侧 meta-ready 契约(prepare / pack plan / trainer log info)