深度强化学习课程文档

动手实践

Hugging Face's logo
加入 Hugging Face 社区

并获取增强型文档体验

开始使用

动手实践

Ask a Question Open In Colab

现在我们已经学习了 Q 学习算法,让我们从头开始实现它,并在两种环境中训练我们的 Q 学习智能体。

  1. Frozen-Lake-v1(非滑冰和滑冰版本) ☃️:我们的智能体需要通过仅在冰冻方块 (F) 上行走,并避开洞 (H) 来**从起始状态 (S) 到达目标状态 (G)**。
  2. 自动驾驶出租车 🚖 需要**学习在城市中导航**,**将乘客从 A 点运送到 B 点**。
Environments

得益于一个排行榜,您可以将自己的结果与其他同学进行比较,并交流最佳实践以提高智能体的得分。谁将在单元 2 的挑战中获胜?

为了验证此动手实践以用于认证流程,您需要将训练好的出租车模型推送到 Hub,并**获得大于或等于 4.5 的结果**。

要查找您的结果,请访问排行榜并查找您的模型,**结果 = 平均奖励 - 奖励标准差**

有关认证流程的更多信息,请查看此部分 👉 https://huggingface.co/deep-rl-course/en/unit0/introduction#certification-process

您可以在这里查看您的进度 👉 https://huggingface.co/spaces/ThomasSimonini/Check-my-progress-Deep-RL-Course

**要开始动手实践,请点击“在 Colab 中打开”按钮** 👇

Open In Colab

我们强烈**建议学生使用 Google Colab 进行动手练习**,而不是在个人电脑上运行它们。

使用 Google Colab,**您可以专注于学习和实验,而无需担心设置环境的技术方面**。

单元 2:使用 FrozenLake-v1 ⛄ 和 Taxi-v3 🚕 的 Q 学习

Unit 2 Thumbnail

在本笔记本中,**您将从头开始编写第一个强化学习智能体**,使用 Q 学习玩 FrozenLake ❄️,将其与社区共享,并尝试不同的配置。

⬇️ 以下是您**在短短几分钟内就能实现**的示例。⬇️

Environments

🎮 环境:

📚 RL-Library:

我们一直在努力改进我们的教程,因此,**如果您在本笔记本中发现任何问题**,请在 GitHub 仓库中打开问题

本笔记本的目标 🏆

在本笔记本的最后,您将

  • 能够使用**Gymnasium**,环境库。
  • 能够从头开始编写 Q 学习智能体。
  • 能够**将训练好的智能体和代码推送到 Hub**,并附带漂亮的视频回放和评估分数 🔥。

本笔记本来自深度强化学习课程

Deep RL Course illustration

在本免费课程中,您将

  • 📖 学习深度强化学习的**理论和实践**。
  • 🧑‍💻 学习**使用著名的深度 RL 库**,如 Stable Baselines3、RL Baselines3 Zoo、CleanRL 和 Sample Factory 2.0。
  • 🤖 在**独特的环境中训练智能体**

还有更多检查📚教学大纲👉 https://simoninithomas.github.io/deep-rl-course

别忘了报名课程(我们收集您的电子邮件,以便在发布每个单元时发送链接,并向您提供有关挑战和更新的信息)。

保持联系的最佳方式是加入我们的 Discord 服务器,与社区和我们交流👉🏻 https://discord.gg/ydHrjt3WP5

先决条件🏗️

在深入研究笔记本电脑之前,您需要

🔲 📚 学习阅读第二单元的 Q 学习 🤗

Q 学习的简要回顾

Q 学习是 RL 算法,它

  • 训练Q 函数,一个动作值函数,它由Q 表在内部存储器中编码,其中包含所有状态-动作对值。

  • 给定一个状态和动作,我们的 Q 函数将在 Q 表中搜索相应的值。

Q function
  • 训练完成后,我们得到了一个最优 Q 函数,即最优 Q 表。

  • 而且,如果我们拥有最优 Q 函数,那么我们也拥有最优策略,因为我们知道对每个状态,应该采取的最佳动作。

Link value policy

但是,在开始时,我们的Q 表毫无用处,因为它为每个状态-动作对提供了任意值(大多数情况下我们将 Q 表初始化为 0 值)。但是,随着我们探索环境并更新 Q 表,它将为我们提供越来越好的近似值

q-learning.jpeg

这是 Q 学习的伪代码

Q-Learning

让我们编写第一个强化学习算法🚀

为了验证此动手实践以用于认证流程,您需要将训练好的出租车模型推送到 Hub,并**获得大于或等于 4.5 的结果**。

要查找您的结果,请访问排行榜并查找您的模型,**结果 = 平均奖励 - 奖励标准差**

有关认证流程的更多信息,请查看此部分 👉 https://huggingface.co/deep-rl-course/en/unit0/introduction#certification-process

安装依赖项并创建虚拟显示🔽

在笔记本电脑中,我们需要生成一个回放视频。为此,在使用 Colab 时,我们需要有一个虚拟屏幕来渲染环境(从而录制帧)。

因此,以下单元格将安装库,并创建和运行一个虚拟屏幕🖥

我们将安装多个库

  • gymnasium:包含 FrozenLake-v1 ⛄ 和 Taxi-v3 🚕 环境。
  • pygame:用于 FrozenLake-v1 和 Taxi-v3 的 UI。
  • numpy:用于处理我们的 Q 表。

Hugging Face Hub 🤗 作为一个中心位置,任何人都可以在其中共享和探索模型和数据集。它具有版本控制、指标、可视化和其他功能,使您可以轻松地与其他人协作。

您可以在此处查看所有可用的深度强化学习模型(如果它们使用 Q 学习)👉 https://huggingface.co/models?other=q-learning

pip install -r https://raw.githubusercontent.com/huggingface/deep-rl-class/main/notebooks/unit2/requirements-unit2.txt
sudo apt-get update
sudo apt-get install -y python3-opengl
apt install ffmpeg xvfb
pip3 install pyvirtualdisplay

为了确保使用新安装的库,有时需要重新启动笔记本电脑运行时。下一个单元格将强制运行时崩溃,因此您需要重新连接并从这里开始运行代码。借助此技巧,我们将能够运行虚拟屏幕。

import os

os.kill(os.getpid(), 9)
# Virtual display
from pyvirtualdisplay import Display

virtual_display = Display(visible=0, size=(1400, 900))
virtual_display.start()

导入包📦

除了安装的库之外,我们还使用

  • random:生成随机数(这将对 ε-贪婪策略有用)。
  • imageio:生成回放视频。
import numpy as np
import gymnasium as gym
import random
import imageio
import os
import tqdm

import pickle5 as pickle
from tqdm.notebook import tqdm

我们现在准备编写我们的 Q 学习算法 🔥

第 1 部分:冰湖⛄(非滑冰版本)

创建和理解冰湖环境⛄ (( https://gymnasium.org.cn/environments/toy_text/frozen_lake/ )


💡 开始使用环境时,养成查看其文档的良好习惯

👉 https://gymnasium.org.cn/environments/toy_text/frozen_lake/


我们将训练我们的 Q 学习代理仅通过在冰冻瓷砖(F)上行走来从起始状态(S)导航到目标状态(G),并避开洞(H)

我们可以有两种环境尺寸

  • map_name="4x4":一个 4x4 网格版本
  • map_name="8x8":一个 8x8 网格版本

环境有两种模式

  • is_slippery=False:由于冰湖的非滑性(确定性),代理始终按预期方向移动
  • is_slippery=True:由于冰湖的滑性(随机性),代理可能不会始终按预期方向移动

现在让我们先用 4x4 地图和非滑性来简化。我们添加了一个名为render_mode的参数,该参数指定环境的显示方式。在我们的例子中,因为我们希望在最后记录环境的视频,所以我们需要将 render_mode 设置为 rgb_array

文档中所述,“rgb_array”:返回一个表示环境当前状态的单个帧。帧是一个形状为 (x, y, 3) 的 np.ndarray,表示 x x y 像素图像的 RGB 值。

# Create the FrozenLake-v1 environment using 4x4 map and non-slippery version and render_mode="rgb_array"
env = gym.make()  # TODO use the correct parameters

解决方案

env = gym.make("FrozenLake-v1", map_name="4x4", is_slippery=False, render_mode="rgb_array")

您可以像这样创建自己的自定义网格

desc=["SFFF", "FHFH", "FFFH", "HFFG"]
gym.make('FrozenLake-v1', desc=desc, is_slippery=True)

但我们现在将使用默认环境。

让我们看看环境是什么样子的:

# We create our environment with gym.make("<name_of_the_environment>")- `is_slippery=False`: The agent always moves in the intended direction due to the non-slippery nature of the frozen lake (deterministic).
print("_____OBSERVATION SPACE_____ \n")
print("Observation Space", env.observation_space)
print("Sample observation", env.observation_space.sample())  # Get a random observation

我们看到 Observation Space Shape Discrete(16),观察结果是一个整数,表示**代理的当前位置,计算方式为 current_row * ncols + current_col(其中行和列都从 0 开始)**。

例如,在 4x4 地图中,目标位置的计算方式如下:3 * 4 + 3 = 15。可能的观察结果数量取决于地图的大小。**例如,4x4 地图有 16 种可能的观察结果。**

例如,这就是 state = 0 的样子

FrozenLake
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

动作空间(代理可以采取的可能动作集)是离散的,有 4 种可用的动作 🎮

  • 0:向左移动
  • 1:向下移动
  • 2:向右移动
  • 3:向上移动

奖励函数 💰

  • 到达目标:+1
  • 到达洞穴:0
  • 到达冰面:0

创建并初始化 Q 表 🗄️

(👀 伪代码的步骤 1)

Q-Learning

现在该初始化我们的 Q 表了!要了解需要使用多少行(状态)和列(动作),我们需要知道动作空间和观察空间。我们之前已经知道它们的值,但我们希望通过编程方式获取它们,以便我们的算法可以泛化到不同的环境中。Gym 提供了一种方法来实现这一点:env.action_space.nenv.observation_space.n

state_space =
print("There are ", state_space, " possible states")

action_space =
print("There are ", action_space, " possible actions")
# Let's create our Qtable of size (state_space, action_space) and initialized each values at 0 using np.zeros. np.zeros needs a tuple (a,b)
def initialize_q_table(state_space, action_space):
  Qtable =
  return Qtable
Qtable_frozenlake = initialize_q_table(state_space, action_space)

解决方案

state_space = env.observation_space.n
print("There are ", state_space, " possible states")

action_space = env.action_space.n
print("There are ", action_space, " possible actions")
# Let's create our Qtable of size (state_space, action_space) and initialized each values at 0 using np.zeros
def initialize_q_table(state_space, action_space):
    Qtable = np.zeros((state_space, action_space))
    return Qtable
Qtable_frozenlake = initialize_q_table(state_space, action_space)

定义贪婪策略 🤖

记住,我们有两个策略,因为 Q 学习是一种**非策略**算法。这意味着我们**使用不同的策略来行动和更新价值函数**。

  • ε-贪婪策略(行动策略)
  • 贪婪策略(更新策略)

贪婪策略也将是我们 Q 学习代理完成训练后将使用的最终策略。贪婪策略用于使用 Q 表来选择一个动作。

Q-Learning
def greedy_policy(Qtable, state):
  # Exploitation: take the action with the highest state, action value
  action =

  return action

解决方案

def greedy_policy(Qtable, state):
    # Exploitation: take the action with the highest state, action value
    action = np.argmax(Qtable[state][:])

    return action

定义ε-贪婪策略 🤖

ε-贪婪是训练策略,用于处理探索/利用权衡。

ε-贪婪的想法

  • 概率 1 - ɛ:我们进行利用(即我们的代理选择具有最高状态-动作对值的动作)。

  • 概率 ɛ:我们进行探索(尝试一个随机动作)。

随着训练的进行,我们逐渐**降低ε值,因为我们将需要越来越少的探索和越来越多的利用**。

Q-Learning
def epsilon_greedy_policy(Qtable, state, epsilon):
  # Randomly generate a number between 0 and 1
  random_num =
  # if random_num > greater than epsilon --> exploitation
  if random_num > epsilon:
    # Take the action with the highest value given a state
    # np.argmax can be useful here
    action =
  # else --> exploration
  else:
    action = # Take a random action

  return action

解决方案

def epsilon_greedy_policy(Qtable, state, epsilon):
    # Randomly generate a number between 0 and 1
    random_num = random.uniform(0, 1)
    # if random_num > greater than epsilon --> exploitation
    if random_num > epsilon:
        # Take the action with the highest value given a state
        # np.argmax can be useful here
        action = greedy_policy(Qtable, state)
    # else --> exploration
    else:
        action = env.action_space.sample()

    return action

定义超参数 ⚙️

与探索相关的超参数是最重要的超参数之一。

  • 我们需要确保我们的代理**充分探索状态空间**以学习一个好的值近似值。为此,我们需要逐步衰减ε。
  • 如果你太快地降低ε(衰减速率太高),**你的代理可能会卡住**,因为你的代理没有充分探索状态空间,因此无法解决问题。
# Training parameters
n_training_episodes = 10000  # Total training episodes
learning_rate = 0.7  # Learning rate

# Evaluation parameters
n_eval_episodes = 100  # Total number of test episodes

# Environment parameters
env_id = "FrozenLake-v1"  # Name of the environment
max_steps = 99  # Max steps per episode
gamma = 0.95  # Discounting rate
eval_seed = []  # The evaluation seed of the environment

# Exploration parameters
max_epsilon = 1.0  # Exploration probability at start
min_epsilon = 0.05  # Minimum exploration probability
decay_rate = 0.0005  # Exponential decay rate for exploration prob

创建训练循环方法

Q-Learning

训练循环是这样的

For episode in the total of training episodes:

Reduce epsilon (since we need less and less exploration)
Reset the environment

  For step in max timesteps:
    Choose the action At using epsilon greedy policy
    Take the action (a) and observe the outcome state(s') and reward (r)
    Update the Q-value Q(s,a) using Bellman equation Q(s,a) + lr [R(s,a) + gamma * max Q(s',a') - Q(s,a)]
    If done, finish the episode
    Our next state is the new state
def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable):
  for episode in tqdm(range(n_training_episodes)):
    # Reduce epsilon (because we need less and less exploration)
    epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)
    # Reset the environment
    state, info = env.reset()
    step = 0
    terminated = False
    truncated = False

    # repeat
    for step in range(max_steps):
      # Choose the action At using epsilon greedy policy
      action =

      # Take action At and observe Rt+1 and St+1
      # Take the action (a) and observe the outcome state(s') and reward (r)
      new_state, reward, terminated, truncated, info =

      # Update Q(s,a):= Q(s,a) + lr [R(s,a) + gamma * max Q(s',a') - Q(s,a)]
      Qtable[state][action] =

      # If terminated or truncated finish the episode
      if terminated or truncated:
        break

      # Our next state is the new state
      state = new_state
  return Qtable

解决方案

def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable):
    for episode in tqdm(range(n_training_episodes)):
        # Reduce epsilon (because we need less and less exploration)
        epsilon = min_epsilon + (max_epsilon - min_epsilon) * np.exp(-decay_rate * episode)
        # Reset the environment
        state, info = env.reset()
        step = 0
        terminated = False
        truncated = False

        # repeat
        for step in range(max_steps):
            # Choose the action At using epsilon greedy policy
            action = epsilon_greedy_policy(Qtable, state, epsilon)

            # Take action At and observe Rt+1 and St+1
            # Take the action (a) and observe the outcome state(s') and reward (r)
            new_state, reward, terminated, truncated, info = env.step(action)

            # Update Q(s,a):= Q(s,a) + lr [R(s,a) + gamma * max Q(s',a') - Q(s,a)]
            Qtable[state][action] = Qtable[state][action] + learning_rate * (
                reward + gamma * np.max(Qtable[new_state]) - Qtable[state][action]
            )

            # If terminated or truncated finish the episode
            if terminated or truncated:
                break

            # Our next state is the new state
            state = new_state
    return Qtable

训练 Q 学习代理 🏃

Qtable_frozenlake = train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable_frozenlake)

让我们看看我们的 Q 学习表现在是什么样子的 👀

Qtable_frozenlake

评估方法 📝

  • 我们定义了要用于测试 Q 学习代理的评估方法。
def evaluate_agent(env, max_steps, n_eval_episodes, Q, seed):
    """
    Evaluate the agent for ``n_eval_episodes`` episodes and returns average reward and std of reward.
    :param env: The evaluation environment
    :param n_eval_episodes: Number of episode to evaluate the agent
    :param Q: The Q-table
    :param seed: The evaluation seed array (for taxi-v3)
    """
    episode_rewards = []
    for episode in tqdm(range(n_eval_episodes)):
        if seed:
            state, info = env.reset(seed=seed[episode])
        else:
            state, info = env.reset()
        step = 0
        truncated = False
        terminated = False
        total_rewards_ep = 0

        for step in range(max_steps):
            # Take the action (index) that have the maximum expected future reward given that state
            action = greedy_policy(Q, state)
            new_state, reward, terminated, truncated, info = env.step(action)
            total_rewards_ep += reward

            if terminated or truncated:
                break
            state = new_state
        episode_rewards.append(total_rewards_ep)
    mean_reward = np.mean(episode_rewards)
    std_reward = np.std(episode_rewards)

    return mean_reward, std_reward

评估我们的 Q 学习代理 📈

  • 通常,你的平均奖励应该是 1.0
  • **环境比较容易**,因为状态空间很小(16)。你可以尝试做的是用滑滑的版本替换它,它引入了随机性,使环境更复杂。
# Evaluate our Agent
mean_reward, std_reward = evaluate_agent(env, max_steps, n_eval_episodes, Qtable_frozenlake, eval_seed)
print(f"Mean_reward={mean_reward:.2f} +/- {std_reward:.2f}")

现在我们已经看到了训练后的良好结果,**只需一行代码,我们就可以将训练好的模型发布到 Hub 🤗 上**。

这是一个模型卡的示例

Model card

在幕后,Hub 使用基于 git 的存储库(不用担心,即使你不知道什么是 git 也没关系),这意味着你可以在你对代理进行实验和改进时,使用新版本更新模型。

请勿修改此代码

from huggingface_hub import HfApi, snapshot_download
from huggingface_hub.repocard import metadata_eval_result, metadata_save

from pathlib import Path
import datetime
import json
def record_video(env, Qtable, out_directory, fps=1):
    """
    Generate a replay video of the agent
    :param env
    :param Qtable: Qtable of our agent
    :param out_directory
    :param fps: how many frame per seconds (with taxi-v3 and frozenlake-v1 we use 1)
    """
    images = []
    terminated = False
    truncated = False
    state, info = env.reset(seed=random.randint(0, 500))
    img = env.render()
    images.append(img)
    while not terminated or truncated:
        # Take the action (index) that have the maximum expected future reward given that state
        action = np.argmax(Qtable[state][:])
        state, reward, terminated, truncated, info = env.step(
            action
        )  # We directly put next_state = state for recording logic
        img = env.render()
        images.append(img)
    imageio.mimsave(out_directory, [np.array(img) for i, img in enumerate(images)], fps=fps)
def push_to_hub(repo_id, model, env, video_fps=1, local_repo_path="hub"):
    """
    Evaluate, Generate a video and Upload a model to Hugging Face Hub.
    This method does the complete pipeline:
    - It evaluates the model
    - It generates the model card
    - It generates a replay video of the agent
    - It pushes everything to the Hub

    :param repo_id: repo_id: id of the model repository from the Hugging Face Hub
    :param env
    :param video_fps: how many frame per seconds to record our video replay
    (with taxi-v3 and frozenlake-v1 we use 1)
    :param local_repo_path: where the local repository is
    """
    _, repo_name = repo_id.split("/")

    eval_env = env
    api = HfApi()

    # Step 1: Create the repo
    repo_url = api.create_repo(
        repo_id=repo_id,
        exist_ok=True,
    )

    # Step 2: Download files
    repo_local_path = Path(snapshot_download(repo_id=repo_id))

    # Step 3: Save the model
    if env.spec.kwargs.get("map_name"):
        model["map_name"] = env.spec.kwargs.get("map_name")
        if env.spec.kwargs.get("is_slippery", "") == False:
            model["slippery"] = False

    # Pickle the model
    with open((repo_local_path) / "q-learning.pkl", "wb") as f:
        pickle.dump(model, f)

    # Step 4: Evaluate the model and build JSON with evaluation metrics
    mean_reward, std_reward = evaluate_agent(
        eval_env, model["max_steps"], model["n_eval_episodes"], model["qtable"], model["eval_seed"]
    )

    evaluate_data = {
        "env_id": model["env_id"],
        "mean_reward": mean_reward,
        "n_eval_episodes": model["n_eval_episodes"],
        "eval_datetime": datetime.datetime.now().isoformat(),
    }

    # Write a JSON file called "results.json" that will contain the
    # evaluation results
    with open(repo_local_path / "results.json", "w") as outfile:
        json.dump(evaluate_data, outfile)

    # Step 5: Create the model card
    env_name = model["env_id"]
    if env.spec.kwargs.get("map_name"):
        env_name += "-" + env.spec.kwargs.get("map_name")

    if env.spec.kwargs.get("is_slippery", "") == False:
        env_name += "-" + "no_slippery"

    metadata = {}
    metadata["tags"] = [env_name, "q-learning", "reinforcement-learning", "custom-implementation"]

    # Add metrics
    eval = metadata_eval_result(
        model_pretty_name=repo_name,
        task_pretty_name="reinforcement-learning",
        task_id="reinforcement-learning",
        metrics_pretty_name="mean_reward",
        metrics_id="mean_reward",
        metrics_value=f"{mean_reward:.2f} +/- {std_reward:.2f}",
        dataset_pretty_name=env_name,
        dataset_id=env_name,
    )

    # Merges both dictionaries
    metadata = {**metadata, **eval}

    model_card = f"""
  # **Q-Learning** Agent playing1 **{env_id}**
  This is a trained model of a **Q-Learning** agent playing **{env_id}** .

  ## Usage

  model = load_from_hub(repo_id="{repo_id}", filename="q-learning.pkl")

  # Don't forget to check if you need to add additional attributes (is_slippery=False etc)
  env = gym.make(model["env_id"])
  """

    evaluate_agent(env, model["max_steps"], model["n_eval_episodes"], model["qtable"], model["eval_seed"])

    readme_path = repo_local_path / "README.md"
    readme = ""
    print(readme_path.exists())
    if readme_path.exists():
        with readme_path.open("r", encoding="utf8") as f:
            readme = f.read()
    else:
        readme = model_card

    with readme_path.open("w", encoding="utf-8") as f:
        f.write(readme)

    # Save our metrics to Readme metadata
    metadata_save(readme_path, metadata)

    # Step 6: Record a video
    video_path = repo_local_path / "replay.mp4"
    record_video(env, model["qtable"], video_path, video_fps)

    # Step 7. Push everything to the Hub
    api.upload_folder(
        repo_id=repo_id,
        folder_path=repo_local_path,
        path_in_repo=".",
    )

    print("Your model is pushed to the Hub. You can view your model here: ", repo_url)

.

通过使用 push_to_hub,**您可以评估、记录回放、生成代理的模型卡并将其推送到 Hub 上**。

这样

为了能够与社区分享您的模型,您还需要遵循以下三个步骤

1️⃣ (如果还没有)在 HF 上创建一个帐户 ➡ https://huggingface.co/join

2️⃣ 登录,然后您需要从 Hugging Face 网站存储您的身份验证令牌。

Create HF Token
from huggingface_hub import notebook_login

notebook_login()

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

3️⃣ 现在,我们就可以使用 push_to_hub() 函数将训练好的代理推送到 🤗 Hub 🔥 上了。

  • 让我们创建**包含超参数和 Q_table 的模型字典**。
model = {
    "env_id": env_id,
    "max_steps": max_steps,
    "n_training_episodes": n_training_episodes,
    "n_eval_episodes": n_eval_episodes,
    "eval_seed": eval_seed,
    "learning_rate": learning_rate,
    "gamma": gamma,
    "max_epsilon": max_epsilon,
    "min_epsilon": min_epsilon,
    "decay_rate": decay_rate,
    "qtable": Qtable_frozenlake,
}

让我们填充 push_to_hub 函数

  • repo_id:要创建/更新的 Hugging Face Hub 存储库的名称 (repo_id = {username}/{repo_name}) 💡 一个好的 repo_id{username}/q-{env_id}
  • model:包含超参数和 Qtable 的模型字典。
  • env:环境。
  • commit_message:提交信息
model
username = ""  # FILL THIS
repo_name = "q-FrozenLake-v1-4x4-noSlippery"
push_to_hub(repo_id=f"{username}/{repo_name}", model=model, env=env)

恭喜 🥳 您已经从头开始实现、训练并上传了您的第一个强化学习代理。FrozenLake-v1 no_slippery 是一个非常简单的环境,让我们尝试一个更难的环境 🔥。

第二部分:Taxi-v3 🚖

创建并理解 Taxi-v3 🚕


💡 开始使用环境时,养成查看其文档的良好习惯

👉 https://gymnasium.org.cn/environments/toy_text/taxi/


Taxi-v3 🚕 中,网格世界中有四个指定的区域,分别用 R(ed) 、G(reen) 、Y(ellow) 和 B(lue) 表示。

当游戏开始时,**出租车从一个随机的方格出发**,乘客位于一个随机的位置。出租车开到乘客的位置,**接上乘客**,开到乘客的目的地(另外四个指定位置中的一个),然后**放下乘客**。乘客被放下后,游戏结束。

Taxi
env = gym.make("Taxi-v3", render_mode="rgb_array")

由于有 25 个出租车位置、5 个可能的乘客位置(包括乘客在出租车里的情况)和 4 个目的地位置,**因此有 500 个离散状态**。

state_space = env.observation_space.n
print("There are ", state_space, " possible states")
action_space = env.action_space.n
print("There are ", action_space, " possible actions")

动作空间(代理可以采取的可能动作的集合)是离散的,有 **6 个可用的动作🎮**

  • 0: 向南移动
  • 1: 向北移动
  • 2: 向东移动
  • 3: 向西移动
  • 4: 接乘客
  • 5: 下乘客

奖励函数 💰

  • -1 每步,除非触发其他奖励。
  • +20 送达乘客。
  • -10 非法执行“接客”和“下客”操作。
# Create our Q table with state_size rows and action_size columns (500x6)
Qtable_taxi = initialize_q_table(state_space, action_space)
print(Qtable_taxi)
print("Q-table shape: ", Qtable_taxi.shape)

定义超参数 ⚙️

⚠ 请勿修改 EVAL_SEED:eval_seed 数组**允许我们使用相同的出租车起始位置评估每个同学的代理**

# Training parameters
n_training_episodes = 25000  # Total training episodes
learning_rate = 0.7  # Learning rate

# Evaluation parameters
n_eval_episodes = 100  # Total number of test episodes

# DO NOT MODIFY EVAL_SEED
eval_seed = [
    16,
    54,
    165,
    177,
    191,
    191,
    120,
    80,
    149,
    178,
    48,
    38,
    6,
    125,
    174,
    73,
    50,
    172,
    100,
    148,
    146,
    6,
    25,
    40,
    68,
    148,
    49,
    167,
    9,
    97,
    164,
    176,
    61,
    7,
    54,
    55,
    161,
    131,
    184,
    51,
    170,
    12,
    120,
    113,
    95,
    126,
    51,
    98,
    36,
    135,
    54,
    82,
    45,
    95,
    89,
    59,
    95,
    124,
    9,
    113,
    58,
    85,
    51,
    134,
    121,
    169,
    105,
    21,
    30,
    11,
    50,
    65,
    12,
    43,
    82,
    145,
    152,
    97,
    106,
    55,
    31,
    85,
    38,
    112,
    102,
    168,
    123,
    97,
    21,
    83,
    158,
    26,
    80,
    63,
    5,
    81,
    32,
    11,
    28,
    148,
]  # Evaluation seed, this ensures that all classmates agents are trained on the same taxi starting position
# Each seed has a specific starting state

# Environment parameters
env_id = "Taxi-v3"  # Name of the environment
max_steps = 99  # Max steps per episode
gamma = 0.95  # Discounting rate

# Exploration parameters
max_epsilon = 1.0  # Exploration probability at start
min_epsilon = 0.05  # Minimum exploration probability
decay_rate = 0.005  # Exponential decay rate for exploration prob

训练我们的 Q-Learning 代理 🏃

Qtable_taxi = train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable_taxi)
Qtable_taxi

创建模型字典 💾 并将训练好的模型发布到 Hub 🔥

  • 我们创建一个模型字典,它将包含所有用于可重复性的训练超参数和 Q-Table。
model = {
    "env_id": env_id,
    "max_steps": max_steps,
    "n_training_episodes": n_training_episodes,
    "n_eval_episodes": n_eval_episodes,
    "eval_seed": eval_seed,
    "learning_rate": learning_rate,
    "gamma": gamma,
    "max_epsilon": max_epsilon,
    "min_epsilon": min_epsilon,
    "decay_rate": decay_rate,
    "qtable": Qtable_taxi,
}
username = ""  # FILL THIS
repo_name = ""  # FILL THIS
push_to_hub(repo_id=f"{username}/{repo_name}", model=model, env=env)

现在它已经上传到 Hub 上了,您可以使用排行榜 🏆 👉 https://huggingface.co/spaces/huggingface-projects/Deep-Reinforcement-Learning-Leaderboard 与您的同学比较 Taxi-v3 的结果。

Taxi Leaderboard

第三部分:从 Hub 加载 🔽

Hugging Face Hub 🤗 的神奇之处在于,您可以轻松地从社区加载功能强大的模型。

从 Hub 加载保存的模型非常容易

  1. 您可以访问 https://huggingface.co/models?other=q-learning 查看所有保存的 q-learning 模型列表。
  2. 选择一个,复制其 repo_id
Copy id
  1. 然后我们只需要使用 load_from_hub,并传入:
  • repo_id
  • 文件名:repo 中保存的模型。

请勿修改此代码

from urllib.error import HTTPError

from huggingface_hub import hf_hub_download


def load_from_hub(repo_id: str, filename: str) -> str:
    """
    Download a model from Hugging Face Hub.
    :param repo_id: id of the model repository from the Hugging Face Hub
    :param filename: name of the model zip file from the repository
    """
    # Get the model from the Hub, download and cache the model on your local disk
    pickle_model = hf_hub_download(repo_id=repo_id, filename=filename)

    with open(pickle_model, "rb") as f:
        downloaded_model_file = pickle.load(f)

    return downloaded_model_file

.

model = load_from_hub(repo_id="ThomasSimonini/q-Taxi-v3", filename="q-learning.pkl")  # Try to use another model

print(model)
env = gym.make(model["env_id"])

evaluate_agent(env, model["max_steps"], model["n_eval_episodes"], model["qtable"], model["eval_seed"])
model = load_from_hub(
    repo_id="ThomasSimonini/q-FrozenLake-v1-no-slippery", filename="q-learning.pkl"
)  # Try to use another model

env = gym.make(model["env_id"], is_slippery=False)

evaluate_agent(env, model["max_steps"], model["n_eval_episodes"], model["qtable"], model["eval_seed"])

一些额外的挑战 🏆

学习的最佳方式**是自己尝试!**正如您所见,当前的代理表现不佳。作为第一个建议,您可以训练更多步。在 1,000,000 步训练后,我们看到了很棒的结果!

排行榜 上,您将找到您的代理。你能登上榜首吗?

以下是一些攀登排行榜的想法

  • 训练更多步
  • 通过查看您的同学做了什么来尝试不同的超参数。
  • 在 Hub 🔥 上**推送您新训练的模型**。

在冰面上行走和驾驶出租车对你来说太无聊了吗?尝试**改变环境**,为什么不使用 FrozenLake-v1 的滑滑版本?查看它们是如何工作的 使用 gymnasium 文档,享受乐趣🎉。


恭喜 🥳,您已经实现、训练并上传了您的第一个强化学习代理。

理解 Q-Learning 是**理解基于价值的方法的重要一步**。

在下一单元的深度 Q 学习中,我们将看到,虽然创建和更新 Q 表是一个好的策略,**但它不可扩展。**

例如,想象你创建一个学习玩 Doom 的智能体。

Doom

Doom 是一个大型环境,具有巨大的状态空间(数百万种不同的状态)。为该环境创建和更新 Q 表将是低效的。

这就是为什么我们将在下一单元学习深度 Q 学习,一种**使用神经网络根据给定状态来近似每个动作的不同 Q 值的算法。**

Environments

第三单元见!🔥

继续学习,保持优秀 🤗

< > 更新 在 GitHub 上