Unit 2 训练你的第一个深度强化学习智能体 LunarLander-v3
Unit 2: Train your first Deep Reinforcement Learning Agent
训练一个深度强化学习智能体——一个月球着陆器智能体,它会学习如何在月球上正确着陆 🌕,并且使用深度强化学习库 Stable-Baselines3 来训练该智能体。
安装依赖项:
- gymnasium[box2d]:包含 LunarLander-v3 环境。
- stable-baselines3[extra]:深度强化学习库。
导入所需的包
import gymnasium
from stable_baselines3 import PPO
from stable_baselines3.common.env_util import make_vec_env
from stable_baselines3.common.evaluation import evaluate_policy
from stable_baselines3.common.monitor import Monitor
了解 Gymnasium 及其工作原理
Gymnasium 是由 Farama 基金会维护的 Gym 库的新版本,Gymnasium 库提供了以下两项功能:
- 一个接口,允许你创建强化学习(RL)环境。
- 一系列环境集合(如 gym-control、Atari、Box2D 等)。
使用 Gymnasium 时:
-
通过 gymnasium.make() 来创建环境。
-
使用 observation = env.reset() 将环境重置为其初始状态。
在每一步操作中:
-
使用模型获取一个动作(在本例中,我们采取一个随机动作)。
-
使用 env.step(action),我们在环境中执行该动作,并获取以下信息:
- observation:新的状态(st+1)。
- reward:执行该动作后获得的奖励。
- terminated:指示该回合是否已结束(智能体是否到达了终止状态)。
- truncated:这是新版本中引入的,它表示时间限制或智能体是否超出了环境边界等情况。
- info:一个字典,提供额外的信息(具体内容取决于环境)。
如果回合已结束:
- 使用 observation = env.reset() 将环境重置为其初始状态。
import gymnasium as gym# 首先,创建一个LunarLander-v3的环境
env = gym.make("LunarLander-v3")# 初始化环境
observation, info = env.reset()for _ in range(20):# 采取一个随机动作action = env.action_space.sample()print("Action taken:", action)# 执行这个动作,并获取# next_state, reward, terminated, truncated and infoobservation, reward, terminated, truncated, info = env.step(action)# 如果游戏终止(在我们的例子中,我们着陆、崩溃)或被截断(超时)if terminated or truncated:# 重置环境print("Environment is reset")observation, info = env.reset()env.close()
Action taken: 0
Action taken: 3
Action taken: 3
略略路
Action taken: 1
Action taken: 3
Action taken: 2
观察空间
状态是一个八维向量:包含着陆器在 x 轴和 y 轴上的坐标、在 x 轴和 y 轴上的线速度、角度、角速度,以及两个布尔值,分别表示着陆器的每条腿是否与地面接触。
# We create our environment with gym.make("<name_of_the_environment>")
env = gym.make("LunarLander-v3")
env.reset()
print("_____OBSERVATION SPACE_____ \n")
print("Observation Space Shape", env.observation_space.shape)
print("Sample observation", env.observation_space.sample()) # Get a random observation
_____OBSERVATION SPACE_____ Observation Space Shape (8,)
Sample observation [-0.39945436 -0.36198062 -7.3894777 7.566114 -4.997432 4.54730220.53182733 0.834311 ]
动作空间
有四个离散动作可供选择:
0:不执行任何操作(即保持当前状态)
1:启动左侧姿态调整引擎(即向左喷射)
2:启动主引擎(即向下喷射,提供主要推力)
3:启动右侧姿态调整引擎(即向右喷射)
print("\n _____ACTION SPACE_____ \n")
print("Action Space Shape", env.action_space.n)
print("Action Space Sample", env.action_space.sample()) # Take a random action
_____ACTION SPACE_____ Action Space Shape 4
Action Space Sample 3
奖励机制
每一步操作后都会给予一个奖励。一个回合的总奖励是该回合内所有步骤奖励的总和。
对于每一步操作,奖励的计算方式如下:
- 着陆器距离着陆平台越近,奖励增加;距离越远,奖励减少。
- 着陆器移动速度越慢,奖励增加;移动速度越快,奖励减少。
- 着陆器倾斜程度越大(角度非水平),奖励减少。
- 着陆器的每条腿与地面接触时,奖励增加 10 分。
- 侧边引擎每喷射一帧,奖励减少 0.03 分。
- 主引擎每喷射一帧,奖励减少 0.3 分。
如果着陆器坠毁,该回合将获得 -100 分的额外惩罚;如果安全着陆,则获得 +100 分的额外奖励。
如果一个回合的得分至少达到 200 分,则认为该回合的解决方案是成功的。
回合终止条件
当出现以下情况时,回合结束:
- 着陆器坠毁(着陆器主体与月球表面接触);
- 着陆器飞出视野范围(x 坐标大于 1);
- 着陆器处于“休眠”状态。根据 Box2D 的文档说明,一个处于非唤醒状态(not awake)的物体是指该物体既不移动也不与其他任何物体发生碰撞:
当 Box2D 判定一个物体(或一组物体)已经静止时,该物体会进入休眠状态,此时 CPU 开销非常小。
如果一个处于唤醒状态的物体与一个处于休眠状态的物体发生碰撞,那么休眠状态的物体会被唤醒。
此外,如果与物体相连的关节或接触点被销毁,该物体也会被唤醒。
向量化环境
创建一个包含 16 个独立环境的向量化环境(这是一种将多个独立环境叠加成一个单一环境的方法)。通过这种方式,我们在训练过程中将获得更多样化的经验。
# Create the environment
env = make_vec_env("LunarLander-v3", n_envs=16)
环境参数
Lunar Lander(月球着陆器)环境具有大量的参数,这些参数允许用户自定义环境的各个方面,以适应不同的训练需求和实验设置。
import gymnasium as gym
env = gym.make("LunarLander-v3", continuous=False, gravity=-10.0,enable_wind=False, wind_power=15.0, turbulence_power=1.5)
-
continuous
参数用于确定是使用离散动作还是连续动作(分别对应引擎的油门控制),动作空间将相应地设置为Discrete(4)
或Box(-1, +1, (2,), dtype=np.float32)
。对于连续动作,动作的第一个坐标决定主引擎的油门,而第二个坐标指定侧向助推器的油门。给定一个动作np.array([main, lateral])
,如果main < 0
,主引擎将完全关闭;当0 <= main <= 1
时,油门会从 50% 线性变化到 100%(特别地,主引擎在功率低于 50% 时不会工作)。类似地,如果-0.5 < lateral < 0.5
,侧向助推器将完全不会启动。如果lateral < -0.5
,左侧助推器将启动;如果lateral > 0.5
,右侧助推器将启动。同样地,油门会在 -1 和 -0.5(以及 0.5 和 1)之间从 50% 线性变化到 100%。 -
gravity
参数用于设定重力常数,其取值范围被限定在 0 到 -12 之间。默认值为 -10.0。 -
enable_wind
参数用于确定是否对着陆器施加风力效果。风力是通过函数tanh(sin(2 k (t+C)) + sin(pi k (t+C)))
生成的,其中k
被设置为 0.01,而C
是在 -9999 和 9999 之间随机采样的值。 -
wind_power
参数用于设定施加在飞行器上的线性风力的最大强度。wind_power 的推荐取值范围在 0.0 到 20.0 之间。 -
turbulence_power
参数用于设定施加在飞行器上的旋转风力的最大强度。turbulence_power
的推荐取值范围在 0.0 到 2.0 之间。
创建模型
使用深度强化学习库——Stable Baselines3(简称SB3)创建模型,SB3 是一套基于 PyTorch 的强化学习算法的可靠实现。我们将使用 SB3 中的 PPO 算法。PPO(即近端策略优化,Proximal Policy Optimization)是最先进的(SOTA,state of the art)深度强化学习算法之一。
PPO 结合了以下两种方法:
- 基于价值的强化学习方法:学习一个动作价值函数,该函数能在给定状态和动作的情况下,告诉我们采取哪个动作最有价值。
- 基于策略的强化学习方法:学习一个策略,该策略能为我们提供一个动作上的概率分布。
Stable-Baselines3 的设置非常简单:
-
创建自己的环境(在我们的例子中,这一步已经在上面完成了)。
-
你需要定义想要使用的模型,并实例化该模型,例如:model = PPO(“MlpPolicy”)。
-
使用 model.learn 来训练智能体,并定义训练的时间步数。
# Create environment
env = gym.make('LunarLander-v3')
# Instantiate the agent
model = PPO(policy="MlpPolicy",env=env,n_steps=1024,batch_size=64,n_epochs=4,gamma=0.999,gae_lambda=0.98,ent_coef=0.01,verbose=1,
)
训练模型
# SOLUTION
# Train it for 1,000,000 timesteps
model.learn(total_timesteps=1000000)
# Save the model
model_name = "ppo-LunarLander-v3"
model.save(model_name)
---------------------------------
| rollout/ | |
| ep_len_mean | 94.2 |
| ep_rew_mean | -146 |
| time/ | |
| fps | 567 |
| iterations | 1 |
| time_elapsed | 1 |
| total_timesteps | 1024 |
---------------------------------
-------------------------------------------
| rollout/ | |
| ep_len_mean | 90.5 |
| ep_rew_mean | -189 |
| time/ | |
| fps | 524 |
| iterations | 2 |
| time_elapsed | 3 |
| total_timesteps | 2048 |
| train/ | |
| approx_kl | 0.00025148428 |
| clip_fraction | 0 |
| clip_range | 0.2 |
| entropy_loss | -1.39 |
| explained_variance | 0.000702 |
| learning_rate | 0.0003 |
| loss | 1.81e+03 |
| n_updates | 4 |
| policy_gradient_loss | -0.00137 |
| value_loss | 3.56e+03 |
-------------------------------------------略略略
------------------------------------------
| rollout/ | |
| ep_len_mean | 921 |
| ep_rew_mean | 116 |
| time/ | |
| fps | 539 |
| iterations | 249 |
| time_elapsed | 472 |
| total_timesteps | 254976 |
| train/ | |
| approx_kl | 0.0010052922 |
| clip_fraction | 0.00317 |
| clip_range | 0.2 |
| entropy_loss | -0.806 |
| explained_variance | 0.783 |
| learning_rate | 0.0003 |
| loss | 39.9 |
| n_updates | 992 |
| policy_gradient_loss | -0.000245 |
| value_loss | 244 |
------------------------------------------
------------------------------------------
| rollout/ | |
| ep_len_mean
评估智能体并可视化智能体的表现
- 记得要将环境封装在 Monitor 中。
- 现在,月球着陆器智能体已经训练完成 🚀,我们需要检查它的性能表现。
- Stable-Baselines3 提供了一个方法来实现这一点:evaluate_policy。
在接下来的步骤中,我们将看到如何自动评估你的智能体,在评估智能体时,你不应该使用训练时的环境,而是应该创建一个评估环境。
eval_env = Monitor(gym.make("LunarLander-v3"))
mean_reward, std_reward = evaluate_policy(model, eval_env, n_eval_episodes=10, deterministic=True)
print(f"mean_reward={mean_reward:.2f} +/- {std_reward}")
mean_reward=253.50 +/- 35.760438569719035
视频保存在./LunarLander-ppo目录下
eval_env = gym.wrappers.RecordVideo(gym.make("LunarLander-v3",render_mode="rgb_array"), video_folder="./LunarLander-ppo",disable_logger=True,fps=30)
observation, info = eval_env.reset()
while True:action = model.predict(observation)[0]observation, reward, terminated, truncated, info = eval_env.step(action)if terminated == True:break
eval_env.close()
LunarLander-v3