强化学习-PPO 奖励塑形实验:Pendulum-v1 中角速度惩罚权重的影响

PPO 奖励塑形实验:Pendulum-v1 中角速度惩罚权重的影响

算法:PPO(Stable-Baselines3)| 环境:Pendulum-v1 | 单组 3M steps

对照:vel_penalty = 0.1 / 0.3 / 0.5 / 0.8

一、实验动机

之前做的消融(batch_size / clip_range / gae_lambda / lr)都是在算法侧 调参,但 RL 里还有个更"要命"的杠杆------奖励函数本身。同一个环境,奖励塑形(Reward Shaping)不一样,学到的策略可以天差地别。

Pendulum-v1 默认奖励:

r=−(θ2+0.1⋅θ˙2+0.001⋅u2) r = -(\theta^2 + 0.1 \cdot \dot{\theta}^2 + 0.001 \cdot u^2) r=−(θ2+0.1⋅θ˙2+0.001⋅u2)

三项分别是:角度偏差、角速度、扭矩(能耗)。这次只动中间那项的权重 vel_penalty,看训练差异。


二、实验代码

核心是自定义 gym.Wrapper,在 step 里重写奖励:

python 复制代码
from typing import Any, SupportsFloat

import gymnasium as gym
from gymnasium import RewardWrapper
import numpy as np
import stable_baselines3 as sb3
from multiprocessing import Pool


class OriginalReward(RewardWrapper):
    def __init__(self, env: gym.Env):
        super().__init__(env)

    def reward(self, reward: SupportsFloat) -> SupportsFloat:
        return super().reward(reward)

class AngualVelocityPenaltyQrapper(gym.Wrapper):
    def __init__(self, env: gym.Env, vel_penalty = 0.5):
        super().__init__(env)
        self.vel_penatty = vel_penalty

    def step(self, action: Any) -> tuple[Any, SupportsFloat, bool, bool, dict[str, Any]]:
        obs, reward, terminated, truncated, info = self.env.step(action=action)
        cos_th, sin_th = obs[0], obs[1]
        theta = np.arctan2(sin_th, cos_th)
        theta_dot = obs[2]
        u = action[0]

        new_reward = -(theta ** 2 + self.vel_penatty * theta_dot ** 2 + 0.001 * u ** 2)
        return obs, new_reward, terminated, truncated, info
    

def train_one(vel_penalty):
    env = AngualVelocityPenaltyQrapper(gym.make("Pendulum-v1"), vel_penalty=vel_penalty)
    model = sb3.PPO("MlpPolicy", env=env, tensorboard_log=f"./result/vel_penalty_{vel_penalty}")
    model.learn(total_timesteps=3_000_000)
    env.close()
    print(f"Finsh vel_penalty {vel_penalty}")


if __name__ == "__main__":
    vel_penalty = [0.1, 0.3, 0.5, 0.8]
    with Pool(processes=2) as pool:
        pool.map(train_one, vel_penalty)

📌 代码里 Qrapper / vel_penatty 是拼写笔误,跑起来没问题,正式仓库建议改回 Wrapper / vel_penalty


三、结果分析

3.1 回合平均奖励(ep_rew_mean)

vel_penalty 最终平滑 reward 表现
0.1 -152 ✅ 最优,收敛快且稳
0.3 ≈ -155 尚可,略逊于 0.1
0.5 ≈ -1300 ❌ 崩
0.8 ≈ -1300 ❌ 崩

现象:0.1 / 0.3 还能学,0.5 / 0.8 直接"躺平",reward 掉到 -1300 以下起不来。

原因 :Pendulum 要在杆顶维持平衡,不可能做到 θ˙=0\dot\theta = 0θ˙=0 的绝对静止,总有微小抖动。当 vel_penalty 大到 0.5+,智能体发现"一动就被狠罚",于是学到一条取巧策略 ------让杆垂到最下方(θ=π\theta=\piθ=π 处角速度天然接近 0),扣分反而比费力立杆少。典型 reward hacking

3.2 训练损失 & 价值损失

  • 0.1 / 0.3:loss 平滑下降,value_loss 低位稳定 → Critic 正常拟合。
  • 0.5 / 0.8:loss 和 value_loss 周期性暴冲到 2000+ → 奖励信号剧烈抖动,PPO trust region 被反复冲破,策略来回跳变。

四、结论

💡 默认 0.1 不是随便设的。本次实验验证了 Pendulum-v1 原版 0.1 * θ̇² 是 sweet spot:角速度有约束但不会压死探索。

几条可迁移经验:

  1. 奖励塑形先松后紧:新环境第一次调,惩罚系数从默认值往小试,能学到后再收紧;反过来容易直接学崩。
  2. "躺平" = 惩罚过重:智能体苟在角落不动而非完成任务,先查是不是某项惩罚太重。
  3. loss 暴冲 + reward 趴窝 这对组合,90% 是奖励函数问题,不是 lr 或 clip。

五、可扩展方向

  • vel_penalty 做成随时间衰减的 curriculum(前期松鼓励起摆,后期紧鼓励稳住);
  • |θ + π| 下垂惩罚,强行杜绝躺平策略;

TensorBoard:tensorboard --logdir ./result

相关推荐
灵晔君1 小时前
【C++】标准模板库STL——set /multiset/map /multimap
开发语言·c++
Sylvia33.1 小时前
足球数据接口开发实战:如何用火星数据API盘活赛事应用
java·服务器·开发语言·数据库·python
z落落2 小时前
C# WinForm 自定义控件
开发语言·c#
lupai2 小时前
身份证二要素实名认证 API 落地应用指南
python
ch.ju2 小时前
Java程序设计(第3版)第四章——匿名内部类
java·开发语言
cxr8282 小时前
大语言模型上下文缓存命中率测试全场景清单
人工智能·python·算法·缓存·语言模型·自然语言处理·llm
某林2122 小时前
大模型边缘部署到底层硬件闭环
python·架构·机器人·硬件架构·ros2
LadenKiller2 小时前
最新量化软件选择,先按能力判断表达生成和执行
人工智能·python
geovindu2 小时前
go: Enumeration Algorithm
开发语言·后端·算法·golang·枚举算法