Week 12 - 学生练习

Actor-Critic 方法

练习目标

  • 巩固对 Actor-Critic (AC) 框架的理解,包括 Actor 和 Critic 的角色分工。
  • 掌握 AC 方法如何结合策略梯度和 TD 学习来降低方差。
  • 理解使用 TD 误差作为优势函数估计来更新 Actor 的原理。
  • 区分 A2C 和 A3C 的基本概念。
  • 练习使用 Stable Baselines3 (SB3) 运行 A2C 算法。
  • 通过实验对比 A2C 和 DQN 在离散动作任务上的表现。
  • 理解 A2C 处理连续动作空间的能力。

练习内容

练习 1: Actor-Critic 概念

  1. 框架组成: Actor-Critic (AC) 框架包含哪两个主要组成部分?它们各自的作用是什么?(提示:一个负责选动作,一个负责评估)
  2. Critic 的作用: Critic 网络(通常学习 \(V\) 函数)是如何帮助 Actor 网络(策略网络)学习的?它提供了什么关键信息来指导 Actor 的更新?相比于 REINFORCE 使用的蒙特卡洛回报 \(G_t\),这个信息有什么优势?
  3. 更新规则:
    • 在基本的 Actor-Critic 方法中,Actor (策略参数 \(\theta\)) 的更新规则通常是什么样的?(写出包含 TD 误差 \(\delta\) 的更新公式)
    • Critic (价值参数 \(w\)) 的更新规则通常是什么样的?(写出包含 TD 误差 \(\delta\) 的更新公式)
  4. A2C vs. A3C: A2C 和 A3C 的主要区别是什么?哪个是同步更新,哪个是异步更新?哪个在现代实践中更常用?

练习 2: 优势函数估计

  1. 优势函数 \(A_{\pi}(s, a)\): 回顾其定义,它衡量了什么?
  2. TD 误差作为估计: 为什么可以用 TD 误差 \(\delta_t = R + \gamma V(S') - V(S)\) 来近似优势函数 \(A_{\pi}(s, a)\)?(提示:思考 \(\delta_t\) 的期望与 \(A_{\pi}\) 的关系)
  3. 为何有效: 相比于直接使用 \(Q_{\pi}(S, A)\)\(G_t\),使用优势函数(或其估计 \(\delta_t\))来乘以 Score Function (\(\nabla \log \pi\)) 进行策略梯度更新,主要的好处是什么?

练习 3: A2C 挑战实验 - 月球登陆器 (LunarLander-v2)

本练习旨在让你运用 A2C 算法解决一个比 CartPole 更具挑战性的环境:LunarLander-v2。你将需要设置 A2C 模型,训练它,评估其性能,并尝试调整超参数以获得更好的结果。该环境在 CPU 上应有合理的训练时间。

环境介绍: LunarLander-v2

  • 目标: 控制一个登陆器安全地降落在月球表面的目标区域(两个黄色旗帜之间)。安全降落意味着登陆器停下来,并且两个腿都接触地面。
  • 状态空间 (连续): 8个值,包括登陆器的位置 (x, y),线速度 (vx, vy),角度,角速度,以及两个腿是否接触地面 (布尔值)。
  • 动作空间 (离散): 4个动作:0-什么都不做,1-点燃左侧引擎,2-点燃主引擎,3-点燃右侧引擎。
  • 奖励:
    • 移动到目标区域会获得奖励。
    • 坠毁会获得 -100 分。
    • 成功降落会获得 +100 分。
    • 每条腿接触地面会获得 +10 分。
    • 点燃主引擎会消耗少量燃料(小的负奖励)。
    • 环境在获得 +200 分时被认为解决。

1. 实验设置与代码实现:

参考 Lab 7 中 A2C on CartPole 的代码结构,你需要进行以下调整来训练 LunarLander-v2

  • 环境名称:"CartPole-v1" 更改为 "LunarLander-v2"

  • 并行环境数量 (n_envs): 对于 LunarLander-v2,可以尝试使用 8 或 16 个并行环境。

    # 示例:
    env_id = "LunarLander-v2"
    vec_env = make_vec_env(env_id, n_envs=8)
  • A2C 模型超参数: LunarLander-v2 可能比 CartPole 需要不同的超参数设置。以下是一些建议的初始值,你可能需要调整它们:

    • policy: "MlpPolicy"
    • gamma: 0.99 (折扣因子)
    • n_steps: 516。这个参数定义了每个环境在进行一次更新之前运行的步数。较大的 n_steps 可以减少 TD 误差的方差,但可能会引入偏差。
    • vf_coef: 0.5 (值函数损失的系数,用于平衡 Actor 和 Critic 的学习)。
    • ent_coef: 0.01。熵系数,用于鼓励探索。LunarLander 比 CartPole 更需要探索,所以一个小的正值可能有助于学习。
    • learning_rate: 7e-4 (0.0007) 或 1e-3 (0.001)。可以尝试不同的学习率。
    • tensorboard_log: 设置一个目录来保存 TensorBoard 日志。
    # 示例:
    model = A2C("MlpPolicy", vec_env, verbose=1,
                gamma=0.99,
                n_steps=5,        # 初始尝试值
                vf_coef=0.5,
                ent_coef=0.01,    # 为 LunarLander 增加少量熵正则化
                learning_rate=7e-4,
                tensorboard_log="./a2c_lunarlander_logs/")
  • 训练总步数 (total_timesteps): LunarLander-v2 通常需要比 CartPole 更多的训练步数。建议从 200_000500_000 步开始。如果你的 CPU 较快,可以尝试更多步数。

    # 示例:
    model.learn(total_timesteps=300_000, log_interval=100, tb_log_name="A2C_LunarLander_run1")

    注意 log_intervaltb_log_name 的使用,方便在 TensorBoard 中区分不同的运行。

2. 训练与监控:

  • 运行你的脚本开始训练。
  • 使用 TensorBoard 监控训练过程。特别关注以下指标:
    • rollout/ep_rew_mean: 平均回合奖励,这是衡量智能体性能的关键指标。
    • train/value_loss: Critic (值函数) 的损失。
    • train/policy_loss: Actor (策略) 的损失。
    • train/entropy_loss: 熵损失 (如果 ent_coef > 0)。
    • 观察 ep_rew_mean 是否随着训练的进行而稳步上升。

3. 评估模型:

  • 训练完成后,使用 evaluate_policy 函数评估你的模型在多个回合中的平均表现。

    # 示例:
    eval_env = gym.make(env_id) # LunarLander-v2, render_mode="human" 可用于可视化
    mean_reward, std_reward = evaluate_policy(model, eval_env, n_eval_episodes=20, deterministic=True)
    print(f"Evaluation results (A2C on LunarLander): Mean reward = {mean_reward:.2f} +/- {std_reward:.2f}")
    eval_env.close()
    • deterministic=True 表示在评估时 Actor 选择概率最大的动作。

4. 实验分析与报告:

  • 基础性能: 记录你使用初始超参数训练后得到的 ep_rew_mean 训练曲线截图和最终的评估 mean_reward。模型是否成功解决了环境(平均奖励达到约 +200)?
  • 超参数调整 (挑战部分):
    • 选择至少 两个 你认为对 LunarLander-v2 性能影响较大的超参数进行调整(例如 learning_rate, n_steps, ent_coef, 或网络结构 policy_kwargs 中的 net_arch)。
    • 对于每个调整的超参数,进行一次新的训练。简要说明你为什么选择调整该参数以及你期望它如何影响学习过程。
    • 记录调整后的训练曲线和评估结果。比较不同参数设置下的性能差异。
    • 提示:
      • learning_rate: 太高可能导致不稳定,太低可能导致收敛缓慢。
      • n_steps: 影响 TD 误差的偏差-方差权衡。
      • ent_coef: 调整探索与利用的平衡。太高可能导致策略过于随机,太低可能导致陷入次优。
      • net_arch: 默认是 [dict(pi=[64, 64], vf=[64, 64])]。对于更复杂的 LunarLander,可以尝试更大的网络,如 [dict(pi=[256, 256], vf=[256, 256])] (通过 policy_kwargs 设置)。
  • A2C 适用性: 你认为 A2C 算法是否适合解决 LunarLander-v2 这样的问题?为什么?(考虑其特性,如处理离散动作、on-policy 性质、多环境并行等)。
  • 遇到的问题与思考 (可选): 在实验过程中,你遇到了哪些问题?你是如何解决的?或者有什么其他有趣的发现或思考?

练习 4: A2C 高级挑战 - 双足行走机器人 (BipedalWalker-v3)

本练习将引导你使用 A2C 算法挑战一个更复杂、动作空间连续的环境:BipedalWalker-v3。这个任务比月球登陆器更难,需要更长的训练时间和更细致的超参数调整。

环境介绍: BipedalWalker-v3

  • 目标: 控制一个两足机器人尽可能远地行走。
  • 状态空间 (连续): 24个值,包括机器人躯干的角度和角速度、水平和垂直速度、关节的角度和角速度,以及10个激光雷达传感器读数,用于感知前方地形。
  • 动作空间 (连续): 4个值,代表施加到四个关节(两个髋关节,两个膝关节)的力矩。每个力矩的范围通常在 [-1, 1] 之间。
  • 奖励:
    • 每向前走一步都会获得奖励。
    • 机器人摔倒会受到惩罚。
    • 使用力矩会消耗少量能量(小的负奖励)。
    • 成功行走超过约230个单位的距离(通常对应总奖励约 +300)被认为是解决了这个环境。
  • 解决条件: 在连续100个回合中平均奖励大于等于 +300。

重要提示: BipedalWalker-v3 是一个计算密集型任务。在普通的 CPU 上训练可能需要数小时甚至更长时间才能看到显著的性能提升。请有耐心,并根据你的硬件情况调整训练总步数。

1. 实验设置与代码实现:

参考之前练习中 A2C 的代码结构,针对 BipedalWalker-v3 进行调整:

  • 环境名称: env_id = "BipedalWalker-v3"

  • 并行环境数量 (n_envs): 建议使用较多的并行环境,例如 n_envs=16 或更多(如果你的 CPU 核心数允许)。

    # 示例:
    env_id = "BipedalWalker-v3"
    # 对于 BipedalWalker,通常建议使用 Monitor 包装器来跟踪回合统计信息,即使是向量化环境
    # from stable_baselines3.common.monitor import Monitor
    # vec_env = make_vec_env(env_id, n_envs=16, wrapper_class=Monitor) # Monitor is often good for complex envs
    vec_env = make_vec_env(env_id, n_envs=16)
  • A2C 模型超参数: BipedalWalker-v3 对超参数非常敏感。以下是一些可以作为起点的建议值,你很可能需要进行大量调整:

    • policy: "MlpPolicy"

    • gamma: 0.99 (折扣因子)

    • n_steps: 建议尝试较大的值,如 32, 64, 128, 甚至 256。这决定了每个 actor 收集多少步经验才进行一次更新。更大的 n_steps 意味着更大的批次大小 (n_envs * n_steps),有助于稳定学习,但会降低策略更新的频率。

    • vf_coef: 0.5 (标准值)

    • ent_coef: 0.0010.0。BipedalWalker 可能不需要很强的熵正则化,有时设为0效果也不错。可以从一个小值开始尝试。

    • learning_rate: 建议使用较小的学习率,例如 1e-4 (0.0001) 或 2.5e-4 (0.00025)。也可以考虑使用学习率调度 (SB3 支持,例如 lr_schedule = ConstantSchedule(value=2.5e-4) 或线性衰减)。

    • gae_lambda: 0.95 (Generalized Advantage Estimation 的 lambda 参数,通常效果良好)

    • max_grad_norm: 0.5 (梯度裁剪,防止梯度爆炸)

    • policy_kwargs: BipedalWalker-v3 通常受益于更大的网络。

      # 示例 policy_kwargs:
      policy_kwargs = dict(
          net_arch=dict(pi=[256, 256], vf=[256, 256]), # Actor 和 Critic 各自两层,每层256个神经元
          # activation_fn=torch.nn.ReLU # 可以尝试不同的激活函数
      )
    # 示例模型定义:
    model = A2C("MlpPolicy", vec_env, verbose=1,
                gamma=0.99,
                n_steps=128,         # 初始尝试较大值
                vf_coef=0.5,
                ent_coef=0.001,      # 初始尝试小值
                learning_rate=2.5e-4,
                gae_lambda=0.95,
                max_grad_norm=0.5,
                policy_kwargs=policy_kwargs, # 使用自定义网络结构
                tensorboard_log="./a2c_bipedalwalker_logs/")
  • 训练总步数 (total_timesteps): 这是关键。BipedalWalker-v3 通常需要 至少 1,000,000 到 5,000,000 步才能看到较好的结果,甚至更多才能完全解决。请根据你的计算机性能和可用时间设定。即使只训练 500,000 步,也可能需要相当长的时间。

    # 示例:
    # 开始时可以先训练较少步数 (例如 200k-500k) 来检查代码和基本参数是否合理
    # 然后再进行更长时间的训练
    model.learn(total_timesteps=1_000_000, log_interval=1000, tb_log_name="A2C_BipedalWalker_run1")

2. 训练与监控:

  • 启动训练脚本。由于训练时间较长,建议在后台运行或使用 screen/tmux 会话。
  • 使用 TensorBoard 密切监控 rollout/ep_rew_mean。期望看到奖励缓慢但稳定地增长。
  • 同时关注 train/value_loss, train/policy_loss。如果损失出现 NaN 或剧烈震荡,可能需要调整学习率或网络结构。

3. 评估模型:

  • 训练达到预设步数或你认为满意后,评估模型。

    # 示例:
    eval_env = gym.make(env_id) # render_mode="human" 可用于可视化,但评估时通常不渲染
    mean_reward, std_reward = evaluate_policy(model, eval_env, n_eval_episodes=10, deterministic=True)
    print(f"Evaluation results (A2C on BipedalWalker): Mean reward = {mean_reward:.2f} +/- {std_reward:.2f}")
    eval_env.close()

4. 实验分析与报告:

  • 训练曲线与性能:
    • 提供 rollout/ep_rew_mean 的 TensorBoard 截图。
    • 记录最终的评估 mean_reward 和训练的总步数。
    • 你的模型在训练结束时达到了什么水平?是否观察到了持续学习的趋势?
  • 超参数探索 (关键部分):
    • BipedalWalker-v3 对超参数非常敏感。详细记录你尝试过的主要超参数组合(至少尝试调整 两个 不同的参数或参数组合,如 learning_rate, n_steps, ent_coef, net_arch)。
    • 解释你为什么选择这些参数进行调整,以及调整后的效果如何(基于 TensorBoard 曲线和评估结果)。
    • 哪个(或哪些)参数的调整对性能提升最大?
  • 挑战分析:
    • 你认为是什么使得 BipedalWalker-v3 这个环境比 LunarLander-v2 更具挑战性?
    • A2C 在处理这种复杂连续控制任务时表现如何?你观察到了哪些优点或潜在的局限性?
  • 训练时间与资源:
    • 大致记录你的训练时长和所用步数。
  • 遇到的问题与解决方案 (可选): 分享你在实验中遇到的任何具体问题以及你是如何尝试解决的。

提交要求

  • 请将你的答案整理成一个文档(如 Word, PDF, 或 Markdown 文件)。
  • 对于练习 1, 2, 3, 4,请清晰地回答问题并阐述理由。
  • 文件命名格式:姓名_学号_Week12_Exercise.xxx
  • 通过教学平台提交。