前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【开发随笔】以强化学习环境 gym 库为例:为什么日常中我应该试图标准化接口?

【开发随笔】以强化学习环境 gym 库为例:为什么日常中我应该试图标准化接口?

作者头像
Piper蛋窝
发布2020-11-19 17:44:54
7850
发布2020-11-19 17:44:54
举报
文章被收录于专栏:Piper蛋窝Piper蛋窝

前言: 这两天在看 openAIgym ,并尝试用其测试自己写的 Sarsa 。一塌糊涂,这里来记录下经验教训。官网对于 gym 的文档不多,也不详细,读了 gym 的源码,很直观,看注释也可以。强化学习与传统的“监督学习”、“非监督学习”不同,强化学习要时刻与环境/模型交互,以传输数据。这就不能简单地将数据输入,而要整理算法与数据的接口,将二者连接起来。

注:这里的接口是抽象的,用途是实现两个基类 (Class) 或函数在迭代的同时交互数据,并非 java 中所指的 interface 。额外推荐做 java / .net 开发的朋友移步 我没有三颗心脏:谈一谈依赖倒置原则 拓展兴趣。

强化学习中智能体与算法(Agent)的交互

图片来自 https://gym.openai.com/docs/

上面这张图片描述了强化学习算法的训练过程:Agent 做出决策 / 动作 actionEnvironment 根据这个 action 做出反应,变化状态,Agent 则以 observationreward 的形式接受这些信息,并做出下一个决策。如此往复。

这是一个动态的过程,每一次迭代中,Agent 与 Environment 就要进行交互。这就涉及一个问题,如何设计这个传输并整理数据的接口?

看上去好像没什么可犹豫的,做几个函数就完了:

代码语言:javascript
复制
class Agent:
    ...
    def update_value_function(self, observation, reward):
        ...
    def action(self, observation):
        ...
        return action

class Environment:
    ...
    def step(self, action):
        ...
        return observation, reward

不幸的是实事并非如此,单单 Agent 的训练与决策过程就不止一次涉及到与 Environment 的耦合:

•如贪心动作选择下,Agent 需要通过 Environment 来知晓该状态下所有可用的动作都有哪些;•初始状态是什么?•停止条件?•...

设计接口

不同的开发者有不同的习惯,也许有人会把停止条件与动作选择写进一个函数有人会把其分开写。就像同样是电源插头,功能都是传输电能,但其形状、适用电压就是不同。

欧洲

这是德法常用的插头,230V。

中国

这是我国大陆的三角插头,220V。

但是我们出国时,不必为不能充电而感到担心,因为我们有“转换插头”这个神器:

同样的功能,不同形状的设备,我们引入“转换插头”这个东西,来使交互成为可能。

在程序设计时,两个类道理相通,但开发时做出的接口不同,就需要用到“转换插头”,对某个类的的输出和输入“包装”一下

比如我在知道 gym 之前,做了个 Agent 算法接口:

代码语言:javascript
复制
def sarsa(value_function, start_state, end_state, action_available, step):
    # @value_function:
    #    a warpper class for ValueFunion
    # @start_state: return state
    #     start_state() -> tuple
    # @end_state: return if_done
    #     end_state() -> bool
    # @action_available: return actions
    #    action_available(state) -> list
    # @step: return next_state, reward
    #    step(action) -> tuple, float or int

然而,gym 对外提供的接口长成这个样子:

代码语言:javascript
复制
class Env(object):
    r"""The main OpenAI Gym class. It encapsulates an environment with
    arbitrary behind-the-scenes dynamics. An environment can be
    partially or fully observed...
    """
    def step(self, action):
        ...
        return observation, reward, done, info

    def reset(self):
        ...
        return observation

    def render(self, mode='human'):
        # for plot
        ...

    def close(self):
        # for close
        ...

    def seed(self, seed=None):
        # for seeding
        ...

关于基类完整的代码可见 https://github.com/openai/gym/blob/master/gym/core.py。

所以你看,我的 Agent 是中国三头的插头,而 gym 提供的测试环境是欧陆的二孔式插口。

三头的插不进二孔的,必须要自己造个“转换插头”了。

于是我写了一个类,相当于给 gym 套了个“转换插头”,把二孔转换为三孔:

代码语言:javascript
复制
class DiscreteState:
    def __init__(self, env, block_num=10):
        self.discrete_state = []
        self.block_num = block_num
        self.env = env
        self.action = None
        self.trace = []

        ...

    def state(self, observation):
        rts = []
        ...
        return tuple(rts)

    def _return_index(self, ind, sta):
        ...

    def start_state(self):
        self.trace = []
        observation = self.env.reset()
        self.trace.append(observation)
        return self.state(observation)

    def action_available(self, state):
        return [0, 1, 2]  # up to env

    def step(self, action):
        observation, reward, done, info = self.env.step(action)
        self.action = action
        self.trace.append(observation)
        return self.state(observation), reward

    def end_state(self):
        observation, reward, done, info = self.env.step(self.action)
        return done
自己写“转换插头”,不如一开始就贴近规范

但是你看,我写的 DiscreteState 并不通用,当 env 变化后,我还需要修改 DiscreteState 其中的代码,及其麻烦。

那么,为什么不一开始就按照 gym 的规范,做一个可以直接把 gym 拿来用的 Agent 呢?

于是我觉得修改之前的代码,并且以后也按照 gym 的接口来标准化我以后的 Agent 接口。

其实对于我这种不太娴熟的开发者,修改原来的代码其实是很不忍心的,但长痛不如短痛,开始干吧。

以后记得:接触一个新领域时,先进行检索、总结,接触并了解该领域的标准化规范,再动手写代码。大大节省时间、提升效率。

后记: 本来决定今天写完代码的。但白天没奈住寂寞,看了两个电影 Frozen 和 Titanic 。Frozen 没有期望中的惊艳,重温 Titanic 注意到不少细节。现在都十一点半了,今天就先结束工作吧!尽量不要熬夜。明天争取早起把代码修改好,然后找找哪里的问题导致不收敛(现在写的 Agent 还很幼稚,甚至没法收敛,实在是进展缓慢、一塌糊涂,希望能尽快解决)。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Piper蛋窝 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 强化学习中智能体与算法(Agent)的交互
  • 设计接口
  • 自己写“转换插头”,不如一开始就贴近规范
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档