世界冠军带你从零实践强化学习心得(一)

世界冠军带你从零实践强化学习心得(二),点击这里

写在前面

不要重复造轮子,学会使用轮子。

本文源于百度AI平台飞桨学院《世界冠军带你从零实践强化学习》课程的总结,感谢科科老师这几天精彩的讲解。本文旨在提供给读者PARL框架的使用方法,并从模型的理解和代码的构建角度来整理五次课所学内容,不求详尽但求简洁明了。我认为强化学习中对算法每一个概念的理解很重要,你可以不懂公式的推导,但是只要你理解了算法框图中的每一个步骤,那你就能够灵活的应用PARL框架去解决自己的问题。

开始之前我假设大家都已经对强化学习有了最基本的认识,同时具有python编程基础,一定程度上掌握paddlepaddlenumpy库的用法。如果完全是小白,理论部分可以看看大神的笔记,推荐Mr.郑先生_Tiny Tonyhhhsy叶强大佬们的总结。

强化学习——从尝试到创造

每个人都是过去经验的总和,你过去的经验造成了现在的你。

初识强化学习

强化学习(Reinforcement learning,简称RL)是机器学习中的一个领域,强调如何基于环境而行动,以取得最大化的预期利益。核心思想是:智能体(agent)在环境(environment)中学习,根据环境的状态(state)或观测(observation),执行动作(action),并根据环境的反馈 (reward)来指导更好的动作。

强化学习核心思想

作为机器学习三巨头之一,强化学习和监督学习以及非监督学习关系如下图。
机器学习三巨头

监督学习关注的是认知,而强化学习关注的是决策。简单的说,前者学习经验,后者运用经验。同样都是一张小熊的图片,监督学习输出的是灰熊、熊猫还是老虎,强化学习输出的是装死、逃跑还是干一架。

熊来了怎么办?强化学习告诉你

强化学习的分类和方法

强化学习的分类

强化学习主要关注的是无模型的问题,在未知的环境中进行探索学习,在生活中有广泛的应用。

强化学习应用

其探索方案有二:

  • 基于价值的方法(Q表格)
    给每个状态都赋予一个价值的概念,来代表这个状态是好还是坏,这是一个相对的概念,让智能体往价值最高的方向行进。基于价值是确定性的。
  • 基于策略的方法(Policy)
    制定出多个策略,策略里的每个动作都有一定的概率,并让每一条策略走到底,最后查看哪个策略是最优的。基于策略是随机性的。

强化学习方法

PRAL框架和GYM环境

  • 强化学习经典环境库GYM将环境(Env)交互接口规范化为:重置环境reset()、交互step()、渲染render()。
  • 强化学习框架库PARL将强化学习框架抽象为: Model、Algorithm、Agent三层,使得强化学习算法的实现和调试更方便和灵活。(前两者有神经网络才用得上)

Agent的训练(Train)和测试(Test)过程直接上图展示如下。

gym中agent训练和测试过程

本文所需全部依赖库代码如下,paddlepaddle默认使用CPU版本,可自行选用GPU版本,这里不再赘述。

# 可以直接 pip install -r requirements.txt
pip install paddlepaddle==1.6.3
pip install parl==1.3.1
pip install gym
pip install atari-py
pip install rlschool==0.3.1

基于表格型方法求解RL

没有什么比前人走过的路(Q)更有价值(V)。

序列决策的经典表达

某一状态信息包含了所有相关的历史,只要当前状态可知,所有的历史信息都不再需要,当前状态就可以决定未来,则认为该状态具有马尔科夫性马尔可夫决策过程(MDP)是序列决策的数学模型,它是一个无记忆的随机过程,可以用一个元组<S,P>表示,其中S是有限数量的状态集,P是状态转移概率矩阵。

强化学习中我们引入奖励R和动作A来描述环境,构成MDP五元组<S,A,P,R, γ \gamma γ>,其中P函数表示环境的随机性,R函数其实是P函数的一部分,表示获得的收益, γ \gamma γ是衰减因子以适当的减少对未来收益的考虑。

熊问题树形图

同样以熊问题为例,对应的是Model-free的情况,即P函数和R函数都未知的情况。这时我们用价值V代表某一状态的好坏,用Q函数来代表某个状态下哪个动作更好,即状态动作价值。

熊问题model-free

现实世界中,奖励R往往是延迟的,所以一般会从当前时间点开始,对后续可能得到的收益累加,以此来计算当前的价值。但是有时候目光不要放得太长远,对远一些的东西当作近视看不见就好。适当地引入一个衰减因子 γ \gamma γ,再去计算未来的总收益, γ \gamma γ的值在0-1之间,时间点越久远,对当前的影响也就越小。

状态动作价值的求解

假设人走在树林里,先看到树上有熊爪后看到熊,接着就看到熊发怒了,经过很多次之后,原来要见到熊才瑟瑟发抖的,后来只要见到树上有熊爪就会有晕眩和害怕的感觉。也就是说,在不断地训练之后,下一个状态的价值可以不断地强化、影响上一个状态的价值。

这样的迭代状态价值的强化方式被称为时序差分(Temporal Difference)。单步求解Q函数,用 Q ( S t + 1 , A t + 1 ) Q(S_{t+1},A_{t+1}) Q(St+1,At+1)来近似 G t + 1 G_{t+1} Gt+1,以迭代的方式简化数学公式,最终使得 Q ( S t , A t ) Q(S_t,A_t) Q(St,At)逼近目标值 G t G_t Gt。这里的目标值Target就是前面提到的未来收益的累加。

Q表格TD单步更新

Sarsa和Qlearning

Sarsa全称是state-action-reward-state’-action’,目的是学习特定的state下,特定action的价值Q,最终建立和优化一个Q表格,以state为行,action为列,根据与环境交互得到的reward来更新Q表格,更新公式即为上面的迭代公式。Sarsa在训练中为了更好的探索环境,采用ε-greedy方式(如下图)来训练,有一定概率随机选择动作输出。

epsilon-greedy

Q-learning也是采用Q表格的方式存储Q值,探索部分与Sarsa是一样的,采用ε-greedy方式增加探索。

  • Q-learning跟Sarsa不一样的地方是更新Q表格的方式,即learn()函数。
  • Sarsa是on-policy,先做出动作再learn,Q-learning是off-policy,learn时无需获取下一步动作

二者更新Q表格的方式分别为:

sarsa和qlearning更新Q表格方式对比

二者算法对比如下图所示,有三处不同点。

sarsa和qlearning算法对比

on-policy优化的是目标策略,用下一步一定会执行的动作来优化Q表格;off-policy实际上有两种不同的策略,期望得到的目标策略和大胆探索的行为策略,在目标策略的基础上用行为策略获得更多的经验。

离线在线之争

代码构建与演示

Sarsa Agent构建

class SarsaAgent(object):
    def __init__(self,
                 obs_n,
                 act_n,
                 learning_rate=0.01,
                 gamma=0.9,
                 e_greed=0.1):
        self.act_n = act_n  # 动作维度,有几个动作可选
        self.lr = learning_rate  # 学习率
        self.gamma = gamma  # reward的衰减率
        self.epsilon = e_greed  # 按一定概率随机选动作
        self.Q = np.zeros((obs_n, act_n))

    # 根据输入观察值,采样输出的动作值,带探索
    def sample(self, obs):
        if np.random.uniform(0, 1) < (1.0 - self.epsilon):  #根据table的Q值选动作
            action = self.predict(obs)
        else:
            action = np.random.choice(self.act_n)  #有一定概率随机探索选取一个动作
        return action

    # 根据输入观察值,预测输出的动作值
    def predict(self, obs):
        Q_list = self.Q[obs, :]
        maxQ = np.max(Q_list)
        action_list = np.where(Q_list == maxQ)[0]  # maxQ可能对应多个action
        action = np.random.choice(action_list)
        return action

    # 学习方法,也就是更新Q-table的方法
    def learn(self, obs, action, reward, next_obs, next_action, done):
        """ on-policy
            obs: 交互前的obs, s_t
            action: 本次交互选择的action, a_t
            reward: 本次动作获得的奖励r
            next_obs: 本次交互后的obs, s_t+1
            next_action: 根据当前Q表格, 针对next_obs会选择的动作, a_t+1
            done: episode是否结束
        """
        predict_Q = self.Q[obs, action]
        if done:
            target_Q = reward  # 没有下一个状态了
        else:
            target_Q = reward + self.gamma * self.Q[next_obs,
                                                    next_action]  # Sarsa
        self.Q[obs, action] += self.lr * (target_Q - predict_Q)  # 修正q

Qlearning Agent构建

class QLearningAgent(object):
    def __init__(self,
                 obs_n,
                 act_n,
                 learning_rate=0.01,
                 gamma=0.9,
                 e_greed=0.1):
        self.act_n = act_n  # 动作维度,有几个动作可选
        self.lr = learning_rate  # 学习率
        self.gamma = gamma  # reward的衰减率
        self.epsilon = e_greed  # 按一定概率随机选动作
        self.Q = np.zeros((obs_n, act_n))

    # 根据输入观察值,采样输出的动作值,带探索
    def sample(self, obs):
        if np.random.uniform(0, 1) < (1.0 - self.epsilon):  #根据table的Q值选动作
            action = self.predict(obs)
        else:
            action = np.random.choice(self.act_n)  #有一定概率随机探索选取一个动作
        return action

    # 根据输入观察值,预测输出的动作值
    def predict(self, obs):
        Q_list = self.Q[obs, :]
        maxQ = np.max(Q_list)
        action_list = np.where(Q_list == maxQ)[0]  # maxQ可能对应多个action
        action = np.random.choice(action_list)
        return action

    # 学习方法,也就是更新Q-table的方法
    def learn(self, obs, action, reward, next_obs, done):
        """ off-policy
            obs: 交互前的obs, s_t
            action: 本次交互选择的action, a_t
            reward: 本次动作获得的奖励r
            next_obs: 本次交互后的obs, s_t+1
            done: episode是否结束
        """
        predict_Q = self.Q[obs, action]
        if done:
            target_Q = reward  # 没有下一个状态了
        else:
            target_Q = reward + self.gamma * np.max(
                self.Q[next_obs, :])  # Q-learning
        self.Q[obs, action] += self.lr * (target_Q - predict_Q)  # 修正q

全部代码已上传至我的GitHub,大家可以尝试用命令行运行以下演示代码,训练环境是悬崖问题(CliffWalking)。

# sarsa 演示
cd .\tutorials\lesson2\sarsa
python .\train.py
# qlearing 演示
cd .\tutorials\lesson2\q_learning
python .\train.py

最终结果如下面的GIF所示。可以看出来Sarsa比较保守,会选择下限最高的路线,即尽可能远离悬崖的路线,虽然路程远了,但至少掉下悬崖的风险就小了很多;而QLearning比较激进,会选择上限最高的路线,即路程最近的路线,但存在些微扰动便可能掉下悬崖。

Sarsa训练图:

Sarsa训练图

QLearning训练图:

QLearning训练图

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值