基本用法

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

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

初始化环境

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

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

此函数将返回一个 Env 供用户交互。要查看可以创建的所有环境,请使用 pprint_registry()。此外,make() 提供了许多其他参数,用于为环境指定关键字、添加更多或更少的包装器等等。有关更多信息,请参见 make()

与环境交互

在强化学习中,下图所示的经典“代理-环境循环”是对代理和环境如何相互作用的简化表示。代理接收有关环境的观察结果,然后代理选择一个动作,环境使用该动作来确定奖励和下一个观察结果。然后,该循环重复自身,直到环境结束(终止)。

../../_images/AE_loop.png ../../_images/AE_loop_dark.png

对于 Gymnasium,下面的“代理-环境循环”是在单个 episode 中实现的(直到环境结束)。有关逐行说明,请参见下一节。请注意,运行此代码需要安装 swig(pip install 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()

输出应该类似于以下内容

https://user-images.githubusercontent.com/15806078/153222406-af5ce6f0-4696-4a24-a683-46ad4939170c.gif

解释代码

首先,使用 make() 创建一个环境,其中包含一个额外的关键字 "render_mode",用于指定应如何可视化环境。有关不同渲染模式的默认含义的详细信息,请参见 Env.render()。在此示例中,我们使用 "LunarLander" 环境,其中代理控制一艘需要安全着陆的宇宙飞船。

初始化环境后,我们 Env.reset() 环境以获得环境的第一个观察结果以及其他信息。要使用特定随机种子或选项(有关可能的选项,请参阅环境文档)初始化环境,请使用 seedoptions 参数以及 reset()

由于我们希望继续代理-环境循环,直到环境结束,即在未知数量的时间步内结束,因此我们将 episode_over 定义为一个变量,以便知道何时停止与环境交互,以及一个使用它的 while 循环。

接下来,代理在环境中执行一个动作,Env.step() 执行所选动作(在本例中,使用 env.action_space.sample() 随机执行),以更新环境。此动作可以想象为移动机器人或按下游戏控制器上的按钮,从而导致环境发生变化。因此,代理会从更新后的环境中接收新的观察结果以及执行该动作的奖励。这种动作-观察交换被称为**时间步**。

但是,经过一些时间步后,环境可能会结束,这被称为终止状态。例如,机器人可能已经坠毁,或者可能已经成功完成任务,环境将需要停止,因为代理无法继续。在 Gymnasium 中,如果环境已终止,则 step() 会将此作为第三个变量 terminated 返回。类似地,我们可能还想在固定数量的时间步后结束环境,在这种情况下,环境会发出一个截断信号。如果 terminatedtruncated 中的任何一个为 True,那么我们将结束 episode,但在大多数情况下,用户可能希望重新启动环境,这可以通过 env.reset() 完成。

动作空间和观察空间

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

重要的是,Env.action_spaceEnv.observation_spaceSpace 的实例,这是一个高级 Python 类,提供了关键函数:Space.contains()Space.sample()。Gymnasium 支持用户可能需要的各种空间

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

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

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

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

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

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

  • Tuple: 描述一组简单空间。

  • Graph: 描述一个数学图 (网络),包含相互连接的节点和边。

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

有关空间的示例用法,请参阅它们的 文档 以及 实用程序函数。还有几个更加小众的空间 GraphSequenceText

修改环境

包装器是一种方便的方式来修改现有环境,而无需直接修改底层代码。使用包装器将使您能够避免大量样板代码,并使您的环境更加模块化。包装器也可以链接起来,以组合它们的效果。通过 gymnasium.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 中实现的包装器的完整列表,请参阅 包装器

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

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

更多信息