gym库文档学习(一)

最近老板突然让我编写一个自定义的强化学习环境,一头雾水(烦),没办法,硬着头皮啃官方文档咯~

第一节先学习常用的API:

1 初始化环境

在 Gym 中初始化环境非常简单,可以通过以下方式完成:

import gym
env = gym.make('CartPole-v0')

2 与环境交互

Gym 实现了经典的“代理环境循环”:

gym库文档学习(一)_第1张图片

代理在环境中执行一些动作(通常通过将一些控制输入传递给环境,例如电机的扭矩输入)并观察环境状态如何变化。一种这样的动作-观察交换被称为时间步长。

RL 的目标是以某种特定方式操纵环境。例如,我们希望agent将机器人导航到空间中的特定点。如果它成功地做到了这一点(或朝着该目标取得了一些进展),它将在此时间步的观察中获得积极的奖励。如果agent尚未成功(或未取得任何进展),则奖励也可能为负数或 0。然后agent将被训练以最大化它在许多时间步长上积累的奖励。

在一些时间步之后,环境可能会进入终端状态。例如,机器人可能已经坠毁!在这种情况下,我们希望将环境重置为新的初始状态。如果agent进入这样的终端状态,环境就会向agent发出完成信号。并非所有完成信号都必须由“灾难性故障”触发:有时我们还希望在固定数量的时间步之后发出完成信号,或者如果agent已成功完成环境中的某些任务。

让我们看看 Gym 中的代理环境循环是什么样的。此示例将运行 LunarLander-v2 环境实例 1000 个时间步长。

import gym
env = gym.make("LunarLander-v2")
env.reset()
for _ in range(1000):
    env.render()
    action = env.action_space.sample()
    observation, reward, done, info = env.step(action)
    print(observation)
env.close()

输出:

每个环境都通过提供 env.action_space 属性来指定有效操作的格式。同样,有效观察的空间由 env.observation_space 指定。在上面的示例中,我们通过 env.action_space.sample() 对随机动作进行采样。请注意,我们需要将动作空间与环境分开seed,以确保可重复的样本。

3 标准方法

3.1 stepping步进

gym.Env.step(self, action: gym.core.ActType) → Tuple[gym.core.ObsType, float, bool, dict]

运行环境动态的一个时间步长。

当情节结束时,我们可以调用 reset() 来重置此环境的状态。接受一个动作并返回一个元组:(observation, reward, done, info).

参数:

action:agent做出的动作

返回信息:

observation :环境观察空间的一个元素。例如,这可能是一个包含某些对象的位置和速度的 numpy 数组。上述例子中observation即为一个数组。

reward (float) :agent采取行动后返回的奖励值。

done (bool) :如果游戏已经结束,则为布尔值,在这种情况下,进一步的 step() 调用将返回未定义的结果。可能会因为不同的原因发出 done 信号:可能环境下的任务已成功解决,超出了某个时间限制,或者物理模拟已进入无效状态。

info (dictionary):可能包含有关附加信息的字典。 info 包含辅助诊断信息(有助于调试、学习和记录)。例如,这可能包含:描述agent性能状态的指标、对观察隐藏的变量、区分截断和终止的信息或组合起来产生总奖励的单个奖励​​项。

3.2 Resetting重置

gym.Env.reset(self, *, seed: Optional[int] = None, return_info: bool = False, options: Optional[dict] = None) → Union[gym.core.ObsType, Tuple[gym.core.ObsType, dict]]

将环境重置为初始状态并返回初始观察值。

如果种子是整数或环境尚未初始化随机数生成器,此方法可以重置环境的随机数生成器。如果环境已经有一个随机数生成器,并且用 seed=None 调用了 reset(),则不应重置环境的随机数生成器。此外,reset() 应该(在典型用例中)在初始化后立即使用整数种子调用,然后再也不调用。

参数:

seed (optional int):用于初始化环境 PRNG(伪随机数生成器) 的种子。如果环境还没有 PRNG 并且通过了 seed=None(默认选项),则将从一些熵源(例如时间戳或 /dev/urandom)中选择一个种子。但是,如果环境已经有 PRNG 并且通过了 seed=None,则 PRNG 将不会被重置。如果你传递一个整数,即使 PRNG 已经存在,它也会被重置。通常,您希望在环境初始化后立即传递一个整数,然后再不传递。

return_info (bool):如果为真,则返回附加信息以及初始观察。类似于 step() 中返回的信息。

options (optional dict):指定如何重置环境的附加信息(可选,取决于具体环境)

返回信息:

observation (object):观察初始状态。是 observation_space 的一个元素(通常是一个 numpy 数组),类似于 step() 返回的观察值。

info (optional dictionary):仅当 return_info=True 被传递时才会返回。它包含补充观察的辅助信息。类似于 step() 返回的信息。

3.3 Rendering渲染

gym.Env.render(self, mode='human')

用于渲染环境。

一组支持的模式因环境而异。(并且一些第三方环境可能根本不支持渲染。)按照惯例,如果模式是:

human:渲染到当前显示器或终端并且不返回任何内容。

rgb_array:返回一个形状为 (x, y, 3) 的 numpy.ndarray,表示 x-by-y 像素图像的 RGB 值,适合转换为视频。

ansi:返回包含终端样式文本表示的字符串 (str) 或 StringIO.StringIO。文本可以包含换行符和 ANSI 转义序列(例如颜色)。

注:确保您的类的元数据“render_modes”键包含支持的模式列表。建议在实现中调用 super() 以使用此方法的功能。

import numpy as np
class MyEnv(Env):
   metadata = {'render_modes': ['human', 'rgb_array']}

   def render(self, mode='human'):
       if mode == 'rgb_array':
           return np.array(...) # 返回适合视频的RGB帧
       elif mode == 'human':
           ... # 弹出一个窗口并渲染
       else:
           super().render(mode=mode) # 仅提出一个例外

参数:

mode:渲染模式,有效模式是 env.metadata[“render_modes”]。

4 附加环境 API

4.1 Attributes属性

4.1.1 动作空间

Env.action_space: gym.spaces.space.Space[gym.core.ActType]

该属性给出了有效动作的格式。它是 Gym 提供的数据类型 Space。例如,如果动作空间的类型为 Discrete 并给出值 Discrete(2),这意味着有两个有效的离散动作:0 和 1。

env.action_space
Discrete(2)
env.observation_space
Box(-3.4028234663852886e+38, 3.4028234663852886e+38, (4,), float32)

4.1.2 观测空间

Env.observation_space: gym.spaces.space.Space[gym.core.ObsType]

该属性给出了有效观察的格式。它是 Gym 提供的数据类型 Space。例如,如果观察空间是 Box 类型并且对象的形状是 (4,),这表示有效的观察将是 4 个数字的数组。我们也可以使用属性检查框边界。

env.observation_space.high
array([4.8000002e+00, 3.4028235e+38, 4.1887903e-01, 3.4028235e+38], dtype=float32)
env.observation_space.low
array([-4.8000002e+00, -3.4028235e+38, -4.1887903e-01, -3.4028235e+38], dtype=float32)

4.1.3 奖励范围

Env.reward_range = (-inf, inf)

该属性是对应于最小和最大可能奖励的元组。默认范围设置为 (-inf,+inf)。如果您想要更窄的范围,可以自定义。

4.2 Methods方法

4.2.1 关闭环境

gym.Env.close(self)

在您的子类中覆盖 close 以执行任何必要的清理。 当程序退出时,环境将自动关闭。

4.2.2 为环境的随机数生成器设置种子

env.reset(seed=seed) 

参数:

seed (Optional int) :随机数生成器的种子值

返回值:

seeds (List[int]) :返回此环境的随机数生成器中使用的种子列表。列表中的第一个值应该是“主”种子,或者是应该传递给“种子”的值。通常,主种子等于提供的“种子”,但如果seed=None,将不会生效。

5 检查 API 一致性

如果您已经实现了自定义环境并希望执行健全性检查以确保它符合 API,您可以运行:

from gym.utils.env_checker import check_env
check_env(env)

如果您的环境不遵循 Gym API,此函数将引发异常。如果看起来您犯了错误或未遵循最佳实践(例如,如果 observation_space 看起来像图像但没有正确的 dtype),它也会产生警告。可以通过传递warn=False 来关闭警告。默认情况下,check_env 不会检查渲染方法。要更改此行为,您可以传递 skip_render_check=False。

注:在环境中运行 check_env 后,您不应重复使用已检查的实例,因为它可能已经关闭!

6 spaces空间

spaces通常用于指定有效动作和观察的格式。每个环境都应该有属性 action_space 和 observation_space,它们都应该是继承自 Space 的类的实例。 Gym 中有多种可用的空间类型:

  • Box:描述了一个 n 维的连续空间。这是一个有界空间,我们可以在其中定义上限和下限,这些上限和下限描述了我们的观察可以采用的有效值。
  • Discrete: 描述了一个离散空间,其中 {0, 1, ..., n-1} 是我们的观察或行动可以采取的可能值。可以使用可选参数将值转换为 {a, a+1, ..., a+n-1}。
  • Dict: 表示简单空间的字典。
  • Tuple:表示简单空间的元组。
  • MultiBinary:创建一个 n 维大小的二元空间。参数 n 可以是数字或数字列表。
  • MultiDiscrete:由一系列离散动作空间组成,每个元素中具有不同数量的动作。
import numpy as np
from gym.spaces import Box, Discrete, Dict, Tuple, MultiBinary, MultiDiscrete

observation_space = Box(low=-1.0, high=2.0, shape=(3,), dtype=np.float32)
print(f"Box空间动作抽样:",observation_space.sample())

observation_space = Discrete(4)
print(f"Discrete空间动作抽样:",observation_space.sample())

observation_space = Dict({"position": Discrete(2), "velocity": Discrete(3)})
print(f"Dict空间动作抽样:",observation_space.sample())

observation_space = Tuple((Discrete(2), Discrete(3)))
print(f"Tuple空间动作抽样:",observation_space.sample())

observation_space = MultiBinary(5)
print(f"MultiBinary空间动作抽样:",observation_space.sample())

observation_space = MultiDiscrete([ 5, 2, 2 ])
print(f"MultiDiscrete空间动作抽样:",observation_space.sample())

 输出:

gym库文档学习(一)_第2张图片

7 Wrappers装饰器

装饰器是一种无需直接更改底层代码即可修改现有环境的便捷方式。使用装饰器将使您避免大量样板代码并使您的环境更加模块化。装饰器也可以链接起来以组合它们的效果。大多数通过 gym.make 生成的环境已经被默认包装了。

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

import gym
from gym.wrappers import RescaleAction
base_env = gym.make("BipedalWalker-v3")
print(base_env.action_space)
wrapped_env = RescaleAction(base_env, min_action=0, max_action=1)
print(wrapped_env.action_space)

输出:

装饰器完成了三个功能:

  • 在将操作应用到基础环境之前转换操作。
  • 转换由基础环境返回的观测值。
  • 转换基础环境返回的奖励。

通过从 ActionWrapper、ObservationWrapper 或 RewardWrapper 继承并实现相应的转换,可以轻松实现此类装饰器。

但是,有时您可能需要实现一个装饰器来进行一些更复杂的修改(例如,根据信息中的数据修改奖励)。这样的装饰器可以通过从 Wrapper 继承来实现。 Gym 已经为你提供了很多常用的装饰器。一些例子:

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

ClipAction:剪辑动作,使其位于动作空间(Box 类型)中。

RescaleAction:重新调整动作以位于指定的时间间隔内

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

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

print(wrapped_env)
print(wrapped_env.unwrapped)

 

8 在环境中执行游戏

我们可以使用gym.utils.play 使用键盘播放游戏环境。

假设我们希望使用左右箭头键来玩 CartPole-v0。代码如下:

import gym
import pygame
from gym.utils.play import play
mapping = {(pygame.K_LEFT,): 0, (pygame.K_RIGHT,): 1}
play(gym.make("CartPole-v0"), keys_to_action=mapping)

我们从 pygame 中获取相应的键 ID 常量。如果未指定 key_to_action 参数,则使用该环境的默认 key_to_action 映射。

下一讲学习怎么创建环境~

 

 

 

 

 

你可能感兴趣的:(强化学习笔记,学习,人工智能,pygame)