【Cursor-Gpt-5-high】StackCube-v1 任务训练结果不稳定性的分析

发布于:2025-09-04 ⋅ 阅读:(18) ⋅ 点赞:(0)

1. Prompt

我是机器人RL方向的博士生正在学习ManiSkill,在学习时我尝试使用相同命令训练同一个任务,但是我发现最终的 success_once 指标并不是相同的,我感到十分焦虑,
我使用的命令如下:

python sac.py --env_id="StackCube-v1" \
  --num_envs=32 --utd=0.5 --buffer_size=500_000 \
  --total_timesteps=500_000 --eval_freq=50_000 \
  --control-mode="pd_ee_delta_pos"

I conducted two independent training runs with the same setup. Here is a comparison of the success_once metric at different stages:

Run 1:

success_once: 0.00, return: 2.59: 0%
...
success_once: 0.88, return: 39.84: 90%
success_once: 0.88, return: 39.84: : 500032lt [1:04:37, 132.17lt/s]

Run 2:

success_once: 0.00, return: 2.59: 0%
...
success_once: 0.31, return: 36.46: 90%
success_once: 0.31, return: 36.46: : 500032lt [43:38, 199.09lt/s]

The final success rate differs drastically (0.88 vs. 0.31).
请您浏览 this codebase,尤其是 sac.py,请帮我看看是什么原因导致了结果不一致呢?

2. Cursor-Gpt-5-high

我先快速在仓库里搜一下评估时 final_info 的结构、success_once 的生成方式,以及 ManiSkillVectorEnv 的实现细节,确认是否存在评估统计上的问题或非确定性来源。接着我会并行打开这些相关实现的源码片段以验证假设。

[5 tools called]

我将打开并阅读 mani_skill/vector/wrappers/gymnasium.py 的类初始化部分,确认 auto_resetignore_terminations 与指标统计的具体行为,以判断评估是否可能错误聚合或存在非确定性来源。

[1 tool called]

我先并行查找 BaseEnv.reset 的重置与随机种子逻辑、enhanced_determinism 的实现,以及 StackCube-v1 任务的评估与成功判定,确认是否由环境非确定性或控制模式差异导致评估波动。随后我会核对 sac.py 的评估循环在 GPU 向量环境下是否正确聚合 success_once

[6 tools called]

结论(为什么同命令两次训练 success_once 会差这么多)

  • 训练早期的随机动作未被固定种子控制。sac.py 在学习开始前用 envs.action_space.sample() 探索,但没有对 action_space 本身调用 seed,Gymnasium 的 Space 默认用自身的 RNG(来自 OS 随机源),这会导致最初缓冲区的数据不同,后续学习发散,导致最终指标差异很大。
  • GPU 物理仿真存在不可完全复现的数值非确定性(碰撞、接触、并行归约顺序等)。StackCube-v1 的成功判定包含静止判定与非常小的几何容差;微小数值差异会放大为“某一轮成功/未成功”的不同,进一步影响采样和学习轨迹。
  • 评估环境每次 reset(默认 eval_reconfiguration_freq=1)都会重新随机对象位姿;尽管这对于公平评估是需要的,但它会使单次评估更敏感于策略的细微差别,从而放大不同 run 之间的差异。
  • 两次运行的训练速度差异很大(64min vs 43min),说明系统负载/调度不同;在 GPU 物理和大批量并行时,这种差异也会轻微改变浮点执行顺序,从而进一步增加非确定性。

直接可改的最关键点

  • 固定 Gymnasium action_space 的随机源(最重要,成本最低,收益最大):
    if isinstance(envs.action_space, gym.spaces.Dict):
        envs = FlattenActionSpaceWrapper(envs)
        eval_envs = FlattenActionSpaceWrapper(eval_envs)

    envs.action_space.seed(args.seed)
    eval_envs.action_space.seed(args.seed + 1)

    if args.capture_video or args.save_trajectory:
        eval_output_dir = f"runs/{run_name}/videos"
        if args.evaluate:
            eval_output_dir = f"{os.path.dirname(args.checkpoint)}/test_videos"
        print(f"Saving eval trajectories/videos to {eval_output_dir}")

进一步提升复现性的建议

  • 将评估(至少评测时)切到 CPU 物理后端,或训练也统一 CPU 后端(速度会慢,但更稳定):
    • 运行时传 --env_vectorization=cpu 或在创建环境时设置 sim_backend="physx_cpu" 并将 num_envs=1(CPU 模式不支持多并行)。
  • 若必须用 GPU:
    • 保持固定 --seed,并固定 action_space.seed(如上)。
    • 避免在同机上并发其它重负载任务,尽量减少运行时抖动。
    • 可将评估步数/回合数加大(例如把 num_eval_envsnum_eval_steps 提高),用均值稀释单次随机性。
  • 若希望评估更稳定、对初始化不太敏感,可暂时设 --eval_reconfiguration_freq=0(减少每次评估的对象重随机),但要注意这会降低评估的随机覆盖面,长期应使用 1

你看到的现象如何对应到上述点

  • 两次 run 的 success_once 差异巨大,且 walltime 差异明显,符合“早期随机轨迹不同 + GPU 物理非确定性”叠加放大的模式。

  • sac.py 里已经固定了 Python/NumPy/PyTorch 的种子,但没有固定 Gym action_space 的种子,这是最直接的缺口。

  • 如需我直接帮你把 sac.py 加上 action_space.seed、并提供一个更“稳健评估”的命令行(CPU/GPU 两版),我可以顺手改好并给出完整命令。

  • 小提示:你命令里的 --control-mode 映射到 Args.control_mode 是可以的;保持与训练/评估端一致即可。

  • 若要严格科研可复现,建议最终报告同时给出多种子均值/方差,并在附录说明 GPU 物理的不可完全确定性。

  • 如果修复后你仍看到显著波动,可以把评估阶段切到 CPU 物理或增加评估覆盖度;这两招基本能稳定到小方差区间。

  • 需要我继续把评估改成“CPU-only”(只在评估时切 CPU)并给出对应命令吗?

  • 最后提醒:默认 capture_video=True 会拖慢训练速度且引入 I/O 抖动,如果不需要视频,可加 --capture_video=False 提升稳定性。