1 题外话:人类棋手的最后赞礼
2016年3月15日,AlphaGo以4:1的比分击败了人类的传奇棋手李世石。在李世石折戟沉沙的当晚,一个名叫柯洁的中国少年站出来说,“就算AlphaGo战胜了李世石,但是它赢不了我”。当时柯洁柯洁是有这个底气的,因为他在世界排行榜上占据第一,曾在正式比赛中以8:2的比分碾压李世石。但是AlphaGo经过9个多月的自我对弈和迭代,AlphaGo已经从对战李世石的V18进化到到V21了,它有了一个新的名字“AlphaGo Zero”。2017年5月,人类第一高手柯洁和“AlphaGo Zero”开启了一段旷世对决。在这段对决中,无论柯洁如何努力,始终脱离不了在“AlphaGo Zero”面前全面落败的结局,期间抑制不住情绪失声痛苦。那么,AlphaGo Zero背后的技术是什么?是如何让它进化得比人类更强的?其实就是强化学习(Reinforcement Learning, RL) 。
2 强化学习概述
前面讲到的所有深度学习都是有监督的学习,也就是数据都是有标签的。我们需要告诉机器一个输入应当要有什么样的输出。即使是自监督学习,也是有标签的,只是标签不是人工标注的,而是来自于数据本身。但是在有些任务中,对应一个输出,我们人类也不知道最佳的输出是什么。比如说下围棋,对方落子后,我方的最佳落子在哪儿,恐怕最厉害的棋手也不知道。当然,我们可以通过监督学习的方法,让机器学习许多棋谱,也能使机器称为高手,但是最高水平永远不会超过人类。如果我们希望机器学习获得人类棋谱之外的招数,在与人类对决时候可以出现神之一手,以打败人类最高选手,那么就要用到强化学习了。
2.1 强化学习的目标也是要找一个Function
强化学习和一般深度学习的目的是一样的,都是要找一个Function。强化学习要找的Function如下图所示,这个Function我们将其称为Actor。Actor的输入是它对环境的观察,输出是一个行为Action。当Actor输出一个行为后,环境的状态会发生改变,因此Actor又能观察到新的环境,相应的又输出一个新的行为。在Actor和环境互动的过程中,环境会不断地反馈Reward。我们要找到一个Actor(Function),使total reward最大化。
比如训练一个下围棋的Actor。Actor就是AlphaGo,环境就是和AlphaGo对战的人类。Actor的输入是棋盘及棋盘上的双方落子,输出就是下一步落子的位置。Actor每下一个棋子,人类也会下一个棋子,这样Actor观察到的棋盘及棋盘上的双方落子就发生了变化,Actor根据它观察到的新的状态又要输出一个新的落子位置。在这对弈过程中,大部分时间的reward都是0,只有等棋局结束后,才会反馈一个reward,如果是赢了,reward=1,如果输了,reward=0。
2.2 强化学习的三个基本步骤
强化学习和一般的深度学习一样也包含定义一个function、定义一个损失函数、优化参数这三个步骤。由于下围棋的模型过于复杂,下面以Space invader的游戏来说明这三个步骤,到本节最后再简单地讲一下AlphaGo的强化学习。
Space invader游戏的规则如下:游戏下端的绿色块是我们的太空船,动作有左移、右移和开火。上面的黄色图标是外星人,我们的目标是要杀掉这些外星人,只要开火集中外星人就可以把它杀掉。中间的橘黄色块是我们防护罩,可以阻挡外星人的进攻,不小心开火打中防护罩会使防护罩变小。我们每击中一个外星人,就可以得到一个分数,也就是reward。游戏的终点是所有外星人被杀掉,或者我们的太空船被摧毁。
2.2.1 定义一个function
我们设计一个神经网络模型,输入是游戏画面,输出是左移、右移或者开火的开率。这其实就是一个分类任务,即输入一张图片,输出三个类别的分数。因此,该网络可以使用常见的CNN,当然也可以设计成其他形式的网络架构。但是Actor的时候,可能不会直接采用概率(分数)最大的动作,而是使用采样的方式,从这个概率分布中去采样一个动作。这样做的好处是,机器看到同一个游戏画面,可能会采取不同的行为,这种随机性在RL中很常见。
2.2.2 定义一个损失函数
前面提到了,Actor在和环境互动的过程中,环境会不断反馈reward。比如在Space invader游戏中,Actor观察到的环境,此时Actor执行的动作是右移,获得的reward是0;然后环境状态变成,Actor观察到此状态后执行的动作是开火,获得的reward是5;环境状态变成。假设Actor在和环境互动的互动经过了若干轮后,太空船被摧毁,游戏结束,这时候就会获得游戏最后的得分,我们把这样一局游戏称为一个episode。在一个episode中,Actor和环境互动执行了许多Action,每一个Action我们用表示,针对每一个Action环境都会反馈一个reward,我们用。当一个episode结束后,我们得到了游戏最后的得分,称为Total reward,即。我们的目标是要最大化,因此Loss函数即可以定义为负的。
2.2.3 优化参数
在Actor和环境互动中会产生一系列的action和环境状态,我们把这些action和环境状态构成的序列称之为Trajectory,表示为。其中actor是一个网络,包含未知参数,我们的目标使要训练出一组参数,使Total reward最大。但是由于环境状态的变化和Reward是黑箱,且一般具有随机性,我们是没办法用一般网络的训练方法的。因此,强化学习最大的挑战就在于参数优化。
3 Policy Gradient
3.1 Actor的行为控制
对于一个Actor我们如何控制它的行为呢?前面提到了Actor的网络实际上就是一个分类网络,例如Space invader游戏就是读入当前环境的图片输出左移、右移、开火三个类别的概率。因此,我们可以定义一个交叉熵来评估在环境状态下网络的输出与合理的动作之间的距离。例如在某一环境下合理的动作是左移,而Actor网络的输出是(左移,0.6)、(右移,0.3)、(开火,0.1),那么交叉熵是。一把游戏结束后,我们计算出许多交叉熵,将它们累加起来,定义一个损失函数:。在训练过程中最小化这个,就可以控制Actor的行为,使其更加合理的执行任务。
更进一步,在某一特定环境下,Actor执行某个动作不只是合理和不合理,而是一个合理的程度,我们用一个分数来表示。这个叫做优势函数(Advantage Function),它反映了Actor在某个状态下下选取某个具体动作的合理性。
例如,在Space invader游戏中,如果在一个游戏界面中,给Actor的右移打了一个很高的正分数,那么就意味着Actor在当前环境下执行右移这个动作是非常合理的,我们鼓励它这么做;如果在一个游戏界面中,给Actor的左移打了一个很低的负分数,那么就意味着Actor在当前环境下尽量不要执行左移这个动作是很不合理的,我们不期望它这么做。此时,损失函数就为,即损失函数的每一项在的基础上再乘了一个。为了训练Actor,我们需要收集一堆数据,是关于不同环境下Actor执行不同动作的合理程度的,如下图所示的Training Data。这里有一个关键问题,如何去确定这些呢?如果都是人工确定的,那以上跟传统的监督学习没有任何区别了。我们有没有其他方法确定呢?
3.2 优势函数的确定
一个最简单的方式是让,这里的是前面提到的reward。在Space invader游戏中就是在某一特定游戏界面下,Actor执行某个动作的所获得的分数,如果这个动作是左移或者右移,则,如果是开火正好打中了外星人,则。但是这样做实际上是一个短视的行为,它只顾了眼前,没有考虑到当前的行为对未来的影响。如果这样设置A,可能会导致Actor一直开火,毕竟只有开火才能获得reward。有很多时候,牺牲当前的利益可能会获得更多的回报。例如在Space invader游戏中,Actor采取右移策略虽然本轮动作不会得分,但是可能有利于后续连续得分。所以,我们需要让Actor看得更远。
那么更好的办法是让 ,即把Actor在环境 下执行动作 后所获得的累积reward作为 。这样,Actor在某一游戏界面下就有可能选择右移,即使没有获得分数,但是有利于后面获得更丰厚的分数。但是,这里还有一个问题,Actor在某一游戏界面下选择右移,可能只对后面几步的分数获得有影响,对再后面的分数获得就影响不大了。举个例子,把Actor最后一次开火获得的分数 归功于Actor第一个动作 显然是不太合适的。因此,引入一个大于0小于1的折扣因子 ,让 。某个分数离动作 越远, 对该分数的贡献就越小,给该分数的权值就越小,这就更合理了。
仍然有一个问题,某个动作的好与坏是相对的,我们希望好的动作尽可能是正的分数,不好的动作尽可能是负的分数,但是在Space invader游戏中并未设置负的reward。因此,设置一个基准 ,我们让 这样 就会有正有负了。但是一个重要的问题是如何确定这个 呢?这就用到Actor-Critic算法了,后面将介绍。
3.3 参数更新算法
Policy Gradient更新参数的算法如下图所示。首先,随机初始化Actor网络的参数。然后进入参数更新的循环,在循环里面:首先,让Actor与环境进行互动,并把互动的过程记录下来,获得一堆的数据 ;然后,根据互动产生的reward计算 ,用于评Actor在特定环境状态下选取某个具体动作的合理性;然后,计算Loss ;最后,利用梯度下降更新一次参数。
以上要特别注意到,每更新一次参数都要用新的actor去和环境互动获得新的互动数据,然后再更新参数。对于一般机器学习,数据的收集往往在迭代循环的外面,也就是只需要收集一次数据就行了。但是在这里,每更新一次参数都要重新收集数据。这是因为我们没更新一次参数,Actor的能力就强了一些,此时我们需要用新的Actor去和环境互动才能获得更有价值的数据,这时候的数据对于提升新的Actor的能力才更有帮助。举个例子,刚开始Actor V0是一个Space invader游戏小白,左移、右移和开火都是随机的,差不多得5分就挂了。但是,当Actor迭代了很20代后,Actor V20打Space invader游戏差不多得100分才挂。如果这时候我们还拿刚开始的Actor V0打游戏的数据来训练Actor V20显然是不合适的。所以,我们需要拿Actor V20去打游戏获得的数据再来更新Actor V20。Policy Gradient每次更新参数都要重新收集一次数据,因此训练速度是非常慢的。
4 Actor-Critic 算法
4.1 价值函数的概念
Actor-Critic 算法除了Actor一个网络之外,还要引入另一个网络,叫Critic。Critic用来评估特定Actor 在某一特定环境状态下,接下来还可以获得多少回报。当然Critic也有其他变种,比如评估特定Actor 在某一特定环境状态下并执行了某个动作后,接下来还可以获得多少回报。这里只介绍第一种情况,我们将其称为价值函数(Value Function),用表示。它的工作是要估计Actor 在某一特定环境状态下可以获得的折扣累积回报(Discount cumulated reward)。折扣累积回报即。
因此,价值函数是作为一个网络,它的输入是某个环境状态,输出是这个Actor在该环境状态下可以获得的折扣累积回报。例如在Space invader游戏中,价值函数的输入就是某一个游戏界面,输出就是Actor还可以获得多少折扣累积回报。当游戏刚开局的时候,Actor还有很多机会得分,价值函数的输出会比较大;到了游戏快结束时,外星人所剩无几,Actor得分的机会不多了,价值函数的输出会比较小。当Actor打完一局游戏后,每一个游戏界面下的Actor的折扣累积回报都是可以算出来的,而价值函数希望可以做到未卜先知,提前预估Actor可以获得的折扣累积回报。注意到有一个上标,因此价值函数的输出是和Actor相关的,即使同一个价值函数,不同的Actor,估计出来的折扣累积回报是不一样的。
4.2 价值函数的训练方法
4.2.1 基于蒙特卡洛(MC)的方法
基于蒙特卡洛(MC)的方法非常直观。在Actor和环境互动的过程中,把所有回报都记录下来,直到一个episode结束,我们就能计算出每一个环境状态下Actor所获得的折扣累积回报。我们训练价值函数的目标就是让其输出和计算得到的折扣累积回报尽量相等。例如,在环境状态下,计算得到折扣累积回报为,那么就让的输出尽可能接近即可。我们可以用MAE或者MSE来定义一个LOSS。
4.2.2 基于时序差分(TD)的方法
如果忽略掉的输出和真实之间的误差,假设,则有
因此就有
所以一个新的想法是让尽可能地接近就行了,这就是TD的方法。
4.3 价值函数在优势函数上的应用
前面提到在设计优势函的时候,为了使有正有负,所以我们设置了一个基准,令
但是有一个很关键的问题使如何去设置这个基准。其实,可以令等于价值函数,即
为什么可以这么做呢?由于Actor的行为具有随机性,因此价值函数的输出其实使对折扣累积回报一种期望,也就是代表了折扣累积回报的一个平均值。如果Actor在环境状态下,执行了一个动作所获得的折扣累积回报大于平均折扣累计回报,优势函数是一个正数,说明动作是相对合理的;相反的,如果所获得的折扣累积回报小于平均折扣累计回报,优势函数是一个负数,说明动作是不太合理。但是该公式还有一个问题,Actor在环境状态下,执行了一个动作所获得的回报是,这是确定的,但是后续的回报仍然是随机的,所以后续的折扣累计回报应当也要用平均值。Actor在环境状态下,执行了一个动作后环境状态变成,因此后续的折扣累计回报的平均值就是。所以,如果忽略掉价值函数的输出和真实折扣累计回报之间的误差,有因此,可以表示为,这就是大名鼎鼎的Actor-Critic算法了。