G1-23dof 强化学习训练实战复盘与经验总结
G1-23dof 强化学习训练实战复盘与经验总结
文档版本:V1.0
来源:blind_teacher_v2_training_report.md + phase1_report.md
编写日期:2026-04-12
适用任务:全任务(Velocity / Blind-Teacher / Fusion)
1. 核心经验速查
这些是从真实训练中总结的实战教训,每一条都对应一次或多次失败。
| # | 经验 | 教训级别 |
|---|---|---|
| 1 | PPO 超参数过大 + 小 mini_batch → NaN 崩溃 | 🔴 致命 |
| 2 | 固定抬脚高度无法同时适配平地和楼梯 | 🟡 重要 |
| 3 | Curriculum 晋级门槛过高会导致降级 | 🟡 重要 |
| 4 | 动作 scale 偏小会限制关节运动范围 | 🟡 重要 |
| 5 | 局部最优是长期训练的必然风险 | 🟢 有用 |
| 6 | Domain Randomization 过强会延长训练时间 | 🟢 有用 |
2. NaN 崩溃七层防御体系
2.1 事故经过
V1 训练到 iter 6849 时突然出现 value_loss=NaN,后续所有梯度更新失效。
根因分析:
rsl_rl PPO 使用单个 Adam optimizer 同时更新 actor 和 critic。当 value_loss 出现极端梯度时,其 momentum 通过共享 optimizer 污染 actor 的 noise_std 参数,导致动作噪声发散,进而 reward 崩溃。
2.2 危险配置 vs 修复配置
| 参数 | 危险值(V1) | 修复值(V2) | 参考 |
|---|---|---|---|
learning_rate |
1.0e-3 | 5.0e-4 | StairV4: 5e-4 |
num_mini_batches |
4 | 16 | StairV4: 16 |
desired_kl |
0.02 | 0.01 | Fusion: 0.01 |
核心教训:num_mini_batches=4 意味着每次更新只用 1024 个样本(4096×24/4),梯度估计噪声大,极易被极端值带偏。
2.3 七层防御代码
# L1: 噪声参数化(actor_critic.py)
noise_std = exp(log_noise_std) # 数学保证 std > 0
# L2: value_loss clamp(ppo.py:318)
value_loss = clamp(value_loss, max=10.0)
# L3: reward clamp(rollout_storage.py:92)
reward = clamp(reward, min=-20, max=20)
# L4: returns clamp(rollout_storage.py:155)
returns = clamp(returns, min=-100, max=100)
# L5: 梯度 NaN 检测,跳过更新(ppo.py:391-399)
if torch.isnan(grad).any():
optimizer.step() # 跳过
# L6: ratio clamp(ppo.py:298)
ratio = clamp(ratio, min=0.01, max=100)
# L7: loss NaN/Inf 跳过 backward(ppo.py:374-375)
if not torch.isfinite(loss):
continue # 跳过此次更新
3. Terrain Level 停滞在 5-6 的问题排查
3.1 问题描述
V2 训练 18000+ iterations 后: - 存活率 97%+ ✅ - reward 81+ ✅ - terrain level 卡在 5~6/9,无法突破
3.2 已尝试的 4 种 Curriculum 方案
| 方案 | 晋级条件 | 结果 | 分析 |
|---|---|---|---|
tracking_exp_vel |
速度跟踪 > 0.7 | ❌ 卡住 | 台阶上速度波动大,分数永远达不到 0.7 |
vel_aggressive 固定 2.0m |
distance > 2.0m | ❌ 卡住 | 距离够但策略找到了"省力走法" |
cmd_adaptive ratio=0.8 |
distance > 12.8m@0.8m/s | ❌ 降级 | 门槛过高,机器人在台阶上走不了那么远 |
cmd_adaptive ratio=0.5 |
distance > 8.0m@0.8m/s | 🔄 恢复中 | 上升趋势但缓慢 |
3.3 四大制约因素
因素 1:动作 Scale 偏小(最可能)
| 关节 | BlindTeacher V2 | StairV4(成功突破) |
|---|---|---|
| hip_roll | 0.35 | 0.5 |
| ankle_pitch | 0.4 | 0.5 |
| ankle_roll | 0.4 | 0.5 |
结论:hip_roll 控制侧向抬腿,scale 偏小直接限制了跨越高台阶时的动作幅度。
因素 2:地形组成差异
| V2 | StairV4 | |
|---|---|---|
| 台阶总比例 | 45% | 57% |
| 最大台阶高度 | 0.20m | 0.25m |
V2 的台阶训练时间比 StairV4 少 12%,且最大难度低 5cm。
因素 3:感知延迟(Blind 设计局限)
Height_scan 安装在 torso_link,检测的是脚下地形高度,不是前方的预测。机器人只有踩上台阶才能感知,无法提前规划抬腿。
这是 BlindTeacher 的设计定位(为 Depth-Student 提供教师信号),但确实限制了高难度地形表现。
因素 4:局部最优(长期训练必然风险)
18000 iter 后,策略在 level 5-6 已经非常稳定。"不摔跤 + 不耗能" 的局部最优不需要学会爬高台阶。
3.4 待尝试方案(按优先级)
| 优先级 | 方案 | 预期效果 |
|---|---|---|
| P0 | hip_roll 0.35→0.5, ankle 0.4→0.5 | 对齐 StairV4 的成功配置 |
| P1 | stairs_up 28%→35%, max_height 0.20→0.25m | 增加高难度地形暴露 |
| P2 | 从头训练(清除局部最优) | 跳出局部最优陷阱 |
| P3 | promotion_ratio 0.5→0.3 | 降低晋级门槛 |
4. Curriculum 演进路线
4.1 演进时间线
Phase 0: terrain_levels_vel(纯速度门控)
↓ 发现问题:转圈也能升级
Phase 1: quality_gated_terrain_curriculum(距离+存活率双门控)
↓ 存活率门控导致晋级过慢
StairV4: terrain_levels_vel_aggressive(固定 2.4m 距离)
↓ 对某些地形有效但非通用
V1: tracking_exp_vel(速度跟踪分数 > 0.7)
↓ 台阶上速度波动大,永远达不到 0.7
V2: terrain_levels_cmd_adaptive(速度自适应距离门控)
↓ 目前最优,但仍卡在 level 6
4.2 Command-Adaptive Curriculum 详解
# 晋级:走过距离 > max(cmd_vel × episode_time × 0.5, 2.0m)
# 降级:走过距离 < cmd_vel × episode_time × 0.2
# 速度越快,晋级门槛越高(防止冲刺后摔到)
# 速度越慢,保底 2.0m 门槛(防止低速时无限晋级)
| 训练阶段 | 平均速度 | 晋级门槛 | 降级门槛 |
|---|---|---|---|
| 初期 | 0.05 m/s | 2.0m(保底) | 0.2m |
| 中期 | 0.30 m/s | 3.0m | 1.2m |
| 后期 | 0.80 m/s | 8.0m | 3.2m |
5. 关键设计决策复盘
5.1 V1 → V2 三大改进
改进 1:固定抬脚 → 地形自适应抬脚
V1 问题:固定 0.15m 目标 - 平地上:抬脚 15cm 过多(浪费能量) - 楼梯上:0.15m < 0.17m 台阶(磕碰)
V2 解决方案:
# height_scan 检测前方地形落差
variation = height_scan.max() - height_scan.min()
stair_factor = clamp(variation / 0.08, 0, 1)
# 目标高度动态插值
target = 0.12 + stair_factor * 0.08 # 0.12m(平) ~ 0.20m(楼梯)
效果:terrain level 5-6 上 feet_swing_adaptive 奖励达到 89% 最大值,说明自适应机制有效。
改进 2:forward_progress 加倍激励
V1 问题:distance_scale=4.0 导致近距离梯度太平,机器人缺乏前进动力。
# V1: tanh(distance / 4.0) → 1m 行走仅得 0.24 分
# V2: tanh(distance / 2.0) → 1m 行走可得 0.46 分(+92%)
# weight 也从 1.0 → 2.0,总激励约 ×3
改进 3:PPO 超参数修复(防崩溃)
见第 2 节。
5.2 决策:从头训练 vs 热启动
问题:Phase 0 的 Actor 输入 78D,Phase 1 是 265D(+ height_scan),MLP 第一层维度不匹配。
结论:写部分权重加载器的成本 > 多训练几小时。从头训练 + init_noise_std=0.5 足够稳定。
6. 训练监控指标体系
6.1 核心指标(每日必查)
| 指标 | 健康范围 | 崩溃前兆 |
|---|---|---|
value_loss |
< 1.0 | > 10.0 或 NaN |
noise_std |
单调下降或稳定 | 持续上升 |
Mean episode length |
> 700(70%) | 突然下降 |
terrain_levels |
持续上升 | 停滞 > 5000 iter |
reward |
单调上升 | 突然下降 |
6.2 分层奖励贡献分析
以 V2 iter 18701 为例,各项奖励贡献:
| 奖励项 | 实际值 | 最大值 | 达成率 | 状态 |
|---|---|---|---|---|
| track_lin_vel_xy | 1.68 | 2.00 | 84% | ✅ 良好 |
| forward_progress | 1.54 | 2.00 | 77% | ✅ 良好 |
| feet_swing_adaptive | 1.33 | 1.50 | 89% | ✅ 良好 |
| gait | 0.29 | 0.30 | 97% | ✅ 接近满分 |
| alive | 0.25 | 0.25 | 100% | ✅ 满分 |
| track_ang_vel_z | 0.25 | 0.75 | 33% | ⚠️ 偏低 |
| action_rate | -0.53 | — | — | ⚠️ 最大负项 |
分析:action_rate(动作变化率)是最大负项,说明策略倾向于高频率动作调整,而非稳定步态。
7. 经验总结清单
7.1 训练开始前
- [ ]
num_mini_batches至少 16(4096 envs 下) - [ ]
desired_kl≤ 0.01(过大会导致更新过于激进) - [ ]
init_noise_std验证:期望初期 std ≈ 0.5 - [ ] Domain Randomization 参数记录在案
7.2 训练初期(0~5000 iter)
- [ ] 检查
value_loss是否稳定(< 1.0) - [ ] 检查
noise_std是否开始下降(而非上升) - [ ] terrain level 应该在 1~3 范围内
- [ ] episode length 应该 > 500
7.3 训练中期(5000~20000 iter)
- [ ] terrain level 应持续上升(若停滞 > 3000 iter 开始排查)
- [ ] 检查各奖励项贡献比例是否合理
- [ ] action_rate 负值不应过大(过大说明动作不平滑)
- [ ] 倒地率(bad_orientation)应 < 10%
7.4 训练收尾
- [ ] terrain level 达到目标(通常 6~8 为良好)
- [ ]
noise_std应趋于稳定(不再下降) - [ ]
value_loss应稳定在低位 - [ ] 做 3 次以上独立 play 测试验证泛化性
版本记录
| 版本 | 日期 | 修改内容 | 作者 |
|---|---|---|---|
| V1.0 | 2026-04-12 | 初始版本,整理自 V1/V2 训练报告 | AI Assistant |
本文档由 AI 辅助整理自 unitree_lab_locomotion 仓库训练复盘文档