Gymnasium 基础#

Gymnasium 是为所有单智能体强化学习环境提供 API(应用程序编程接口)的项目,包含了常见环境的实现:cartpole、pendulum、mountain-car、mujoco、atari 等。本页面将概述如何使用 Gymnasium 的基本知识,包括其四个关键函数:make()reset()step()render()

在 Gymnasium 的核心是 Env,代表强化学习理论中的马尔可夫决策过程(MDP)(注意:这不是一个完美的重构,缺少 MDP 的几个组件)。这个类为用户提供了生成初始状态、根据动作转换/移动到新状态以及可视化环境的能力。与 Env 一起提供的还有 Wrapper,用于帮助增强/修改环境,特别是智能体的观察、奖励和所采取的动作。

初始化 Gymnasium 环境#

在 Gymnasium 中初始化环境非常简单,可以通过 make() 函数完成:

import gymnasium as gym
env = gym.make('CartPole-v1')

这个函数会返回 Env,供用户进行交互。

env
<TimeLimit<OrderEnforcing<PassiveEnvChecker<CartPoleEnv<CartPole-v1>>>>>

要查看你可以创建的所有环境,请使用 pprint_registry() 函数。

gym.pprint_registry()
===== classic_control =====
Acrobot-v1             CartPole-v0            CartPole-v1
MountainCar-v0         MountainCarContinuous-v0 Pendulum-v1
===== phys2d =====
phys2d/CartPole-v0     phys2d/CartPole-v1     phys2d/Pendulum-v0
===== box2d =====
BipedalWalker-v3       BipedalWalkerHardcore-v3 CarRacing-v3
LunarLander-v3         LunarLanderContinuous-v3
===== toy_text =====
Blackjack-v1           CliffWalking-v0        FrozenLake-v1
FrozenLake8x8-v1       Taxi-v3
===== tabular =====
tabular/Blackjack-v0   tabular/CliffWalking-v0
===== mujoco =====
Ant-v2                 Ant-v3                 Ant-v4
Ant-v5                 HalfCheetah-v2         HalfCheetah-v3
HalfCheetah-v4         HalfCheetah-v5         Hopper-v2
Hopper-v3              Hopper-v4              Hopper-v5
Humanoid-v2            Humanoid-v3            Humanoid-v4
Humanoid-v5            HumanoidStandup-v2     HumanoidStandup-v4
HumanoidStandup-v5     InvertedDoublePendulum-v2 InvertedDoublePendulum-v4
InvertedDoublePendulum-v5 InvertedPendulum-v2    InvertedPendulum-v4
InvertedPendulum-v5    Pusher-v2              Pusher-v4
Pusher-v5              Reacher-v2             Reacher-v4
Reacher-v5             Swimmer-v2             Swimmer-v3
Swimmer-v4             Swimmer-v5             Walker2d-v2
Walker2d-v3            Walker2d-v4            Walker2d-v5
===== None =====
GymV21Environment-v0   GymV26Environment-v0

此外,make() 还提供了一些额外的参数,用于指定环境的关键字、添加更多或更少的 Wrapper 等。

gym 与环境交互#

在强化学习中,下面展示的经典“智能体-环境循环”是智能体和环境如何相互交互的简化表示。智能体接收关于环境的观察,然后智能体选择一个动作,环境使用这个动作来确定奖励和下一个观察。这个过程会不断重复,直到环境结束(终止)。

对于 Gymnasium,下面实现了单次循环的“智能体-环境循环”(直到环境结束)。请参阅下一部分以获得逐行解释。请注意,运行此代码需要安装swig(通过 pip install swig (WIndows 下使用 conda install anaconda::swig)或下载)以及使用 pip install gymnasium[box2d]

import gymnasium as gym

env = gym.make("LunarLander-v3", render_mode="human")
observation, info = env.reset()

episode_over = False
while not episode_over:
    action = env.action_space.sample()  # agent policy that uses the observation and info
    observation, reward, terminated, truncated, info = env.step(action)

    episode_over = terminated or truncated

env.close()

首先,通过使用 make() 函数并添加额外的关键字“render_mode”来创建环境,该关键字指定了应如何可视化环境。有关不同渲染模式的默认含义,请参阅 render()。在这个例子中,我们使用了 "LunarLander" 环境,其中智能体控制一艘需要安全着陆的宇宙飞船。

初始化环境后,我们通过调用 reset() 来获取环境的第一次观察以及额外信息。为了使用特定的随机种子或选项来初始化环境,可以在 reset() 中使用 seedoptions 参数。

由于我们希望在未知数量的时间步长内继续进行智能体-环境循环,直到环境结束,我们定义了变量 episode_over 来知道何时停止与环境的交互,同时使用 while 循环来执行这个任务。

接下来,智能体在环境中执行动作,step() 执行选定的动作(在这个例子中是随机的,使用 env.action_space.sample())来更新环境。这个动作可以想象为移动机器人或在游戏中的控制器上按下按钮,导致环境发生变化。结果,智能体从更新后的环境中接收到新的观察结果以及采取该动作的奖励。例如,这个奖励可能是正面的,因为摧毁了一个敌人,或者因为移动到熔岩中而得到负面的奖励。一次这样的动作-观察交换被称为一个时间步长。

然而,经过一些时间步长后,环境可能会结束,这称为终止状态。例如,机器人可能已经坠毁,或者成功完成了任务,环境需要停止,因为智能体无法继续。在 Gymnasium 中,如果环境已经终止,这将作为 step() 返回的第三个变量,即 terminated。同样,我们也可能在固定数量的时间步长后希望环境结束,在这种情况下,环境发出截断信号。如果 terminatedtruncated 中的任何一个为真,则我们结束这一回合,但在大多数情况下,用户可能希望重新启动环境,这可以通过 env.reset() 完成。

动作和观测空间#

每个环境都通过 action_spaceobservation_space 属性指定有效动作和观察的格式。这有助于了解环境的预期输入和输出,因为所有有效的动作和观察都应包含在它们各自的空间中。在上面的例子中,我们通过 env.action_space.sample() 随机采样动作,而不是使用智能体策略将观察映射到动作,这是用户想要进行的。

重要的是,action_spaceobservation_spaceSpace 类的实例,提供了关键的函数:contains()sample()。Gymnasium 支持用户可能需要的一系列空间:

  • Box: 描述具有任意 n 维形状的有界空间,具有上限和下限。

  • Discrete: 描述离散空间,其中 {0,1,...,n-1} 是我们观察或动作可能取的值。

  • MultiBinary: 描述任何n维形状的二进制空间。

  • MultiDiscrete: 由一系列具有不同元素数量的 Discrete 动作空间组成。

  • Text: 描述具有最小和最大长度的字符串空间。

  • Dict: 描述简单空间字典的空间。

  • Tuple: 描述简单空间元素的元组空间。

  • Graph: 描述具有相互连接节点和边的数学图(网络)的空间。

  • Sequence: 描述简单空间元素的可变长度序列空间。

有关空间使用的示例,请参阅它们的文档以及实用函数。还有一些更小众的空间,如 GraphSequenceText

修改环境#

包装器是一种方便的方法,可以在不直接修改底层代码的情况下修改现有环境。使用包装器可以避免很多样板代码,并使环境更加模块化。包装器也可以链接起来,以组合它们的效果。通过 gymnasium.make() w.make() 生成的大多数环境默认情况下已经使用 TimeLimitOrderEnforcingPassiveEnvChecker 进行了包装。

为了包装一个环境,首先必须初始化基础环境。然后,可以将此环境与(可能是可选的)参数一起传递给包装器的构造函数:

import gymnasium as gym
from gymnasium.wrappers import FlattenObservation
env = gym.make("CarRacing-v3")
env.observation_space.shape
(96, 96, 3)
wrapped_env = FlattenObservation(env)
wrapped_env.observation_space.shape
(27648,)

Gymnasium 已经为您提供了许多常用的包装器。例如:

  • TimeLimit: 如果超过最大时间步数(或基础环境发出截断信号),则发出截断信号。

  • ClipAction: 裁剪传递给 step 的任何动作,使其位于基础环境的动作空间内。

  • RescaleAction: 对动作应用仿射变换,以线性缩放环境的新的上下界。

  • TimeAwareObservation: 向观察中添加时间步长索引的信息。在某些情况下,这有助于确保转换是马尔可夫的。

要查看 Gymnasium 中实现的所有包装器的完整列表,请参阅 wrappers

如果您有包装后的环境,并且想要获取所有包装层下面的未包装环境(以便您手动调用函数或更改环境的某些底层方面),您可以使用 unwrapped 属性。如果环境已经是基础环境,unwrapped 属性将只返回它自己。

wrapped_env
<FlattenObservation<TimeLimit<OrderEnforcing<PassiveEnvChecker<CarRacing<CarRacing-v3>>>>>>
wrapped_env.unwrapped
<gymnasium.envs.box2d.car_racing.CarRacing at 0x7f69fc126930>