|
Download docs/Embodied-Step-RL-Paper-Code-DeepDive.md from Wendy-Fly/ICML-2027: direct link, hf CLI and curl.
- Browser
- Download file 39.1 kB
-
https://huggingface.co/Wendy-Fly/ICML-2027/resolve/main/docs/Embodied-Step-RL-Paper-Code-DeepDive.md
- Command line
-
hf download hf://Wendy-Fly/ICML-2027/docs/Embodied-Step-RL-Paper-Code-DeepDive.md
-
curl -L -o Embodied-Step-RL-Paper-Code-DeepDive.md https://huggingface.co/Wendy-Fly/ICML-2027/resolve/main/docs/Embodied-Step-RL-Paper-Code-DeepDive.md
39.1 kB
| # EasyR1-V4-Embody 当前实现与两篇论文的完整串讲 | |
| 本文档把三件事串起来讲清楚: | |
| 1. arXiv:2505.22050, **Reinforced Reasoning for Embodied Planning**。 | |
| 2. arXiv:2605.27140v1, **StepOPSD: Step-Aware Online Preference Distillation for Agent Reinforcement Learning**。 | |
| 3. 当前仓库 `EasyR1-V4-Embody` 的代码实现,尤其是 `grpo_step`、`rule` step reward、`forward_proxy`、residual gate / prompt gate。 | |
| 结论先放在前面: | |
| ```text | |
| 2505.22050 是一个 embodied VLM 训练 recipe: | |
| SFT 初始化 + rule-based reward + GRPO/RFT,让 Qwen2.5-VL 学会输出多步可执行计划。 | |
| 2605.27140 StepOPSD 是一个 agent RL 信用分配算法: | |
| 把 OPSD teacher-student logp gap 放到 step/action span 上,做 GRPO advantage shaping。 | |
| 当前 EasyR1-V4-Embody 介于两者之间: | |
| 任务设定、数据和输出形式更像 2505.22050; | |
| 算法改动、step-level advantage shaping 和 forward_proxy 更像 StepOPSD; | |
| 同时又额外实现了 rule step reward、GT-reference teacher、additive advantage、action_id/action_name span control、residual/prompt gates。 | |
| ``` | |
| --- | |
| ## 1. 三个对象各自解决什么问题 | |
| ### 1.1 2505.22050 解决的是“怎么训练 embodied planner” | |
| 这篇论文的主问题是:开源 VLM 在具身场景里很难做长程、多步、视觉条件下的 planning。模型要看当前视觉 observation、历史动作、自然语言任务,然后输出后续 action sequence。 | |
| 它的方案是两阶段: | |
| ```text | |
| Stage 1: SFT | |
| 用强闭源模型 Gemini-2.0-flash 蒸馏出高质量 reasoning + plan 数据。 | |
| 让 Qwen2.5-VL-7B 先学会任务分解、空间常识、输出格式。 | |
| Stage 2: RFT / GRPO | |
| 构造 ALFRED 轨迹分解数据。 | |
| 对模型输出的多步 action plan 设计 rule-based reward。 | |
| 用 GRPO 做 reinforcement fine-tuning。 | |
| ``` | |
| 它的 reward 是规则式的: | |
| ```text | |
| R = R_format + R_accuracy | |
| R_format: | |
| JSON 结构是否正确; | |
| 必需字段是否存在; | |
| action_id / action_name 是否有效匹配。 | |
| R_accuracy: | |
| 按 action sequence 和 gold sequence 做 prefix matching。 | |
| 若连续匹配 n 步,gold 总长为 k: | |
| R(n; k) = n(n + 1) / (k(k + 1)) | |
| ``` | |
| 所以 2505.22050 的重点不是“OPSD 信号怎么改 advantage”,而是“具身规划任务上,SFT + 规则奖励 + GRPO 这条 pipeline 能不能训动”。 | |
| ### 1.2 StepOPSD 解决的是“长轨迹 sparse reward 怎么分给关键 step” | |
| StepOPSD 的主问题是 agent RL 的 credit assignment: | |
| ```text | |
| 一条长 rollout 可能因为一个局部 action 错了而失败。 | |
| 标准 GRPO 只有一个 terminal reward。 | |
| 这个 reward 被广播到整条 response 的所有 token。 | |
| 结果是:模型知道整条轨迹不好,但不知道是哪一步导致不好。 | |
| ``` | |
| StepOPSD 的核心流程: | |
| ```text | |
| rollout | |
| -> trajectory reward / GRPO advantage | |
| -> parse action-centered step spans | |
| -> hindsight teacher context rescoring | |
| -> compute token-level logp gap Delta | |
| -> convert Delta into bounded multiplicative weights | |
| -> reshape GRPO advantage | |
| -> policy update | |
| ``` | |
| 它的信号是: | |
| ```text | |
| Delta_{k,j} | |
| = log pi_T(z_{k,j} | hindsight context, prefix) | |
| - log pi_S(z_{k,j} | causal context, prefix) | |
| ``` | |
| 它的 advantage 注入方式是: | |
| ```text | |
| w_raw = 2 * sigmoid(sign(A) * Delta) | |
| w = clip(w_raw, 1 - alpha_clip, 1 + alpha_clip) | |
| A_tilde = (1 - lambda_mix) * A + lambda_mix * (w * A) | |
| ``` | |
| 关键性质: | |
| ```text | |
| w 始终为正。 | |
| 因此 StepOPSD 只改变原始 GRPO advantage 的 magnitude,不改变 sign。 | |
| 它是 sign-preserving 的 credit redistribution。 | |
| ``` | |
| StepOPSD 的 hindsight 来源主要是同一个 GRPO group 中的 successful peer trajectory;teacher 是 stale reference policy,避免 moving target。 | |
| ### 1.3 当前代码解决的是“one-shot embodied JSON plan 内部的 step credit assignment” | |
| 当前仓库的任务形态: | |
| ```text | |
| 输入: | |
| 图像 + human instruction + action history + action list | |
| 输出: | |
| 一次性生成完整 JSON: | |
| { | |
| "visual_state_description": "...", | |
| "reasoning_and_reflection": "...", | |
| "language_plan": [...], | |
| "executable_plan": [ | |
| {"action_id": 133, "action_name": "..."}, | |
| ... | |
| ] | |
| } | |
| ``` | |
| 注意:当前代码不是多轮在线环境交互。它是一行样本生成一整条后续 trajectory plan。 | |
| 代码里的核心目标: | |
| ```text | |
| 原来只有整条 trajectory 的 scalar reward。 | |
| 现在希望在同一条 response 内部,把不同 step 的 token 赋予不同 advantage。 | |
| A_token = A^E + omega * A^S | |
| A^E: | |
| 原始 GRPO episode advantage。 | |
| 来自整条轨迹 scalar reward 的组内归一化。 | |
| A^S: | |
| 新增 step-level per-token advantage。 | |
| 可以来自 rule action_id 匹配,也可以来自 forward_proxy teacher-student logp contrast。 | |
| ``` | |
| 因此,当前实现和 2505.22050 的任务设定很近,和 StepOPSD 的算法思想也很近。 | |
| --- | |
| ## 2. 当前代码端到端数据流 | |
| ### 2.1 Dataset:把 EB-ALFRED 样本变成 VLM prompt | |
| 主要文件: | |
| ```text | |
| verl/utils/dataset.py | |
| ``` | |
| 当前 embodied dataset 的 `__getitem__` 做了这些事: | |
| 1. 从 parquet 行里读: | |
| ```text | |
| instruction | |
| history | |
| action_id # 可用动作列表 | |
| image | |
| gt_bbox | |
| gt_action | |
| gt_input_text | |
| gt_action_close / gt_action_open 等字段保留在 row_dict 中 | |
| ``` | |
| 2. 构造 prompt: | |
| ```text | |
| You are Embodied-R1 ... | |
| Given the current visual state <image> ... | |
| Current context: {history} | |
| Action Descriptions and Validity Rules | |
| ... | |
| The available action names are: | |
| {actionlist} | |
| Output ONLY a valid JSON object: | |
| visual_state_description | |
| reasoning_and_reflection | |
| language_plan | |
| executable_plan | |
| ``` | |
| 3. 把 `<image>` 替换为 Qwen-VL 视觉占位: | |
| ```text | |
| <|vision_start|><|image_pad|><|vision_end|> | |
| ``` | |
| 4. 用 processor 编码图像和 prompt,生成: | |
| ```text | |
| input_ids | |
| attention_mask | |
| position_ids | |
| raw_prompt_ids | |
| multi_modal_data = {"images": raw_images} | |
| ground_truth = json.dumps(gt) | |
| ``` | |
| 这里的 `ground_truth` 不是直接的 `executable_plan` list,而是一个包装后的 JSON,内部包含: | |
| ```text | |
| action | |
| gt_bbox | |
| input_text | |
| gt_open_ans | |
| ``` | |
| 其中 `input_text` 里还能解析出 GT 的 `executable_plan`。 | |
| ### 2.2 Rollout:模型一次性生成 response | |
| 训练主循环在: | |
| ```text | |
| verl/trainer/ray_trainer.py | |
| ``` | |
| 核心顺序: | |
| ```text | |
| prepare_rollout_engine | |
| -> _make_batch_data | |
| -> release_rollout_engine | |
| -> _balance_batch | |
| -> compute_reward | |
| -> compute_old_log_probs | |
| -> compute_ref_log_probs | |
| -> build step_adv_raw if adv_estimator == grpo_step | |
| -> compute_advantage | |
| -> update actor | |
| ``` | |
| 这里的 response 是完整 JSON plan,不是一步环境 action。 | |
| ### 2.3 Trajectory-level reward:verify model 给整条计划打分 | |
| 主要文件: | |
| ```text | |
| verl/workers/reward/function.py | |
| verl/workers/reward/verify.py | |
| ``` | |
| `compute_reward_batch` 的行为是: | |
| 1. decode response。 | |
| 2. 尝试解析 JSON。 | |
| 3. 从 response 中提取: | |
| ```text | |
| executable_plan | |
| ``` | |
| 4. 从 ground truth 中提取: | |
| ```text | |
| ground_truth_open = json.loads(ground_truth["input_text"])["executable_plan"] | |
| ``` | |
| 5. 构造 verify prompt: | |
| ```text | |
| Sentence 1: {GT executable_plan} | |
| Sentence 2: {pred executable_plan} | |
| You are judging whether a predicted embodied action trajectory matches | |
| the ground-truth trajectory at the intent level. | |
| Focus on FUNCTIONAL EQUIVALENCE ... | |
| Compare mainly by action_name, not exact action_id. | |
| Be lenient about extra/missing find steps ... | |
| Only output: True or False. | |
| ``` | |
| 6. 调用 `ask_llm`,用 verify VLM 生成一个 token,取 True / False 相关概率。 | |
| 7. 得到: | |
| ```text | |
| format = 1.0 if JSON parse ok else 0.0 | |
| accuracy = verify probability, False 会转成负值 | |
| overall = 0.8 * accuracy + 0.2 * format | |
| ``` | |
| 8. 把 `overall` 写到最后一个 response token: | |
| ```text | |
| reward_tensor[i, cur_response_length - 1] = score["overall"] | |
| ``` | |
| 这意味着整条 trajectory 的 reward 在张量里仍然是一个 terminal scalar。 | |
| ### 2.4 原始 GRPO:A^E 怎么来 | |
| 主要文件: | |
| ```text | |
| verl/trainer/core_algos.py | |
| ``` | |
| 标准 GRPO advantage 逻辑是: | |
| ```text | |
| scores = token_level_rewards.sum(-1) | |
| 按 uid 分组: | |
| 同一个 prompt 的 n 条 rollout 共享 uid。 | |
| 对每个 uid group: | |
| A^E_i = (R_i - mean(R_group)) / (std(R_group) + eps) | |
| 然后: | |
| A^E_i 广播到该 response 的所有有效 token。 | |
| ``` | |
| 所以没有 step reward 时,同一条 response 里的每个 token 都拿同一个 advantage。 | |
| 这正是当前工作要改的地方。 | |
| ### 2.5 grpo_step:在 A^E 上加 A^S | |
| 主要文件: | |
| ```text | |
| verl/trainer/core_algos.py | |
| verl/trainer/ray_trainer.py | |
| verl/trainer/step_reward.py | |
| ``` | |
| 新增 estimator: | |
| ```text | |
| AdvantageEstimator.GRPO_STEP = "grpo_step" | |
| ``` | |
| 核心函数: | |
| ```python | |
| episode_adv, _ = compute_grpo_outcome_advantage(...) | |
| if step_adv_raw is None: | |
| return episode_adv, episode_adv | |
| step_adv = step_adv_raw * response_mask | |
| advantages = episode_adv + step_advantage_w * step_adv | |
| return advantages, advantages | |
| ``` | |
| 公式就是: | |
| ```text | |
| A_token = A^E + omega * A^S_token | |
| ``` | |
| 其中: | |
| ```text | |
| A^E: | |
| 仍然是原始 GRPO,完全复用。 | |
| A^S: | |
| shape = (bs, response_length) | |
| response 内不同 token 可以不同。 | |
| 解析失败、scaffolding、非目标 token 为 0。 | |
| ``` | |
| 这个点非常关键:当前实现不是额外加一个 KL loss,也不是重写 GRPO,而是在 advantage 估计阶段加一条旁路信号。 | |
| --- | |
| ## 3. step_adv_raw 的两条来源 | |
| 当前代码把 `step_adv_raw` 做成可切换的: | |
| ```yaml | |
| algorithm.adv_estimator: grpo_step | |
| algorithm.step_reward_kind: rule | forward_proxy | |
| ``` | |
| ### 3.1 Rule:硬规则 step reward | |
| 文件: | |
| ```text | |
| verl/trainer/step_reward.py | |
| ``` | |
| 入口: | |
| ```text | |
| build_step_adv_raw | |
| -> build_step_adv_vector | |
| -> compute_step_match_rewards | |
| ``` | |
| 流程: | |
| 1. decode response。 | |
| 2. 容错解析 `executable_plan`。 | |
| 3. 解析 GT: | |
| ```text | |
| gt_steps_from_close(gt_close) | |
| ``` | |
| 4. 对 predicted steps 和 GT steps 做匹配。 | |
| 支持三种匹配: | |
| ```text | |
| exact: | |
| pred[i] == gt[i] 才算对。 | |
| prefix: | |
| 最长正确前缀;第一个错后面全算错。 | |
| lcs: | |
| longest common subsequence,对顺序扰动更宽松。 | |
| ``` | |
| 默认匹配键: | |
| ```yaml | |
| algorithm.step_match_key: action_id | |
| ``` | |
| reward 转 advantage: | |
| ```text | |
| 匹配:+1 | |
| 不匹配:-1 | |
| scaffolding / 非 step token:0 | |
| 解析失败:整条 A^S = 0,退化为纯 GRPO | |
| ``` | |
| 这条路和 2505.22050 很接近:都是用 GT action sequence 做 rule-based correctness signal。 | |
| 但也有差别: | |
| ```text | |
| 2505.22050: | |
| rule reward 先变成 response-level scalar reward,再进入 GRPO。 | |
| prefix reward R(n;k) 是整条 response 的 reward。 | |
| 当前代码 rule: | |
| rule reward 直接变成 per-token step advantage A^S。 | |
| 一条 response 内部可以前两步 +1,第三步 -1。 | |
| ``` | |
| 也就是说,当前 rule 比 2505.22050 更细:不是只给整条轨迹一个分,而是把 step 对错广播到对应 token。 | |
| ### 3.2 Forward Proxy:GT-aware teacher-student logp contrast | |
| 文件: | |
| ```text | |
| verl/trainer/teacher_proxy.py | |
| verl/workers/reward/function.py | |
| verl/workers/reward/verify.py | |
| verl/trainer/step_reward.py | |
| ``` | |
| 配置: | |
| ```yaml | |
| algorithm.step_reward_kind: forward_proxy | |
| algorithm.step_squash: contrast | |
| algorithm.step_teacher_path: ... | |
| algorithm.step_score_source: action_name | action_id | semantic | |
| algorithm.step_credit_target: action_name | action_id | semantic | |
| ``` | |
| #### 3.2.1 为什么要跑在 reward actor 上 | |
| 最初如果在 driver 上做 teacher forward,会遇到: | |
| ```text | |
| driver 进程没有 GPU。 | |
| verl/Ray 中 GPU 分给 worker actor。 | |
| teacher.to("cuda") 会失败。 | |
| ``` | |
| 所以当前代码把 forward_proxy 放到 reward actor: | |
| ```text | |
| ray.get(self.reward_fn.compute_step_adv.remote(...)) | |
| ``` | |
| reward actor 本来就有 verify model 的 GPU 资源,因此可以 lazy-load teacher scorer。 | |
| #### 3.2.2 TeacherLogpScorer 做什么 | |
| `TeacherLogpScorer.logp_teacher_student` 对同一段 predicted response tokens 跑两次 forward: | |
| ```text | |
| teacher context: | |
| image + "Here is a reference successful language plan:" | |
| + GT reference plan | |
| + transition | |
| + predicted response tokens | |
| student context: | |
| image + "Problem: {instruction}" | |
| + student instruction | |
| + predicted response tokens | |
| ``` | |
| 返回: | |
| ```text | |
| teacher_logp[t] = log p_model(response_token_t | image, GT context, response_prefix) | |
| student_logp[t] = log p_model(response_token_t | image, problem context, response_prefix) | |
| ``` | |
| 然后: | |
| ```text | |
| Delta_t = teacher_logp[t] - student_logp[t] | |
| ``` | |
| 这个 Delta 的语义是: | |
| ```text | |
| 如果模型看了 GT 后更支持这个 response token,Delta 为正。 | |
| 如果模型看了 GT 后更不支持这个 response token,Delta 为负。 | |
| ``` | |
| #### 3.2.3 当前代码里的一个重要现实:teacher 不一定等于 policy | |
| `teacher_proxy.py` 和 `config.py` 的注释里仍然写着: | |
| ```text | |
| teacher should be same path as policy | |
| same tokenizer, true OPSD self-distillation | |
| ``` | |
| 但当前运行脚本 `examples/qwen25_vl_3b_Domain.sh` 实际是: | |
| ```text | |
| policy = Qwen2.5-VL-3B-RobotGPT-R1 | |
| teacher = Qwen2.5-VL-3B-Instruct | |
| ``` | |
| 这意味着当前 forward_proxy 的真实语义不是严格的“policy 自蒸馏 OPSD”,而是: | |
| ```text | |
| 冻结外部 Instruct teacher 在 GT context 和 no-GT context 下的 logp contrast。 | |
| ``` | |
| 这点要在论文/报告中说准。 | |
| 如果 teacher 等于 policy: | |
| ```text | |
| 更像原始 OPSD / self-distillation。 | |
| 但实测容易因为 policy 对自己生成的 token 过度自信而 logp diff 塌平。 | |
| ``` | |
| 如果 teacher 是未微调 Instruct: | |
| ```text | |
| 信号更容易有波动。 | |
| 但它不再代表 policy 自己的 preference shift; | |
| 而是外部 teacher 的 GT-conditioned preference shift。 | |
| ``` | |
| 当前 `step_adv_heatmaps/_diag.txt` 中能看到 forward_proxy 已有波动,例如: | |
| ```text | |
| std ~= 0.9 - 2.3 | |
| mean 通常为正 | |
| min/max 可到约 -15 / +13 | |
| ``` | |
| 这说明“信号活了”,但不自动说明“信号方向一定奖对惩错”。 | |
| #### 3.2.4 Delta 怎么变成 step score | |
| 文件: | |
| ```text | |
| verl/trainer/step_reward.py | |
| build_step_adv_vector_from_logp | |
| ``` | |
| 先选 score tokens: | |
| ```yaml | |
| step_score_source: | |
| action_name # 默认 | |
| action_id | |
| semantic # action_id + action_name | |
| ``` | |
| 对这些 token 聚合: | |
| ```text | |
| contrast 模式: | |
| token_signal = teacher_logp - student_logp | |
| raw_step = robust_mean(token_signal over score tokens) | |
| score = tanh(normalize(raw_step) / score_tau) | |
| prob 模式: | |
| score = 2 * exp(mean teacher_logp) - 1 | |
| ``` | |
| 代码和实验笔记都说明:`prob` 容易恒平,因为 GT-conditioned teacher 对很多 token 都很自信;真正有意义的是 `contrast`。 | |
| #### 3.2.5 score 写回哪些 token | |
| 再选 credit target: | |
| ```yaml | |
| step_credit_target: | |
| action_name | |
| action_id | |
| semantic | |
| ``` | |
| 默认 `action_name`,一些 ablation 用: | |
| ```yaml | |
| step_score_source: semantic | |
| step_credit_target: action_id | |
| step_action_name_weight: 0.0 | |
| ``` | |
| 这个设计很重要: | |
| ```text | |
| score_source 决定“用哪些 token 判断这一步好坏”。 | |
| credit_target 决定“训练时把 advantage 写到哪些 token 上”。 | |
| ``` | |
| 例如: | |
| ```text | |
| score_source = semantic: | |
| 用 action_id + action_name 一起估计这步是否被支持。 | |
| credit_target = action_id: | |
| 主要更新离散动作选择,而不是训练自然语言措辞。 | |
| ``` | |
| 这是当前实现相对 StepOPSD 的一个具身 JSON plan 特化点。 | |
| --- | |
| ## 4. Token span 对齐:当前实现的工程核心 | |
| step reward 最终要进入 PPO/GRPO loss,因此必须是 token 级。 | |
| 当前代码做了以下事情: | |
| ```text | |
| response_ids | |
| -> decode response text | |
| -> extract executable_plan | |
| -> locate each step's action_id / action_name character span | |
| -> map character span back to token indices | |
| -> write step score into selected token positions | |
| ``` | |
| 主要函数: | |
| ```text | |
| extract_plan_steps | |
| pred_step_token_spans | |
| _token_char_offsets | |
| _find_action_id_value_span | |
| _find_action_name_value_span | |
| _select_span_tokens | |
| ``` | |
| ### 4.1 JSON 解析 | |
| `extract_plan_steps` 能处理: | |
| ```text | |
| 正常 JSON dict | |
| 带 json 标记的 fenced code block | |
| 前后有散文的 response | |
| 尾部 <|im_end|> / <|endoftext|> | |
| bare list | |
| ``` | |
| 解析失败返回 `None`,后续整条 A^S 为 0。 | |
| ### 4.2 char offset | |
| `_token_char_offsets` 先尝试: | |
| ```text | |
| tokenizer(text, return_offsets_mapping=True) | |
| ``` | |
| 如果 re-tokenize 后 input_ids 和原始 response_ids 一致,就用 tokenizer offset。 | |
| 如果不一致,则降级为 prefix decode: | |
| ```text | |
| 逐 token decode ids[:t+1] | |
| 用字符串长度差构造 offsets | |
| ``` | |
| 这样比“decode 后重编码”更稳,因为 Qwen/VL tokenizer 在 special token、空格清理、JSON 标点附近可能 round-trip 不一致。 | |
| ### 4.3 step span | |
| 代码先找到 `"executable_plan":` 后面的 list 起点,然后按顺序找每一步: | |
| ```text | |
| action_id value span | |
| action_name value span | |
| ``` | |
| 每个 step 得到: | |
| ```python | |
| StepTokenSpans( | |
| action_id_tokens=[...], | |
| action_name_tokens=[...], | |
| ) | |
| ``` | |
| 然后根据配置选择: | |
| ```text | |
| action_id tokens | |
| action_name tokens | |
| semantic tokens = action_id + action_name | |
| ``` | |
| ### 4.4 当前 span 设计与 StepOPSD 的差别 | |
| StepOPSD 面向的是一般 agent trajectory,常见 span 是: | |
| ```text | |
| <action>...</action> | |
| clean_step_no_observation | |
| ``` | |
| 当前代码面向的是 embodied JSON plan,span 是: | |
| ```text | |
| action_id value | |
| action_name value | |
| ``` | |
| 所以当前实现对 `executable_plan` 的结构假设更强,但也更精确:可以只训练 action id,不训练 JSON scaffold 或语言描述。 | |
| --- | |
| ## 5. Gate 扩展:控制 forward_proxy 信号进来的位置和强度 | |
| 当前代码不止有 plain forward_proxy,还实现了两类 gate。 | |
| ### 5.1 Residual contrast gate | |
| 配置: | |
| ```yaml | |
| algorithm.step_gate: residual_contrast | |
| algorithm.step_gate_residual: response_median | |
| algorithm.step_gate_threshold: 0.0 | |
| algorithm.step_gate_tau: 1.0 | |
| algorithm.step_budget_tau: 1.0 | |
| algorithm.step_min_score_tokens: 2 | |
| ``` | |
| 逻辑: | |
| 1. 先对 token_signal 去 response-level median: | |
| ```text | |
| d'_t = d_t - median(d over valid response tokens) | |
| ``` | |
| 2. 每步算 raw score: | |
| ```text | |
| raw_k = robust_mean(d'_t over score tokens) | |
| soft_score_k = tanh(z_k / score_tau) | |
| ``` | |
| 3. 再用 unsigned contrast 估计 importance: | |
| ```text | |
| imp_k = robust_mean(abs(d'_t) over score tokens) | |
| ``` | |
| 4. 组合三个 gate: | |
| ```text | |
| decision_gate = sigmoid((imp_z - threshold) / gate_tau) | |
| budget_gate = clamp(softmax(imp / budget_tau) * num_steps, 0, 1) | |
| confidence = len_gate * var_gate | |
| gate_k = decision_gate * budget_gate * confidence | |
| ``` | |
| 5. 最终: | |
| ```text | |
| A^S_k = gate_k * soft_score_k | |
| ``` | |
| 直觉: | |
| ```text | |
| soft_score 决定方向:支持还是反对。 | |
| gate 决定强度:这一步是否值得更新。 | |
| ``` | |
| ### 5.2 Prompt gate | |
| 配置: | |
| ```yaml | |
| algorithm.step_gate: prompt | |
| algorithm.step_prompt_gate_mode: generation | |
| algorithm.step_prompt_gate_model_path: ... | |
| algorithm.step_prompt_kl_weight: ... | |
| algorithm.step_use_prompt_causal_gate: true | |
| algorithm.step_use_prompt_redundancy_gate: true | |
| ``` | |
| `PromptGateScorer` 会让 judge 输出每个 predicted step 的: | |
| ```json | |
| { | |
| "decision_gate": 0.0, | |
| "redundancy_gate": 0.0, | |
| "causal_gate": 0.0, | |
| "prompt_kl_score": 0.0, | |
| "reason": "..." | |
| } | |
| ``` | |
| 代码把 gate 合成: | |
| ```text | |
| gate = decision * (1 - redundancy) * (0.5 + 0.5 * causal) | |
| ``` | |
| 并可把 prompt score 加进 supervised KL score: | |
| ```text | |
| supervised_scores = | |
| step_supervised_kl_weight * supervised_scores | |
| + step_prompt_kl_weight * prompt_scores | |
| ``` | |
| 这个版本的目标是处理 residual contrast 看不懂的情况: | |
| ```text | |
| 某步 KL 波动很大,但其实只是冗余 find; | |
| 某步看起来错,但由于前一步已经错了,后续动作不该被强烈惩罚; | |
| 某步是关键 causal action,应该放大。 | |
| ``` | |
| 这已经超出 StepOPSD 原始设计,属于当前实现的额外探索。 | |
| --- | |
| ## 6. 当前实现与 2505.22050 的详细对比 | |
| ### 6.1 共同点 | |
| 两者共同点很多: | |
| ```text | |
| 都做 embodied planning。 | |
| 都使用 Qwen2.5-VL 系列。 | |
| 都要求模型输出结构化 multi-step plan。 | |
| 都使用 GRPO/RFT。 | |
| 都重视 action sequence 的正确性。 | |
| 都有格式约束。 | |
| 都不直接在真实机器人上训练。 | |
| ``` | |
| ### 6.2 数据和任务形式 | |
| 2505.22050: | |
| ```text | |
| 训练: | |
| SFT 数据来自 Gemini-2.0-flash 蒸馏。 | |
| RFT 数据来自 ALFRED 轨迹分解。 | |
| 评测: | |
| Embench。 | |
| EB-ALFRED seen。 | |
| EB-Habitat unseen。 | |
| 模型: | |
| Qwen2.5-VL-7B。 | |
| ``` | |
| 当前代码: | |
| ```text | |
| 训练文件: | |
| eb_alfred_success_opsd_cot_multimodal_v2_embody.parquet | |
| 输入: | |
| 当前图像 + instruction + history + action list。 | |
| 输出: | |
| 一次性完整 JSON plan。 | |
| policy: | |
| Qwen2.5-VL-3B-RobotGPT-R1。 | |
| teacher for forward_proxy: | |
| Qwen2.5-VL-3B-Instruct。 | |
| ``` | |
| 因此,当前代码更像把 2505.22050 的 embodied planning setting 改成了 3B policy + EasyR1/verl 风格训练。 | |
| ### 6.3 Reward 设计差异 | |
| 2505.22050 的 reward: | |
| ```text | |
| R_total = R_format + R_accuracy | |
| R_accuracy = prefix curve n(n+1)/k(k+1) | |
| ``` | |
| 它是 response-level reward。即使 accuracy 来自 step prefix,最后仍然变成一个 scalar reward 给 GRPO。 | |
| 当前代码的 reward 分两层: | |
| ```text | |
| trajectory-level reward: | |
| verify model 判断 pred plan 与 GT plan 是否 functional equivalent。 | |
| overall = 0.8 * verify + 0.2 * format。 | |
| 写到最后一个 token。 | |
| step-level A^S: | |
| rule: action_id exact/prefix/lcs -> per-token +/-1。 | |
| forward_proxy: teacher-student logp contrast -> per-token [-1,1]。 | |
| ``` | |
| 也就是说,当前代码比 2505.22050 多了一个显式 step advantage 通道。 | |
| ### 6.4 GRPO 使用方式差异 | |
| 2505.22050: | |
| ```text | |
| GRPO 直接用 composite reward。 | |
| 每条 sampled response 得一个 reward。 | |
| 组内归一化后更新整条 response。 | |
| ``` | |
| 当前代码: | |
| ```text | |
| GRPO 仍然用 trajectory reward 得到 A^E。 | |
| 但在 compute_advantage 之前额外构造 step_adv_raw。 | |
| 最终 A = A^E + omega * A^S。 | |
| ``` | |
| 所以当前实现是: | |
| ```text | |
| GRPO + per-token step advantage shaping | |
| ``` | |
| 而不是单纯的: | |
| ```text | |
| GRPO + rule scalar reward | |
| ``` | |
| ### 6.5 输出格式差异 | |
| 2505.22050 论文要求输出类似: | |
| ```text | |
| visual_state_description | |
| reasoning_and_reflection | |
| language_plan | |
| executable_plan | |
| ``` | |
| 当前代码的 prompt 也要求这些字段,而且 reward JSON parser 优先取 `executable_plan`。 | |
| 但当前代码的 step credit 只关注 `executable_plan` 中的: | |
| ```text | |
| action_id | |
| action_name | |
| ``` | |
| 不会给 `visual_state_description`、`reasoning_and_reflection`、`language_plan` 里的 token 直接加 step advantage。 | |
| 这和当前方法目标一致:训练动作决策,而不是训练解释文本。 | |
| --- | |
| ## 7. 当前实现与 StepOPSD 的详细对比 | |
| ### 7.1 最大共同点 | |
| 两者都可以概括为: | |
| ```text | |
| step-aware advantage shaping for GRPO。 | |
| ``` | |
| 更具体: | |
| ```text | |
| 都不是把 teacher signal 单独做一个 KL/distillation loss。 | |
| 都在 rollout 完成后处理 sampled response。 | |
| 都解析 step/action span。 | |
| 都把局部 step 信号注入 policy gradient 的 advantage 通道。 | |
| 都试图修正 trajectory-level sparse reward 的信用分配问题。 | |
| ``` | |
| 如果当前论文主方法强调 `forward_proxy`,那和 StepOPSD 的相似度很高,不能写成“完全不同路线”。 | |
| ### 7.2 Hindsight / teacher 来源 | |
| StepOPSD: | |
| ```text | |
| teacher context = causal prefix + peer-trajectory hindsight | |
| teacher model = stale reference policy | |
| peer-trajectory hindsight: | |
| 同一个 GRPO group 中,如果有成功 rollout, | |
| 用第一个成功 peer 给失败 trajectory 提供 hindsight。 | |
| ``` | |
| 当前 forward_proxy: | |
| ```text | |
| teacher context = image + GT reference plan + transition | |
| student context = image + problem instruction | |
| teacher model = step_teacher_path 指定的模型 | |
| ``` | |
| 当前脚本实际: | |
| ```text | |
| teacher = 未微调 Qwen2.5-VL-3B-Instruct | |
| policy = Qwen2.5-VL-3B-RobotGPT-R1 | |
| ``` | |
| 差异: | |
| ```text | |
| StepOPSD 更通用: | |
| 不要求数据集中有显式 GT action plan。 | |
| 只要 group 里有 successful peer。 | |
| 当前代码监督更强: | |
| 直接使用数据集 GT reference plan。 | |
| 更适合 EB-ALFRED 这种有 reference trajectory 的任务。 | |
| ``` | |
| ### 7.3 Delta 到 advantage 的变换方式 | |
| StepOPSD: | |
| ```text | |
| Delta -> token weight w | |
| w > 0 | |
| A_tilde = (1-lambda)A + lambda(wA) | |
| ``` | |
| 性质: | |
| ```text | |
| 只改变 A 的大小。 | |
| 不改变 A 的正负。 | |
| 如果整条 trajectory 的 GRPO advantage 是负的, | |
| 局部 step 也不会被改成正方向,只能少罚或多罚。 | |
| ``` | |
| 当前代码: | |
| ```text | |
| Delta -> step scalar A^S_k = tanh(...) | |
| A = A^E + omega * A^S_k | |
| ``` | |
| 性质: | |
| ```text | |
| 可以改变局部 token 的训练方向。 | |
| 如果整条 trajectory A^E 为负,但某一步 rule/teacher 认为是对的, | |
| 该 step 的 token 可能被加到正方向。 | |
| 如果整条 trajectory A^E 为正,但某一步是错的, | |
| 该 step 的 token 可能被拉成负方向。 | |
| ``` | |
| 这是当前实现和 StepOPSD 最核心的算法差异: | |
| ```text | |
| StepOPSD: | |
| sign-preserving multiplicative reweighting。 | |
| 当前代码: | |
| additive local step advantage。 | |
| ``` | |
| ### 7.4 step 粒度 | |
| StepOPSD: | |
| ```text | |
| token-level Delta | |
| token-level weight | |
| step normalization 用来控制每个 step 的 credit budget | |
| ``` | |
| 当前代码: | |
| ```text | |
| 先把 token_signal 聚合成 step scalar。 | |
| 再把 step scalar 写回 action_id/action_name/semantic tokens。 | |
| ``` | |
| 当前代码更强调: | |
| ```text | |
| step 是决策单位。 | |
| token 只是承载这个 step 决策的优化位置。 | |
| ``` | |
| 这和 embodied action plan 更匹配,因为 `{"action_id": 133, "action_name": ...}` 整体是一个动作选择。 | |
| ### 7.5 span 定义 | |
| StepOPSD: | |
| ```text | |
| ALFWorld: | |
| action_only | |
| Search-QA: | |
| clean_step_no_observation | |
| ``` | |
| 当前代码: | |
| ```text | |
| pred_step_token_spans: | |
| action_id_tokens | |
| action_name_tokens | |
| semantic_tokens = union | |
| ``` | |
| 这不是泛化的 agent transcript span,而是 embodied JSON plan 的结构化 span。 | |
| ### 7.6 normalization / clipping | |
| StepOPSD 有两个核心 knob: | |
| ```text | |
| alpha_clip: | |
| 控制局部 weight trust region。 | |
| lambda_mix: | |
| 控制 shaped signal 与原始 advantage 的混合强度。 | |
| ``` | |
| 当前代码的 knob: | |
| ```text | |
| step_advantage_w: | |
| A^S 总权重 omega。 | |
| step_score_tau: | |
| tanh 温度。 | |
| step_score_norm: | |
| none / per_response。 | |
| step_gate: | |
| none / residual_contrast / prompt。 | |
| step_budget_tau: | |
| residual gate 的 per-response budget 控制。 | |
| ``` | |
| 当前代码没有实现 StepOPSD 同款: | |
| ```text | |
| w = clip(2 * sigmoid(sign(A) * Delta), 1-alpha, 1+alpha) | |
| ``` | |
| 也没有完全等价的: | |
| ```text | |
| equal_step_mean_abs | |
| ``` | |
| 但 residual gate 里的 budget gate 有类似“不要让所有 step 都满强度更新”的意图。 | |
| ### 7.7 对原始 rollout 的干预 | |
| 两者都不改 rollout: | |
| ```text | |
| 先采样 rollout。 | |
| 再做 post-rollout step credit。 | |
| 最后更新 policy。 | |
| ``` | |
| 这点是共同点。 | |
| --- | |
| ## 8. 当前实现的优点、风险和需要说准的地方 | |
| ### 8.1 优点 | |
| #### 优点 1:把 trajectory reward 和 step credit 分开 | |
| 当前实现没有破坏原始 verify reward: | |
| ```text | |
| verify reward 仍然决定整条 trajectory 的 A^E。 | |
| step reward 只作为 A^S 叠加。 | |
| ``` | |
| 因此: | |
| ```text | |
| omega = 0 可以退回纯 GRPO。 | |
| 解析失败可以 A^S=0,不影响主训练。 | |
| ``` | |
| #### 优点 2:rule step reward 对当前任务非常强 | |
| 因为 action space 是离散的 `action_id`,且 GT 中有 reference trajectory: | |
| ```text | |
| action_id exact/prefix/lcs 是直接的 correctness signal。 | |
| ``` | |
| 相比 forward_proxy,它: | |
| ```text | |
| 不需要额外 teacher。 | |
| 不占 GPU。 | |
| 不会自蒸馏塌平。 | |
| 不会把“像正确动作的错误动作”误判为正。 | |
| ``` | |
| #### 优点 3:forward_proxy 是一个活的软信号对照 | |
| 当前诊断显示 teacher-student logp diff 不再全平: | |
| ```text | |
| std 约 1-2 | |
| min/max 有明显波动 | |
| ``` | |
| 这意味着 forward_proxy 至少具备可训练信号,不是全 0 对照。 | |
| #### 优点 4:action_id/action_name 分离很适合 embodied plan | |
| 当前代码可以: | |
| ```text | |
| 用 semantic tokens 算分。 | |
| 只把 credit 写到 action_id token。 | |
| 不给 JSON scaffold 梯度。 | |
| ``` | |
| 这比直接对整段 JSON 做 KL 更贴近“动作选择”。 | |
| ### 8.2 风险 | |
| #### 风险 1:forward_proxy 的 Delta 不等于动作正确性 | |
| Delta 表示: | |
| ```text | |
| teacher 看 GT 后是否更愿意生成这个 token。 | |
| ``` | |
| 它不一定表示: | |
| ```text | |
| 这个 action 是否真的等于 GT action。 | |
| ``` | |
| 典型问题: | |
| ```text | |
| GT 是 find DiningTable。 | |
| 预测是 find Sofa。 | |
| teacher 可能因为 "find a furniture" 这个模式合理而给正 Delta。 | |
| ``` | |
| 所以 forward_proxy 的正确性需要专门验证,不能只看 diff std。 | |
| #### 风险 2:外部 teacher 改变了 OPSD 语义 | |
| 如果 teacher 是 `Qwen2.5-VL-3B-Instruct`,policy 是 `RobotGPT-R1`: | |
| ```text | |
| Delta = Instruct(GT context) - Instruct(no-GT context) | |
| ``` | |
| 而不是: | |
| ```text | |
| Delta = policy_or_stale_ref(GT context) - policy(causal context) | |
| ``` | |
| 这在论文写法上必须说明,否则会被质疑“这不是 StepOPSD/OPSD 的同模型 rescoring”。 | |
| #### 风险 3:additive advantage 可能过强 | |
| 当前: | |
| ```text | |
| A = A^E + omega * A^S | |
| ``` | |
| 如果 `omega=1`,而 A^E 的 group-normalized magnitude 也大约在 0-1 附近,A^S 可能显著改变更新方向。 | |
| 这既是能力,也是风险: | |
| ```text | |
| 能力: | |
| 能在失败轨迹里保留正确 step。 | |
| 风险: | |
| 如果 A^S 判错,会直接反向更新局部动作。 | |
| ``` | |
| StepOPSD 的 sign-preserving 设计更保守,当前 additive 设计更激进。 | |
| #### 风险 4:rule exact 可能太硬 | |
| `action_id` exact 对当前任务很干净,但也可能: | |
| ```text | |
| 对等价替代路径不宽容。 | |
| 对多余 find / 顺序轻微变化不宽容。 | |
| 对 object instance 探索不宽容。 | |
| ``` | |
| 代码已经提供 `prefix` 和 `lcs`,但默认 `exact`,需要用实验比较。 | |
| --- | |
| ## 9. 三方总表 | |
| | 维度 | 2505.22050 | StepOPSD | 当前 EasyR1-V4-Embody | | |
| |---|---|---|---| | |
| | 主问题 | 训练 embodied VLM planner | agent RL credit assignment | one-shot embodied JSON plan 的 step credit assignment | | |
| | 基础算法 | SFT + GRPO/RFT | GRPO + step-aware OPSD shaping | GRPO + additive step advantage | | |
| | 模型 | Qwen2.5-VL-7B | Qwen3-1.7B / Qwen2.5-3B | Qwen2.5-VL-3B RobotGPT-R1 | | |
| | 任务 | Embench / EB-ALFRED / EB-Habitat | ALFWorld / Search-QA | EB-ALFRED parquet embodied planning | | |
| | 输出 | structured reasoning + executable_plan | agent trajectory / actions / search steps | JSON with executable_plan | | |
| | trajectory reward | rule format + prefix accuracy | env/QA reward | verify VLM functional equivalence + format | | |
| | step 信号 | prefix correctness 汇总成 scalar | teacher-student logp gap | rule action_id 或 forward_proxy logp gap | | |
| | step 信号进入方式 | 作为 response reward 的一部分 | multiplicative reweight A | additive A = A^E + omega A^S | | |
| | 是否保留 A 符号 | GRPO scalar reward 决定 | 是 | 否,可能局部翻转 | | |
| | teacher / hindsight | Gemini 用于 SFT,不是 RFT teacher | successful peer + stale ref | GT reference + configured teacher | | |
| | span | action sequence prefix | action-centered step | action_id/action_name token span | | |
| | 是否需要 GT step | 需要 gold sequence | 不需要显式 GT,依赖 peer success | rule 需要;forward_proxy 使用 GT context | | |
| | 是否额外 KL loss | 否 | 否 | 否 | | |
| | 最大风险 | reward 仍较粗,长程困难 | 与当前方法撞车点强 | forward_proxy 正确性、additive 过强、GT 依赖 | | |
| --- | |
| ## 10. 应该如何给当前方法定位 | |
| ### 10.1 不建议的写法 | |
| 如果主方法是 forward_proxy,不建议写: | |
| ```text | |
| We propose to use OPSD-style teacher-student logp gap for step-level GRPO advantage shaping. | |
| ``` | |
| 这个表述和 StepOPSD 撞得太正。 | |
| 也不建议写: | |
| ```text | |
| Our method is fundamentally different from StepOPSD. | |
| ``` | |
| 因为两者确实同属 step-aware OPSD advantage shaping。 | |
| ### 10.2 更准确的写法 | |
| 可以这样定位: | |
| ```text | |
| We study step-level credit assignment for one-shot embodied trajectory planning, | |
| where a VLM generates a structured JSON executable plan in a single response. | |
| Unlike general multi-turn agent trajectories, the decision variables are explicit | |
| action_id/action_name fields. We inject step-local advantages into GRPO by mapping | |
| either GT action matching or GT-reference-privileged teacher contrast onto these | |
| structured action spans. | |
| ``` | |
| 中文表达: | |
| ```text | |
| 我们不是提出“OPSD 信号用于 advantage shaping”这个大方向本身; | |
| 这个方向 StepOPSD 已经非常接近。 | |
| 我们的具体切入点是: | |
| 在 one-shot embodied JSON trajectory planning 中, | |
| 利用显式 action_id/action_name 结构,把 GT-reference 或 rule step signal | |
| 映射到动作字段 token,并以 additive local step advantage 的方式注入 GRPO。 | |
| ``` | |
| ### 10.3 当前实现最清楚的贡献点 | |
| 可以强调: | |
| 1. **任务形态差异**: | |
| ```text | |
| one-shot embodied trajectory planning,不是一般 multi-turn agent transcript。 | |
| ``` | |
| 2. **结构化 action span**: | |
| ```text | |
| 显式区分 action_id 和 action_name。 | |
| 可以 score semantic tokens,但只 credit action_id。 | |
| ``` | |
| 3. **additive local advantage**: | |
| ```text | |
| 允许局部 step 改变更新方向。 | |
| 这和 StepOPSD 的 sign-preserving multiplicative reweighting 不同。 | |
| ``` | |
| 4. **rule vs forward_proxy 的系统比较**: | |
| ```text | |
| 当任务有干净离散 action_id GT 时,hard rule step reward 可能比 KL soft proxy 更可靠。 | |
| forward_proxy 作为软信号和无 step verifier 场景的泛化对照。 | |
| ``` | |
| 5. **gate 机制**: | |
| ```text | |
| residual gate / prompt gate 用来控制 soft KL 信号进入 action tokens 的强度。 | |
| ``` | |
| --- | |
| ## 11. 建议补的实验和分析 | |
| ### 11.1 必做:四个主 baseline | |
| 建议最小实验表: | |
| ```text | |
| 1. GRPO | |
| 2. GRPO + rule step reward | |
| 3. GRPO + forward_proxy additive | |
| 4. GRPO + forward_proxy + residual gate | |
| ``` | |
| 如果资源允许,再加: | |
| ```text | |
| 5. GRPO + forward_proxy + prompt gate | |
| 6. GRPO + StepOPSD-style multiplicative reweighting | |
| ``` | |
| ### 11.2 强烈建议实现 StepOPSD-style multiplicative baseline | |
| 为了和 StepOPSD 讲清楚,建议在当前代码里加一个模式: | |
| ```text | |
| step_injection_mode: | |
| additive # current | |
| multiplicative_stepopsd | |
| ``` | |
| multiplicative 公式: | |
| ```text | |
| Delta_step 或 Delta_token 来自 forward_proxy。 | |
| w = clip(2 * sigmoid(sign(A^E) * Delta), 1 - alpha_clip, 1 + alpha_clip) | |
| A = (1 - lambda_mix) * A^E + lambda_mix * (w * A^E) | |
| ``` | |
| 然后比较: | |
| ```text | |
| additive 是否真的优于 sign-preserving? | |
| additive 的 sign flip 是否带来收益? | |
| ``` | |
| 这个实验对论文非常关键,因为它直接回应 StepOPSD。 | |
| ### 11.3 sign flip 统计 | |
| 当前 additive 最大差异是可能局部翻转方向。建议统计: | |
| ```text | |
| sign_flip_ratio = | |
| mean[ sign(A^E + omega*A^S) != sign(A^E) over action tokens ] | |
| ``` | |
| 并分组看: | |
| ```text | |
| 成功 trajectory vs 失败 trajectory | |
| 正确 step vs 错误 step | |
| Heat/Cool/Clean/PickTwo 等长程任务 | |
| ``` | |
| 如果能证明: | |
| ```text | |
| 失败轨迹中的正确前缀 step 被 additive 保留下来; | |
| 成功轨迹中的错误/冗余 step 被局部压低; | |
| ``` | |
| 那就是相对 StepOPSD 的强证据。 | |
| ### 11.4 forward_proxy 正确性分析 | |
| 不要只看: | |
| ```text | |
| teacher-student diff std | |
| ``` | |
| 还要看: | |
| ```text | |
| rule match = 1 的 step,forward_proxy A^S 分布。 | |
| rule match = 0 的 step,forward_proxy A^S 分布。 | |
| ``` | |
| 理想情况: | |
| ```text | |
| correct steps: mean A^S > 0 | |
| wrong steps: mean A^S < 0 | |
| ``` | |
| 如果 wrong steps 也大量为正,说明 forward_proxy 更像 style/trajectory prior,而不是 correctness signal。 | |
| ### 11.5 rule mode 消融 | |
| 比较: | |
| ```text | |
| exact | |
| prefix | |
| lcs | |
| ``` | |
| 可能结论: | |
| ```text | |
| exact: | |
| 信号干净但太硬。 | |
| prefix: | |
| 更符合 embodied execution,一旦前面错了后面不该继续强判。 | |
| lcs: | |
| 对顺序和多余 find 更宽容,但可能奖励不可执行的乱序计划。 | |
| ``` | |
| ### 11.6 credit target 消融 | |
| 比较: | |
| ```text | |
| score_source=action_name, credit_target=action_name | |
| score_source=semantic, credit_target=action_id | |
| score_source=semantic, credit_target=semantic | |
| ``` | |
| 重点看: | |
| ```text | |
| 只训练 action_id 是否比训练 action_name 更稳定。 | |
| action_name token 是否引入措辞/格式梯度噪声。 | |
| ``` | |
| --- | |
| ## 12. 当前代码路径速查 | |
| ### 12.1 数据和 prompt | |
| ```text | |
| verl/utils/dataset.py | |
| embodied prompt 构造 | |
| image processor | |
| multi_modal_data | |
| ground_truth 包装 | |
| ``` | |
| ### 12.2 trajectory reward | |
| ```text | |
| verl/workers/reward/function.py | |
| compute_reward_batch | |
| verify prompt | |
| overall = 0.8 * accuracy + 0.2 * format | |
| reward 写最后一个 token | |
| verl/workers/reward/verify.py | |
| ask_llm | |
| load_verify / load_verify_qwen3 | |
| ``` | |
| ### 12.3 step reward / step advantage | |
| ```text | |
| verl/trainer/step_reward.py | |
| extract_plan_steps | |
| compute_step_match_rewards | |
| pred_step_token_spans | |
| build_step_adv_vector | |
| build_step_adv_vector_from_logp | |
| build_step_adv_raw | |
| ``` | |
| ### 12.4 forward_proxy teacher | |
| ```text | |
| verl/trainer/teacher_proxy.py | |
| TeacherLogpScorer | |
| PromptGateScorer | |
| verl/workers/reward/verify.py | |
| step_logp_vl | |
| verl/workers/reward/function.py | |
| AutoRewardManager.compute_step_adv | |
| ``` | |
| ### 12.5 GRPO 接线 | |
| ```text | |
| verl/trainer/core_algos.py | |
| AdvantageEstimator.GRPO_STEP | |
| compute_grpo_step_outcome_advantage | |
| verl/trainer/ray_trainer.py | |
| compute_advantage | |
| _build_step_adv | |
| _dump_adv_heatmaps | |
| _save_total_adv_heatmaps | |
| ``` | |
| ### 12.6 配置和脚本 | |
| ```text | |
| verl/trainer/config.py | |
| AlgorithmConfig 中所有 step_* 字段 | |
| examples/qwen25_vl_3b_Domain.sh | |
| 当前 forward_proxy 主运行脚本 | |
| examples/qwen25_vl_3b_residual_gate_ablation.sh | |
| residual gate 消融 | |
| examples/qwen25_vl_3b_prompt_gate_ablation.sh | |
| prompt gate 消融 | |
| ``` | |
| --- | |
| ## 13. 最后总结 | |
| 如果用一句话串起来: | |
| ```text | |
| 2505.22050 告诉我们 embodied planning 可以用 SFT + rule reward + GRPO 训; | |
| StepOPSD 告诉我们长轨迹 agent RL 的关键是 step-aware advantage shaping; | |
| 当前 EasyR1-V4-Embody 把这两个方向接到一起: | |
| 在 one-shot embodied JSON plan 上,用 verify model 给整轨 reward, | |
| 再用 rule 或 GT-aware forward_proxy 给 executable_plan 的 action spans 加 step-local advantage。 | |
| ``` | |
| 当前实现最应该讲清楚的不是“我们用了 GRPO”,也不是“我们用了 OPSD”,而是: | |
| ```text | |
| 我们如何把 embodied JSON plan 中的结构化动作字段变成可训练的 token-level step credit; | |
| 以及 additive step advantage 相比 StepOPSD sign-preserving reweighting 的差异、收益和风险。 | |
| ``` | |
| 当前代码已经具备一套完整实验框架: | |
| ```text | |
| GRPO | |
| GRPO + rule | |
| GRPO + forward_proxy | |
| GRPO + residual gate | |
| GRPO + prompt gate | |
| ``` | |
| 下一步最有价值的是补: | |
| ```text | |
| StepOPSD-style multiplicative baseline | |
| sign-flip analysis | |
| forward_proxy correctness-vs-rule correlation | |
| rule exact/prefix/lcs 消融 | |
| credit target 消融 | |
| ``` | |
| 这些实验能把“和两篇论文的关系”从文字解释变成可验证证据。 | |