问题

学习一样东西最好自己动手做一个,想明白OpenAI gym的运行机制,我们就从0开始搭建个环境。

解决步骤

目录结构:

(.venv) gqw@u:~/workspace/gymtrain$ tree
.
├── env
│   ├── foo_env.py
│   └── __init__.py
└── foo_train.py

1 directory, 3 files

gym将代码分为两部分:环境部分和训练部分

gym 环境

gym 对环境镜像了抽象,无论多复杂的环境,最终暴露出来的只有gym.Env抽象的5个方法:

        step
        reset
        render
        close
        seed

我们现在实现一个最简单的环境类FooEnv:

import gym

class FooEnv(gym.Env):
    """ This is a simple envirionment """

    def __init__(self) -> None:
        super(FooEnv).__init__()
        self.seed()

    def seed(self):
        print("seed")
        pass

    def step(self, action):
        print("step")
        reward = 0
        done = False
        return None, reward, done, {}

    def reset(self):
        print("reset")
        pass
    
    def render(self):
        return True

    def close(self):
        pass

它继承gym.Env并且实现其5个抽象接口方法。到这里gym的环境基础就写完了,就这么简单。

环境注册

注册也非常简单,只要在任何地方调用gym提供的register方法即可,通常我们会将注册写在环境目录下的__init__.py文件中,这样在导入环境类的时候便能自动注册了,就像下面这样:

from gym.envs.registration import register

register(
    id="Foo-v0",
    entry_point="env.foo_env:FooEnv"
)

这里的参数id便是后面训练时gym.make使用的名字,当然entry_point便是实际的类了。注意这里的id需要匹配一定的规则:^(?:[\w:-]+/)?([\w:.-]+)-v(\d+)$.), 也就是{{名字}}-v{{版本号}}格式。

训练

    env = gym.make('Foo-v0')
    env.reset()
    
    for _ in range(1000):
        # is_open = env.render()
        # if is_open == False:
        #     break

        _, _, done, _ = env.step({})
        if done == True:
            env.reset()
    env.close()

训练其实就是env暴露的那5个方法,其中最重要的就是step和reset方法了,其他像render和close是用于展示用的可以没有, seed一般在环境类的构造函数中直接调用了,所以剩下的只有step和reset了。

仓库代码

https://github.com/gqw/foo_train.git

参考信息

[1] ADITHYASOLAI. Cracking Blackjack — Part 2[EB/OL]. Medium, 2020-07-28. https://towardsdatascience.com/cracking-blackjack-part-2-75e32363e38.

[2] FENG Y. Create a customized gym environment for Star Craft 2[EB/OL]. Medium, 2019-11-25. https://towardsdatascience.com/create-a-customized-gym-environment-for-star-craft-2-8558d301131f.