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 概念
- 框架组成: Actor-Critic (AC) 框架包含哪两个主要组成部分?它们各自的作用是什么?(提示:一个负责选动作,一个负责评估)
- Critic 的作用: Critic 网络(通常学习 \(V\) 函数)是如何帮助 Actor 网络(策略网络)学习的?它提供了什么关键信息来指导 Actor 的更新?相比于 REINFORCE 使用的蒙特卡洛回报 \(G_t\),这个信息有什么优势?
- 更新规则:
- 在基本的 Actor-Critic 方法中,Actor (策略参数 \(\theta\)) 的更新规则通常是什么样的?(写出包含 TD 误差 \(\delta\) 的更新公式)
- Critic (价值参数 \(w\)) 的更新规则通常是什么样的?(写出包含 TD 误差 \(\delta\) 的更新公式)
- A2C vs. A3C: A2C 和 A3C 的主要区别是什么?哪个是同步更新,哪个是异步更新?哪个在现代实践中更常用?
练习 2: 优势函数估计
- 优势函数 \(A_{\pi}(s, a)\): 回顾其定义,它衡量了什么?
- TD 误差作为估计: 为什么可以用 TD 误差 \(\delta_t = R + \gamma V(S') - V(S)\) 来近似优势函数 \(A_{\pi}(s, a)\)?(提示:思考 \(\delta_t\) 的期望与 \(A_{\pi}\) 的关系)
- 为何有效: 相比于直接使用 \(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 个并行环境。# 示例: = "LunarLander-v2" env_id = make_vec_env(env_id, n_envs=8) vec_env
A2C 模型超参数:
LunarLander-v2
可能比 CartPole 需要不同的超参数设置。以下是一些建议的初始值,你可能需要调整它们:policy
:"MlpPolicy"
gamma
:0.99
(折扣因子)n_steps
:5
或16
。这个参数定义了每个环境在进行一次更新之前运行的步数。较大的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 日志。
# 示例: = A2C("MlpPolicy", vec_env, verbose=1, model =0.99, gamma=5, # 初始尝试值 n_steps=0.5, vf_coef=0.01, # 为 LunarLander 增加少量熵正则化 ent_coef=7e-4, learning_rate="./a2c_lunarlander_logs/") tensorboard_log
训练总步数 (
total_timesteps
):LunarLander-v2
通常需要比 CartPole 更多的训练步数。建议从200_000
到500_000
步开始。如果你的 CPU 较快,可以尝试更多步数。# 示例: =300_000, log_interval=100, tb_log_name="A2C_LunarLander_run1") model.learn(total_timesteps
注意
log_interval
和tb_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
函数评估你的模型在多个回合中的平均表现。# 示例: = gym.make(env_id) # LunarLander-v2, render_mode="human" 可用于可视化 eval_env = evaluate_policy(model, eval_env, n_eval_episodes=20, deterministic=True) mean_reward, std_reward 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 核心数允许)。# 示例: = "BipedalWalker-v3" env_id # 对于 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 = make_vec_env(env_id, n_envs=16) vec_env
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.001
或0.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: = dict( policy_kwargs =dict(pi=[256, 256], vf=[256, 256]), # Actor 和 Critic 各自两层,每层256个神经元 net_arch# activation_fn=torch.nn.ReLU # 可以尝试不同的激活函数 )
# 示例模型定义: = A2C("MlpPolicy", vec_env, verbose=1, model =0.99, gamma=128, # 初始尝试较大值 n_steps=0.5, vf_coef=0.001, # 初始尝试小值 ent_coef=2.5e-4, learning_rate=0.95, gae_lambda=0.5, max_grad_norm=policy_kwargs, # 使用自定义网络结构 policy_kwargs="./a2c_bipedalwalker_logs/") tensorboard_log
训练总步数 (
total_timesteps
): 这是关键。BipedalWalker-v3
通常需要 至少 1,000,000 到 5,000,000 步才能看到较好的结果,甚至更多才能完全解决。请根据你的计算机性能和可用时间设定。即使只训练 500,000 步,也可能需要相当长的时间。# 示例: # 开始时可以先训练较少步数 (例如 200k-500k) 来检查代码和基本参数是否合理 # 然后再进行更长时间的训练 =1_000_000, log_interval=1000, tb_log_name="A2C_BipedalWalker_run1") model.learn(total_timesteps
2. 训练与监控:
- 启动训练脚本。由于训练时间较长,建议在后台运行或使用
screen
/tmux
会话。 - 使用 TensorBoard 密切监控
rollout/ep_rew_mean
。期望看到奖励缓慢但稳定地增长。 - 同时关注
train/value_loss
,train/policy_loss
。如果损失出现NaN
或剧烈震荡,可能需要调整学习率或网络结构。
3. 评估模型:
训练达到预设步数或你认为满意后,评估模型。
# 示例: = gym.make(env_id) # render_mode="human" 可用于可视化,但评估时通常不渲染 eval_env = evaluate_policy(model, eval_env, n_eval_episodes=10, deterministic=True) mean_reward, std_reward 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
。 - 通过教学平台提交。