首页 训练探测器正确降落在月球🌕上
文章
取消

训练探测器正确降落在月球🌕上

跑模型时间!

来自HuggingFace 🤗 强化学习课程

我们将训练我们智能体(月球着陆器正确登陆月球。为此,智能体需要学习调整其速度和位置(水平、垂直和角度)以正确着陆。

每一步:

  • 我们的代理从 环境中接收状态(S0) —— 我们接收游戏的第一帧(环境)。
  • 根据该 状态 (S0), 代理采取 行动 (A0) —— 我们的代理将向右移动。
  • 环境转换到 新状态 (S1) —— 新框架。
  • 环境给智能体一些 奖励(R1) —— 我们没有死 (正奖励+1)

任务

观测结果是一个大小为 8 的向量,其中每个值都包含有关着陆器的不同信息:

  • 水平坐标 (x)
  • 垂直坐标 (y)
  • 水平速度(x)
  • 垂直速度(y)
  • 角度
  • 角速度
  • 左腿接触点是否触地(布尔值)
  • 右腿接触点是否触地(布尔值)

动作空间(智能体可以采取的一组可能动作)是离散的,有 4 个可用动作🎮:

  • 行动 0:什么也不做,
  • 动作1:启动左方向引擎,
  • 动作2:启动主引擎,
  • 动作3:向右发射定向引擎。

奖励函数(在每个时间步给出奖励的函数)💰:每走一步后都会给予奖励。一个episode的总奖励是该episode中所有步骤的奖励之和。对于每一步,奖励:

  • 着陆器离着陆场越近/越远,则增加/减少。
  • 着陆器移动得越慢/越快,则增加/减少。
  • 着陆器倾斜得越多(角度不是水平的),该值就越小。
  • 每一条与地面接触的腿增加 10 分。
  • 侧引擎点火每帧减少 0.03 点。
  • 主机每点火一帧就减少 0.3 点。
  • 该剧集因坠毁或安全着陆而分别获得-100 或 +100 分的额外奖励。

如果一个情节的得分至少为 200 分,则该情节被视为一个解决方案。

创建环境代码,基于环境库 Gymnasium:

1
2
# Create the environment
env = make_vec_env('LunarLander-v2', n_envs=16)

模型

为了解决这个问题,我们将使用 Stable-Baselines3 的 Proximal Policy OptimizationPPO 是本课程中学习的 SOTA(最先进的)深度强化学习算法之一。

PPO 是以下各项的组合:

  • 基于价值的强化学习方法:学习行动价值函数,该函数将告诉我们在给定状态和行动的情况下要采取的最有价值的行动
  • 基于策略的强化学习方法:学习一个策略,该策略将为我们提供动作的概率分布

创建模型

1
2
3
4
5
6
7
8
9
10
11
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  
)

训练我们的代理 1,000,000 个时间步,不要忘记在 Colab 上使用 GPU。大约需要 20 分钟

1
2
3
4
5
# Train it for 1,000,000 timesteps
model.learn(total_timesteps=1000000)
# Save the model
model_name = "ppo-LunarLander-v2"
model.save(model_name)

一次典型的迭代过程输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-----------------------------------------
| rollout/                |             |
|    ep_len_mean          | 524         |
|    ep_rew_mean          | 19          |
| time/                   |             |
|    fps                  | 1297        |
|    iterations           | 16          |
|    time_elapsed         | 202         |
|    total_timesteps      | 262144      |
| train/                  |             |
|    approx_kl            | 0.005388215 |
|    clip_fraction        | 0.0445      |
|    clip_range           | 0.2         |
|    entropy_loss         | -1.25       |
|    explained_variance   | 0.876       |
|    learning_rate        | 0.0003      |
|    loss                 | 56.7        |
|    n_updates            | 60          |
|    policy_gradient_loss | -0.0021     |
|    value_loss           | 111         |
-----------------------------------------

评估

1
2
3
4
5
6
7
8
# Create a new environment for evaluation
eval_env = Monitor(gym.make("LunarLander-v2"))

# Evaluate the model with 10 evaluation episodes and deterministic=True
mean_reward, std_reward = evaluate_policy(model, eval_env, n_eval_episodes=10, deterministic=True)

# Print the results
print(f"mean_reward={mean_reward:.2f} +/- {std_reward}")

输出:

1
mean_reward=262.39 +/- 20.647280625927973

上传模型到 Hub

准备一个具有 write 角色的令牌。在 notebook 中使用令牌登录可以运行代码:

1
2
notebook_login()
!git config --global credential.helper store

如果不想使用 Google Colab 或 Jupyter Notebook,则需要使用以下命令:huggingface-cli login

使用package_to_hub()函数将经过训练的代理推送到 Hub:

  • model:我们训练好的模型。
  • model_name:我们定义的训练模型的名称model_save
  • model_architecture:我们使用的模型架构,在我们的例子中是 PPO
  • env_id:在我们的例子中是环境的名称LunarLander-v2
  • eval_env:eval_env中定义的评估环境
  • repo_id:将创建/更新的 Hugging Face Hub 存储库的名称repo_id = {username}/{repo_name}

💡一个好名字是{username}/{model_architecture}-{env_id}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import gymnasium as gym
from stable_baselines3.common.vec_env import DummyVecEnv
from stable_baselines3.common.env_util import make_vec_env

from huggingface_sb3 import package_to_hub

# repo_id is the id of the model repository from the Hugging Face Hub (repo_id = {organization}/{repo_name} for instance ThomasSimonini/ppo-LunarLander-v2
repo_id = "QMMMS/ppo-LunarLander-v2"

# Define the name of the environment
env_id = "LunarLander-v2"

# Create the evaluation env and set the render_mode="rgb_array"
eval_env = DummyVecEnv([lambda: Monitor(gym.make(env_id, render_mode="rgb_array"))])

#  Define the model architecture we used
model_architecture = "PPO"

# Define the commit message
commit_message = "Upload PPO LunarLander-v2 trained agent"

# method save, evaluate, generate a model card and record a replay video of your agent before pushing the repo to the hub
package_to_hub(model=model, 
               model_name=model_name,
               model_architecture=model_architecture,
               env_id=env_id, 
               eval_env=eval_env,
               repo_id=repo_id, 
               commit_message=commit_message)

随后就能看到一个仓库会被自动创建,训练好的模型被上传。

从 Hub 加载模型

  1. 复制其 repo_id,例如QMMMS/ppo-LunarLander-v2
  2. 使用 load_from_hub ,需要存储库中保存的模型及其扩展名(*.zip),例如ppo-LunarLander-v2.zip

因为我从 Hub 下载的模型是用 Gym(Gymnasium 的前版本)训练的,所以我们需要安装 shimmy 一个 API 转换工具,它将帮助我们正确运行环境。

1
!pip install shimmy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from huggingface_sb3 import load_from_hub
repo_id = "QMMMS/ppo-LunarLander-v2" # The repo_id
filename = "ppo-LunarLander-v2.zip" # The model filename.zip

# When the model was trained on Python 3.8 the pickle protocol is 5
# But Python 3.6, 3.7 use protocol 4
# In order to get compatibility we need to:
# 1. Install pickle5 (we done it at the beginning of the colab)
# 2. Create a custom empty object we pass as parameter to PPO.load()
custom_objects = {
            "learning_rate": 0.0,
            "lr_schedule": lambda _: 0.0,
            "clip_range": lambda _: 0.0,
}

checkpoint = load_from_hub(repo_id, filename)
model = PPO.load(checkpoint, custom_objects=custom_objects, print_system_info=True)

评估模型

1
2
3
eval_env = Monitor(gym.make("LunarLander-v2"))
mean_reward, std_reward = evaluate_policy(model, eval_env, n_eval_episodes=10, deterministic=True)
print(f"mean_reward={mean_reward:.2f} +/- {std_reward}")
本文由作者按照 CC BY 4.0 进行授权

强化学习介绍

训练狗狗🐕捡起我们扔的棍子