MicroDuck 从零到真机(04):PPO、奖励函数与课程怎样设计
解释 MicroDuck 的 actor–critic 与 PPO 更新,再从目标行为、奖励符号、投机行为、课程和评估出发设计可迁移的训练任务。
系列目录 · 上一篇:训练参数 · 下一篇:Sim2Real 与导出
“设计训练算法”包含两个层面:优化器怎样更新策略,以及环境用什么目标引导策略。本系列沿用官方 PPO 基线,把主要设计工作放在观测、动作、奖励和数据分布上。先有一个能复现的基线,才有理由判断是否需要更复杂的算法。
1. actor 和 critic 分别学什么
actor 接收可部署的观测,输出动作分布;训练时从分布中采样,实机部署通常使用确定性策略输出。critic 估计当前状态下未来折扣回报,用于降低策略梯度估计的方差。
MicroDuck 的 actor 使用 61 维观测。critic 可以看到真实线速度、足接触等额外仿真信息,这叫非对称 actor–critic:训练辅助网络有更多信息,但上线的动作决策仍只依赖实物能构造的输入。不要把 critic 的优势误解为可以把不可观测的仿真状态塞入导出的 actor。
2. PPO 一次迭代做了什么
用旧策略在 N 个环境中各采样 T 步
→ 保存观测、动作、旧 log-prob、奖励、value 和终止标记
→ 用回报与 GAE 计算优势
→ 将数据分为 mini-batch,重复若干 epoch
→ 更新 actor 和 critic,检查 KL、梯度与损失
→ 用更新后的策略采下一批数据
策略概率比的概念表达是:
r_t(θ) = π_θ(a_t | o_t) / π_old(a_t | o_t)
L_clip = mean[min(r_t × A_t,
clip(r_t, 1-ε, 1+ε) × A_t)]
正优势表示这次动作比 critic 预期更好;负优势表示更差。裁剪项限制某些更新带来的收益,降低同一批数据被反复优化时策略变化过大的风险。它不是每个关节角的物理限幅,也不能代替实机限位。
GAE 将多步时序差分误差结合起来:
δ_t = reward_t + γ × V(next_state) - V(state_t)
A_t = δ_t + γλ × δ_(t+1) + (γλ)^2 × δ_(t+2) + ...
这里是便于理解的非终止片段表达。实现时必须使用正确终止掩码,并区分真正失败与时间截断的 bootstrap 处理。不能把所有 reset 都一律当作未来价值为零。
PPO 的原始定义见 Schulman 等人的论文,具体损失、熵项和自适应学习率应查 RSL-RL 5.0.1 实现。概念公式不能替代实现细节。
3. 先写行为规格,再写奖励
假设目标是“在给定速度下稳定行走,零指令时能停住,并按要求转头”。在调权重前,把它拆成可以测量的观察:
| 要求 | 评估量 | 容易钻的空子 |
|---|---|---|
| 速度跟踪 | 指令与机身速度误差 | 拖行或滑动也可能接近目标速度 |
| 保持站立 | 姿态、足支撑、跌倒率 | 机身看似正立,却用头或其他部件撑地 |
| 动作平顺 | 动作变化、关节速度与冲击 | 为减少动作而完全不迈步 |
| 零指令停止 | 停止时间、残余位移与动作 | 一直原地踏步,或把停止误判成失败 |
| 转头跟踪 | 命令与关节角偏差 | 为头部奖励牺牲整个步态 |
这些评估量不应全部直接变成奖励。评估需要独立判定结果;奖励只是帮助探索结果的学习信号。
4. 从最少的任务信号开始
可把奖励结构写成:
总奖励 = 速度跟踪 + 姿态/头部任务 + 合理足步行为
- 动作突变 - 足滑 - 硬限位/碰撞代价
例如速度跟踪常用随误差下降的指数形式。误差尺度太大时,小范围改进几乎不影响得分;太小时,初始随机策略得到的信号又可能接近零。尺度应对应“仍值得改善的误差范围”,不直接使用最大速度作为答案。
固定版本行走任务的速度跟踪、直立与头部跟踪权重都有明确来源;足滑惩罚较弱,动作变化惩罚分阶段加强。应读完整配置,不能只摘几项权重就称作官方配方。
5. 奖励符号比权重大小更先检查
官方代码中存在两种代价风格:一种函数返回非负成本,再乘负权重;另一种函数自身返回负值,需乘正权重。名字叫 penalty 并不能证明它一定非负。
| 函数输出 | 权重 | 最终贡献 | 含义 |
|---|---|---|---|
+2 成本 |
-0.1 |
-0.2 |
惩罚违规 |
-2 自带负号的惩罚 |
+0.1 |
-0.2 |
也在惩罚违规 |
-2 自带负号的惩罚 |
-0.1 |
+0.2 |
反而奖励违规 |
新奖励函数应以几个人工构造的状态检查:好状态、轻微违规、严重违规、边界状态。比较的是加权后的贡献与排序,不是“函数能运行”。训练日志中的每个惩罚贡献也应核对符号,不能只检查总奖励。
6. 防止奖励投机,需要限制行为语义
如果奖励只鼓励机身高度,机器人可能用头撑地;只鼓励角速度,可能甩动身体而非完成翻滚;只奖励“到达站姿后每步得分”,可能使策略用强冲击抢先进入高收益状态。
设计动态技能时,应明确支撑部位、目标旋转轴、开始与结束条件,并在需要时采用锁存或每回合一次的成功事件。仅增加一个很小的碰撞惩罚,未必抵得过更早获得持续奖励的收益。
势函数塑形可以奖励进展,例如朝目标姿态的接近。若要讨论保持最优策略的经典性质,形式是 γΦ(s_next)-Φ(s),并依赖相应假设;直接使用差分是工程塑形方式,不能一概宣称具有理论不变性。设计后仍要检查来回振荡是否能套利。
7. 头部控制说明了“罚错误差”的代价
头部质量与运动会影响整机平衡。官方把瞬时头部跟踪和长期偏置分开处理:瞬时项允许必要摆动,另一项对误差的时间平均进行惩罚,以减少持续低头。
如果直接把瞬时误差要求收得过紧,迈步产生的正常振动也会持续扣分,策略可能选择不走。这里的启示是先区分“行为必然带来的变化”和“策略本来可以消除的偏差”。具体实现见 head_pose_bias_penalty。
8. 课程怎样帮助探索
一个可解释的顺序是:先让核心动作有机会发生,再逐步增加平滑、精度与扰动要求。固定版本把动作变化惩罚从较弱值逐级加强,同时改变站立指令比例和重心随机化范围。
新任务可以借鉴这个结构,但不要凭迭代编号假设技能已经掌握。若每次在同一课程边界退步,先看该边界的难度是否超过当前策略能力。保留早期任务信号,分开测试新增惩罚和新增扰动。
恢复或翻滚等任务还需要合理初始状态分布。策略从来没有接近成功的体验时,单靠增大学习率很难解决最后一段动作;可以考虑从动作中后段的状态开始训练,再逐步扩展到完整起点,但每类状态都要保持物理可达。
9. 何时才改算法本身
如果基线的观测、物理模型与奖励都经过检查,仍出现明确的信息或优化瓶颈,再考虑:历史观测或循环网络应对部分可观测性;教师策略与蒸馏整合技能;对称损失促进双侧一致。
官方的对称功能在该行走配方中默认关闭。不对称任务,例如单侧踢球,不能机械地加左右镜像。LSTM 还会改变导出接口与运行时状态管理,不能继续用本系列前馈网络的单输入、单输出形状要求。
10. 把一个奖励假设变成可比较的配置
假设要检验“减轻动作变化惩罚是否能改善迈步探索”,可在第二篇自定义工厂的 return cfg 之前加入下面的教学改动:
# Remove the inherited schedule so it does not overwrite this fixed value.
cfg.curriculum.pop("action_rate_weight", None)
cfg.rewards["action_rate_l2"].weight = -0.05
以同一自定义任务为基线,先保存未改版本,再只运行这一组改动。这里的 -0.05 是待验证的实验值,不是推荐给所有任务的最佳权重。去掉对应课程十分关键:如果只改初始权重,却保留课程,运行中 manager 仍会按旧阶段改回去。
比较时同时查看迈步、速度误差与动作变化;若探索增加但抖动也增大,下一轮可以研究更晚加强平滑的课程,而不是直接宣布弱惩罚更好。这个过程把一个行为判断变成了能够复查的假设、代码差异和评估结果。
11. 用消融和固定评估结束一轮设计
建议先保留官方基线,再分别比较“加一个奖励项”“改变一个课程阶段”“调整一个观测来源”。使用固定指令集合、不同初始姿态和多随机种子,记录跟踪误差、完成率、跌倒、冲击与动作变化,并观看失败视频。
如果去掉某项没有损害目标行为,它可能不是必要项;如果总奖励更高但独立成功率下降,应修正目标表达。算法设计的交付物应是可复查的行为变化,而不是一张总奖励更漂亮的曲线。