基本用法¶
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()
。
与环境交互¶
在强化学习中,下图所示的经典“代理-环境循环”是对代理和环境如何相互作用的简化表示。代理接收有关环境的观察结果,然后代理选择一个动作,环境使用该动作来确定奖励和下一个观察结果。然后,该循环重复自身,直到环境结束(终止)。
对于 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()
输出应该类似于以下内容
解释代码¶
首先,使用 make()
创建一个环境,其中包含一个额外的关键字 "render_mode"
,用于指定应如何可视化环境。有关不同渲染模式的默认含义的详细信息,请参见 Env.render()
。在此示例中,我们使用 "LunarLander"
环境,其中代理控制一艘需要安全着陆的宇宙飞船。
初始化环境后,我们 Env.reset()
环境以获得环境的第一个观察结果以及其他信息。要使用特定随机种子或选项(有关可能的选项,请参阅环境文档)初始化环境,请使用 seed
或 options
参数以及 reset()
。
由于我们希望继续代理-环境循环,直到环境结束,即在未知数量的时间步内结束,因此我们将 episode_over
定义为一个变量,以便知道何时停止与环境交互,以及一个使用它的 while 循环。
接下来,代理在环境中执行一个动作,Env.step()
执行所选动作(在本例中,使用 env.action_space.sample()
随机执行),以更新环境。此动作可以想象为移动机器人或按下游戏控制器上的按钮,从而导致环境发生变化。因此,代理会从更新后的环境中接收新的观察结果以及执行该动作的奖励。这种动作-观察交换被称为**时间步**。
但是,经过一些时间步后,环境可能会结束,这被称为终止状态。例如,机器人可能已经坠毁,或者可能已经成功完成任务,环境将需要停止,因为代理无法继续。在 Gymnasium 中,如果环境已终止,则 step()
会将此作为第三个变量 terminated
返回。类似地,我们可能还想在固定数量的时间步后结束环境,在这种情况下,环境会发出一个截断信号。如果 terminated
或 truncated
中的任何一个为 True
,那么我们将结束 episode,但在大多数情况下,用户可能希望重新启动环境,这可以通过 env.reset()
完成。
动作空间和观察空间¶
每个环境使用 action_space
和 observation_space
属性指定有效动作和观察结果的格式。这有助于了解环境的预期输入和输出,因为所有有效动作和观察结果都应包含在其各自的空间内。在上面的示例中,我们通过 env.action_space.sample()
采样了随机动作,而不是使用代理策略,将观察结果映射到用户想要执行的动作。
重要的是,Env.action_space
和 Env.observation_space
是 Space
的实例,这是一个高级 Python 类,提供了关键函数:Space.contains()
和 Space.sample()
。Gymnasium 支持用户可能需要的各种空间
Box
:描述了具有任何 n 维形状的上限和下限的边界空间。Discrete
:描述一个离散空间,其中{0, 1, ..., n-1}
是我们的观察结果或动作可以采用的可能值。MultiBinary
:描述任何 n 维形状的二进制空间。MultiDiscrete
: 由一系列Discrete
动作空间组成,每个元素的动作数量不同。Text
: 描述一个字符串空间,具有最小长度和最大长度。Dict
: 描述一个更简单空间的字典。Tuple
: 描述一组简单空间。Graph
: 描述一个数学图 (网络),包含相互连接的节点和边。Sequence
: 描述可变长度的更简单空间元素。
有关空间的示例用法,请参阅它们的 文档 以及 实用程序函数。还有几个更加小众的空间 Graph
、Sequence
和 Text
。
修改环境¶
包装器是一种方便的方式来修改现有环境,而无需直接修改底层代码。使用包装器将使您能够避免大量样板代码,并使您的环境更加模块化。包装器也可以链接起来,以组合它们的效果。通过 gymnasium.make()
生成的绝大多数环境默认情况下将使用 TimeLimit
、OrderEnforcing
和 PassiveEnvChecker
进行包装。
为了包装环境,您必须首先初始化一个基本环境。然后,您可以将此环境以及 (可能可选的) 参数传递给包装器的构造函数
>>> 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>