python笔记 gym Wrapper

Posted UQI-LIUWJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python笔记 gym Wrapper相关的知识,希望对你有一定的参考价值。

1 介绍

Wrapper是一种无需直接更改底层代码即可修改现有环境的便捷方式。 

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

举例:

import gym
from gym.wrappers import RescaleAction
base_env = gym.make("BipedalWalker-v3")

base_env.action_space
#Box([-1. -1. -1. -1.], [1. 1. 1. 1.], (4,), float32)
#没包装之前的动作空间

wrapped_env = RescaleAction(base_env, min_action=0, max_action=1)
wrapped_env.action_space
#Box([0. 0. 0. 0.], [1. 1. 1. 1.], (4,), float32)
#经过Wrapper,也就是被包装之后的动作空间,可以发现我们用一行就修改了环境的动作空间

2 一个Wrapper可以做的事 

包装器做三件常见的事情:

  • 转换动作
  • 转换观测
  • 转换reward

        通过从 ActionWrapper、ObservationWrapper 或 RewardWrapper 继承并实现相应的转换,可以轻松实现此类包装器。 如果需要一个包装器来完成更复杂的任务,你可以直接从 Wrapper 类继承。

3 ActionWrapper

        如果想在将函数传递给基础环境之前将函数应用于“动作”,则可以简单地从 ActionWrapper 继承并覆盖方法“action”以实现该转换。

        该方法中定义的转换必须采用基础环境的操作空间中的值。 但是,它的域可能与原始动作空间不同。 在这种情况下,您需要通过在包装器的 __init__ 方法中设置 self._action_space 来指定包装器的新操作空间。

        假设您有一个动作空间类型为 Box 的环境,但您只想使用有限的动作子集。 然后,您可能想要实现以下包装器

env = gym.make("LunarLanderContinuous-v2")
env.action_space
#Box([-1. -1.], [1. 1.], (2,), float32)


from gym.spaces import Discrete
class DiscreteActions(gym.ActionWrapper):
    def __init__(self, env, disc_to_cont):
        super().__init__(env)
        self.disc_to_cont = disc_to_cont
        self._action_space = Discrete(len(disc_to_cont))
    
    def action(self, act):
        return self.disc_to_cont[act]

    
wrapped_env = DiscreteActions(env, [np.array([1,0]), 
                                    np.array([-1,0]),
                                    np.array([0,1]), 
                                    np.array([0,-1])])
print(wrapped_env.action_space) 
#Discrete(4)

4 ObservationWrapper 

        如果想在将基本环境返回的“观察”传递给代码之前将某个function应用于“观察”,可以简单地从 ObservationWrapper 继承并覆盖“observation”方法来实现该转换。

        该方法中定义的转换必须在基础环境的观察空间上定义。 但是,它可能会在不同的空间中取值。 在这种情况下,您需要通过在包装器的 __init__ 方法中设置 self._observation_space 来指定包装器的新观察空间。

        例如,您可能有一个 2D 导航任务,其中环境返回字典作为带有键“agent_position”和“target_position”的观察值。 一个常见的做法可能是放弃一些自由度,只考虑目标相对于agent的位置,即observation[“target_position”] - observation[“agent_position”]。

         为此,可以像这样实现观察包装器:

class RelativePosition(gym.ObservationWrapper):
    def __init__(self, env):
        super().__init__(env)
        self._observation_space = Box(shape=(2,), low=-np.inf, high=np.inf)

    def observation(self, obs):
        return obs["target"] - obs["agent"]

 4.1 举例

未包装之前——每个observation是一个离散的数

env =gym.make("FrozenLake-v1")
env.reset()
for t in range(5):
    a_t = env.action_space.sample()
    s_t, r_t, done, info = env.step(a_t)
    print(s_t)
'''
1
0
4
5
5
'''

 包装之后——每个observation是一个one-hot编码

class DiscreteToBoxWrapper(gym.ObservationWrapper):
    def __init__(self, env):
        super().__init__(env)
        assert isinstance(env.observation_space, gym.spaces.Discrete), \\
            "Should only be used to wrap Discrete envs."
        self.n = self.observation_space.n
        self.observation_space = gym.spaces.Box(0, 1, (self.n,))
    
    def observation(self, obs):
        new_obs = np.zeros(self.n)
        new_obs[obs] = 1
        return new_obs


env_1 = DiscreteToBoxWrapper(gym.make("FrozenLake-v1"))
env_1.reset()
for t in range(10):
    a_t = env_1.action_space.sample()
    s_t, r_t, done, info = env_1.step(a_t)
    print(s_t)
'''
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
'''

5 RewardWrapper

         如果想在将基本环境返回的“reward”传递给代码之前将某个function应用于“reward”,可以简单地从 RewardWrapper 继承并覆盖“reward”方法来实现该转换。

        这种转变可能会改变奖励范围; 要指定包装器的奖励范围,可以简单地在 __init__ 中定义 self._reward_range。

       比如:,我们希望将奖励限制在一个范围内以获得一些数值稳定性。 为此,我们可以实现以下包装器:

class ClipReward(gym.RewardWrapper):
    def __init__(self, env, min_reward, max_reward):
        super().__init__(env)
        self.min_reward = min_reward
        self.max_reward = max_reward
        self._reward_range = (min_reward, max_reward)
    
    def reward(self, reward):
        return np.clip(reward, self.min_reward, self.max_reward)

6 还原未包装的情况

6.1 .env

访问未经过最近一次包装器下的环境:

wrapped_env.action_space,wrapped_env.env.action_space
'''
(Box([0. 0. 0. 0.], [1. 1. 1. 1.], (4,), float32),
 Box([-1. -1. -1. -1.], [1. 1. 1. 1.], (4,), float32))
'''

6.2 .unwrapped

访问未经过所有一次包装器下的环境:

wrapped_env.action_space,wrapped_env.unwrapped.action_space
'''
(Box([0. 0. 0. 0.], [1. 1. 1. 1.], (4,), float32),
 Box([-1. -1. -1. -1.], [1. 1. 1. 1.], (4,), float32))
'''

参考内容

Gym Wrappers | alexandervandekleut.github.io

以上是关于python笔记 gym Wrapper的主要内容,如果未能解决你的问题,请参考以下文章

Gym wrapper videorecorder 在 Hopper-v2 环境中无法正常工作。给出分段错误

工具篇 | Python虚拟环境的搭建与管理virtualenv/virtualenv-wrapper

Pytorch Note50 Gym 介绍

Python笔记:Python装饰器

强化学习笔记:Gym入门--从安装到第一个完整的代码示例

国际范的DevOps饕餮之旅,尽在GOPS2016北京站