如何设置 openai-gym 环境以特定状态而不是 `env.reset()` 开始?

How to set a openai-gym environment start with a specific state not the `env.reset()`?

今天尝试在openai-gym环境下实现rl-agent时,发现一个问题,好像所有的agent都是从最初始的状态开始训练的:env.reset(),即

import gym

env = gym.make("CartPole-v0")
initial_observation = env.reset()  # <-- Note
done = False

while not done:
    action = env.action_space.sample()  
    next_observation, reward, done, info = env.step(action)

env.close()  # close the environment

所以agent自然可以顺着路线行事env.reset() -(action)-> next_state -(action)-> next_state -(action)-> ... -(action)-> done,这是一个小插曲。但是代理如何从特定状态(如中间状态)开始,然后从该状态采取行动?例如,我从重播缓冲区中抽取一个经验,即 (s, a, r, ns, done),如果我想训练代理直接从状态 ns 开始,然后用 Q-Network 获得一个动作,那么向前 n-step 步。类似的东西:

import gym

env = gym.make("CartPole-v0")
initial_observation = ns  # not env.reset() 
done = False

while not done:
    action = DQN(ns) 
    next_observation, reward, done, info = env.step(action)
    # n-step later or done is true, break

env.close()  # close the environment

但即使我将变量 initial_observation 设置为 ns,我认为代理或 env 根本不会意识到这一点。我如何告诉 gym.env 我想将初始观察设置为 ns 并让代理知道特定的开始状态,直接从该特定观察(从该特定环境开始)继续训练?

AFAIK,大多数 OpenAI 健身房环境的当前实现(包括您在问题中使用的 CartPole-v0)没有实现任何机制来初始化环境给定的状态。

但是,修改 CartPoleEnv.reset() 方法以接受充当初始状态的可选参数应该不会太复杂。

我尝试通过在调用 'env.step()' 之前简单地将 'env.state' 设置为我想要的来解决这个问题。如果我使用 'gym.make()' 初始化环境,这将不起作用。但是,我将环境的源代码复制到另一个文件,从中导入它,然后就可以简单地设置 'env.state'。您只需确保没有将其设置为允许值之外的值。

import numpy as np
from continuous_mountain_car import Continuous_MountainCarEnv

env = Continuous_MountainCarEnv()
env.reset()

print(env.state) # Random value generated by reset

env.state = np.array([-0.53, 0]) # Set it to my own value

print(env.state) # It worked

next_state, reward, done, _ = env.step(np.array([0]))

print(next_state) # The next state should be close to my value not the random one

我从 https://github.com/openai/gym/blob/master/gym/envs/classic_control/continuous_mountain_car.py

复制了 continuous_mountain_car 文件

我建议您使用并根据您的需要调整以下代码,它运行良好,我在我的 AlphaZero 实现中使用了它。

此示例适用于 CartPole,但您应该能够轻松地将其适应其他环境。

from copy import deepcopy

import gym
import numpy as np
from gym.spaces import Discrete, Dict, Box


class CartPole:
def __init__(self, config=None):
    self.env = gym.make("CartPole-v0")
    self.action_space = Discrete(2)
    self.observation_space = self.env.observation_space

def reset(self):
    return self.env.reset()

def step(self, action):
    obs, rew, done, info = self.env.step(action)
    return obs, rew, done, info

def set_state(self, state):
    self.env = deepcopy(state)
    obs = np.array(list(self.env.unwrapped.state))
    return obs

def get_state(self):
    return deepcopy(self.env)

def render(self):
    self.env.render()

def close(self):
    self.env.close()

直接分配给 env.state 的原因是因为生成的 gym 环境实际上是一个 gym.wrappers.TimeLimit 对象。

为了实现您的预​​期,您还必须将 ns 值分配给展开的环境。所以,像这样的事情应该可以解决问题:

env.reset()
env.state = env.unwrapped.state = ns

我建议您扩展 CartPole 环境,以便重置方法可以满足您的需要。然后自己包装你的环境。例如

from gym.envs.classic_control import CartPoleEnv

class ExtendedCartPoleEnv(CartPoleEnv):
    def reset(self):
        self.state = your_very_special_method()

        self.steps_beyond_done = None
        return np.array(self.state, dtype=np.float32)

max_episode_steps = 200
env = ExtendedCartPoleEnv()
env = TimeLimit(env, max_episode_steps)

我刚刚调整了找到的原始方法 here

您还可以扩展原始环境来更改 self.reset 的行为以获取参数,但这不是标准。包装环境不会接受参数,然后您需要直接调用 env.unwrapped.reset 。这变得很难看,因为 env.step 会抱怨 env.reset 没有被调用。等等。有很多方法可以实现它,但话又说回来,这与常规健身房环境应该看起来的样子不同。