Policy-based和Value-based是RL中Model-free的两大分支,关于value-based的课程笔记,点这里(个人认为将李宏毅教授的强化学习笔记结合Sutton强化学习书籍一起学习会更好)。本篇是关于Policy-based的课程笔记。
课程笔记参考:
李宏毅笔记(github版)、叶强pdf、Morvan、刘建平博客园
论文阅读
Sutton强化学习书籍
常见的Policy-based方法:
为什么要学习policy-based,value-based缺陷在哪?
在policy-based方法中,我们有三大成分:actor(即Agent)、环境、奖励函数。value-based如Q-learning算法是一种输出值函数,然后根据最大值函数来求解动作。而policy-based是直接输出动作的,故其可以解决连续动作的RL问题。在强化学习里面,环境跟奖励函数不是你可以控制的,环境跟奖励函数是在开始学习之前,就已经事先给定的。你唯一能做的事情是调整演员里面的策略(policy),使得演员可以得到最大的奖励。演员里面会有一个策略, 这个策略决定了演员的行为。策略就是给一个外界的输入,然后它会输出演员现在应该要执行的行为。
Note:
Policy-gradient算法是整个policy-based算法的基础,它的功能就是让策略网络参数 θ \theta θ的更新朝着性能度量 J ( θ ) J(\theta) J(θ)上升的方向移动,所以他是个梯度上升:
θ t + 1 = θ t + α ∇ θ t J ( θ t ) ^ ∇ θ t J ( θ t ) ∝ E [ ∇ θ t J ( θ t ) ^ ] \theta_{t+1}=\theta_t+\alpha\widehat{\nabla_{\theta_t}J(\theta_t)}\\ \nabla_{\theta_t}J(\theta_t)\propto\mathbb{E}[\widehat{\nabla_{\theta_t}J(\theta_t)}] θt+1=θt+α∇θtJ(θt) ∇θtJ(θt)∝E[∇θtJ(θt) ]
对于性能度量 J J J通常会取值函数,这样也符合RL的目标——最大化期望累计奖励。根据这个特性,在一般的policy-based算法中,策略梯度上升也经常作为策略提升处理。
现在的目标就是将值函数代入上述公式的 J J J中,参考Sutton强化学习的推导可得出:
∇ J ( θ ) = ∇ V π ( θ ) ∝ ∑ s μ ( s ) ∑ a ∇ π θ ( a ∣ s ) Q π ( s , a ) \nabla J(\theta)=\nabla V^\pi(\theta)\propto\sum_s\mu(s)\sum_a\nabla\pi_\theta(a|s)Q^\pi(s,a) ∇J(θ)=∇Vπ(θ)∝s∑μ(s)a∑∇πθ(a∣s)Qπ(s,a)Note:
所以我们的PG单样本更新
进一步变成:
θ t + 1 = θ t + α ∑ a ∇ θ π θ ( a ∣ s t ) Q π ( s t , a ) \theta_{t+1}=\theta_t+\alpha\sum_a\nabla_\theta\pi_\theta(a|s_t)Q^\pi(s_t,a) θt+1=θt+αa∑∇θπθ(a∣st)Qπ(st,a)
REINFORCE算法将从PG算法的 Q Q Q改成期望累计奖励 G G G,详细推导见Sutton强化学习。李宏毅老师通过另一种方法也推出了REINFORCE算法的更新公式:
我们都知道,RL的目的就是最大化累计奖励。但是由于actor处于一个陌生环境中,她一开始并不知道会怎么走,会获得多少奖励,动作都是随机的,因此相应获得的奖励也是随机的。故我们的目标就是累计奖励的估计值,即求它的期望。将他的期望当作我们的目标。因此我们就要最大化这个期望累积奖赏。policy-based通过梯度上升的方式去达到这个目标,具体的:在某一场游戏里面,某一个回合里面,我们会得到R。我们要做的事情就是调整演员内部的参数 θ \theta θ使得R的值越大越好。具体公式推导为:
Note:
将Policy Gradient看成是神经网络的分类问题:
经典的多分类问题通过Cross-Entropy 这个Loss function来求解,而我们的policy gradient也可以看成是分类问题:
Note:
从上面我们就可以看出policy gradient存在的4个问题!
Q1:
既然这个奖励回报是crisis,只要在同一个回合里面,在同一场游戏里面, 所有的状态跟动作的对都会使用同样的奖励项(term)进行加权,这件事情显然是不公平的,因为在同一场游戏里面 也许有些动作是好的,有些动作是不好的。 假设整场游戏的结果是好的, 并不代表这个游戏里面每一个行为都是对的。若是整场游戏结果不好, 但不代表游戏里面的所有行为都是错的。所以我们希望可以给每一个不同的动作前面都乘上不同的权重。每一个动作的不同权重, 它反映了每一个动作到底是好还是不好。因此改动的做法就是:只计算从这一个动作执行以后所得到的奖励。因为这场游戏在执行这个动作之前发生的事情是跟执行这个动作是没有关系的, 所以在执行这个动作之前得到多少奖励都不能算是这个动作的功劳。跟这个动作有关的东西, 只有在执行这个动作以后发生的所有的奖励把它加起来,才是这个动作真正的贡献。这个我们已经很熟悉了,因为之前在value-based里面,每个状态值函数的G就是从当前状态开始的,并且考虑到未来的不确定性, 还加了 γ \gamma γ进行衰减,如下图所示:我们前面说过policy-based的目标就是求解出策略网络,通过更新网络参数 θ \theta θ来最大化期望累计奖赏。那么如何将上述步骤融入到PyTorch的正向推理和反向传播中去呢?
其实就一句话:最小化交叉熵就是最大化对数似然。意思就是,我们现在的目标是最大化:那就等效于
最小化
:而后面这个式子与PyTorch中的Cross-Entropy loss function非常类似,我们只需稍微改动,就可以利用这个Loss function进行优化。
那么现在这个式子是我们一串轨迹样本的Loss,是Loss而不再是奖励。我们不妨一个一个样本考虑(把求和号去掉):如果当前样本产生的G很大,那么其Loss也会很大,那么梯度值就会很大,经过反向传播,然后梯度下降更新参数,那么再次正向推理的时候,之前那个动作输出的概率就会得到加强提升。反之,若G很小,那么概率的提升就会很小。当G是负数时,那么梯度下降就会往反方向去,那么之前那个动作输出的概率就会下降,这就是G起到评价输出动作的作用,也就是policy gradient的核心思想。
Note:
Q2:
既然说 G t G_t Gt是评判家,那么如果某个RL任务的奖励都是大于0的,经过反向传播,那岂不是某个状态s的所有动作a的概率都会上升吗,几个动作的概率和为1这个constrain的存在会使得比如说,3个动作 a 1 、 a 2 、 a 3 a_1、a_2、a_3 a1、a2、a3,我采样到了 a 1 a_1 a1,使得输出 a 1 a_1 a1的概率上升了,那么没采样到的 a 2 、 a 3 a_2、a_3 a2、a3就可能会下降,但是这样对a2、a3岂不是不公平吗,如果说a2是一个很好的动作,那么 a 2 a_2 a2的下降岂不是不合理吗?解决这个的办法就是引入baseline
,引入之后:这个b是怎么工作的呢?
如果得到的总奖励大于 b 的话,就让它的概率上升。如果这个总奖励小于 b,就算它是正的,正的很小也是不好的,你就要让这一项的概率下降。 如果小于b , 你就要让这个状态采取这个动作的概率下降。所以在实现训练的时候,你会不断地把每个G记录下来 然后你会不断地去计算 G的平均值, 你会把这个平均值,当作你的b来用。(平均值可以考虑用增量式计算来缩小存储)
R-b这一项合起来,称为优势函数 A π ( s , a ) = Q π ( s , a ) − V π ( s ) A^\pi(s,a)=Q^\pi(s,a)-V^\pi(s) Aπ(s,a)=Qπ(s,a)−Vπ(s)。它取决于s和a。在后续的Actor-Crisis里面,这个A是用叫做critic网络估计出来的。你需要有一个模型去跟环境做互动,你才知道接下来得到的奖励会有多少。A的上标是 θ \theta θ,说明使用θ参数的网络去和环境互动,然后得到一串轨迹,各个状态计算各自的优势函数,然后去更新 θ \theta θ。Note:
Q3:
我们的目标是设计一个最佳的策略函数π,这个π在前面一直是以符号或者网络图形展现的,具体咋设计呢?针对行为是否连续,分为Softmax策略和高斯策略:
两者处理方式如下:
离散下按概率采样动作即可,不用多说。连续下,我们通常需要知道动作的最大值action_lim,比如拉力在[-2,2],action_lim=2,我们一般都通过tanh将输出归一在[-1,1],然后乘以action_lim输出具体动作值。PG是On-policy算法,Actor先去跟环境互动去搜集资料,搜集很多的,根据它搜集到的资料,会按照policy gradient的式子去更新 policy 的参数。所以 policy gradient 是一个on-policy的算法。
Q4:
这是REINFORCEMENT的核心公式,我么已经知道,这是一种on-policy算法,这没有问题,因为采集信息和更新都是一个策略。那么这种on-policy就有个问题,从公式中我们看出,他必须等采集了完整一条轨迹之后,再更新参数,这个过程耗时不说,更要命的是更新后,刚才那条轨迹就不能在用了,是disposable的,根源在下标 τ ∼ p θ ( τ ) \tau\sim p_\theta(\tau) τ∼pθ(τ)。
也就是说花了很久去采样的东西,只能用一次,就要被迫丢掉,效率低且浪费严重。要知道实际上我们都是用nn去做PG的,他有个学习率,学习率的存在使得一份数据光一次训练是无法直接收敛的,原理上每多用一次,就会更接近目标。所以如果让一个策略去采集信息,另一个策略就来训练,那么他采他的,我训练我的,我可以抽空把同一条轨迹多训练几遍,那么是很nice,此外你在采集的时候,我训练,不耽误功夫,效率也高。这里的典型代表就是REINFORCE和PPO。
REINFORCE算法流程:
常见2种REINFORCE算法:可见我们上述所研究的policy gradient其实是结合MC的回合更新的思想,将他具体化一个算法就是-----REINFORCE算法,也是最简单的policy gradient算法。
伪代码如下:
Note:
REINFORCE实战,点这里
你可能经常在论文中看到Vanilla policy gradient(REINFORCE)或者Vanilla policy gradient/REINFORCE这样的写法,那是因为VPG和REINFORCE几乎是完全一样,只不过有一丢丢的区别
,你可以近似理解为这两个只是名字不同。
直接上VPG伪代码:
Note:
A2C:Advantage Actor Critic算法。
policy gradient结合MC的思想就是REFORCEMENT算法,采用回合更新策略网络。
REINFORCEMENT缺陷就是:
①:效率低。
②:直接用累计奖励做critic,其方差较大,收敛过程不稳定,回合间相同状态的累计奖励之间可以通过nomalization来缓解不稳定性。
针对这两点,Actor critic算法就诞生了,其用policy gradient结合TD的思想,采用步进更新策略网络。
根据critic的不同,大致可将Actor critic分为A2C(Advantage actor critic)、A3C(Asynchronous advantage actor critic)、QAC(Q Advantage actor critic)三类。
如上图所示,在做policy gradient的时候,就算以衰减G为critic,其方差大问题还是存在,造成了收敛的不稳定性,因此我们需要将这个critic换成其期望的形式,即E(G),这样可以抑制方差大带来的不稳定。
看到G,首先想到的就是value-based方法中的Q值函数,没错这里我们就是用Q值来取代G,至于后面的b,即baseline我们可以用V值函数来替代。
这样的话,优势函数Advantage function就变成了Q-V,而V是Q的期望值,故Q-V也是有正负的,这也符合我们设计baseline的初衷。
但是这样也存在一个小问题,除了策略网络以外,你还需要设计2个网络:即Q网络和V网络,为了简化成一个网络,可以对Q做个变式:回忆一下贝尔曼等式:这里可以进一步简化,根据期望公式,可转换成:
虽然都说贝尔曼等式在有模型下才能用,但是上述这个等式在推导过程中可以约去转移概率P,故可以成立。
因此我们的优势函数就变成了:这样我们设计一个网络就可以了,这其实就是TD error的值函数表达式。
整个AC算法结构:
最后你会发现,其实就是用TD error代替了G,其实V也可以充当TD目标值。只不过我们当初选择Q是因为,一是Q能选择动作而V不能;第二是因为当初用V做的时候,经过预测和控制之后,V仍需要转成Q,有了贝尔曼公式就很方便,然后用贪心策略从Q中选出了动作,那么model-free没有贝尔曼公式中的转移概率P,故为了省去这一步,我们直接选择了Q。但是现在动作有policy网络输出,故我们可以不用Q了。其实Q和V从定义就可以看出没啥大差别,就相差了个动作而已,都表达了未来价值的期望值。
上图是网络结构图,和Dueling网络一样之后,由共享网络和子网络组成,子网络分别为策略网络和V估计网络。
A2C算法流程:以下伪代码是on-policy版的A2C,因为行为策略和目标策略均为一个策略,A2C没有官方的伪代码,但是从A3C的代码中看出A2C是如下所示,现在网上实现的A2C都是这种形式。
需要注意的是,不管要不要加IS,A2C都是on-policy算法,因为更新的关键在于,Critci只是辅助作用。
正因为只有一个策略(on-policy),因此Critic估计的V值不需要再加IS修正,即伪代码第7行的中不需要加IS修正因子。
虽然A2C在实现上是TD error的形式,但实现上这种需要估计Q、V网络的做法是不可取的,因为如果估计不准确的话,会造成双倍的风险。
其实就是根据定义,看策略网络有几种策略输出,AC需要判断Actor和Critic各自是否off-policy。但两者是联合的,也就是说,一个是on-policy,另一个一定不是off-policy。一般以判断Actor为主,有2个策略的,则是off-policy的AC算法,如DDPG:确定性策略和带噪声的确定性策略。on-policy的AC典型的就是上面这个A2C,因为Actor只输出一个策略。
下面这个Critic基于Sarsa的on-policy算法,我觉得也行,根据QAC对应改编的。Note:
另一种直接利用Q的是QAC,即Critic是Q值,这是一种on-policy AC算法,因为其Critic是Sarsa,故如下所示:
A2C实战部分,点这里
A3C论文笔记,点这里
A3C:即Asynchronous Adavantage Actor-Critic
针对A2C难以收敛原因之一的输入连续性问题,就出了2大分支,一个是DDPG,采用Experience Reply。另一个是A3C,采用多线程并行更新网络参数的方式。体现2种不同的解决问题的思想。A3C是针对多块CPU上的,GA3C是针对多块GPU上的,GA3C相对A3C速度更快,且节省内存。
A3C解决了Actor-Critic难以收敛的问题,同时更重要的是,提供了一种通用的异步的并发的强化学习框架,也就是说,这个并发框架不光可以用于A3C,还可以用于其他的强化学习算法。这是A3C最大的贡献。目前,已经有基于GPU的A3C框架,这样A3C的框架训练速度就更快了。
DPG主要的四大贡献:
①:确定性策略a=(s),而非之前的随机策略,e.g. 高斯策略和softmax策略
②:调整策略参数θ朝着值函数Q梯度上升的方向。
③:确定性策略梯度的performance objective只对状态积分,相比于随机性策略,对动作的积分空间大大减少,意味着无需对动作进行采样了,大大提高了效率。
④:Actor使用确定性策略,其对动作不积分不采样,不需要IS修正因子。
关于DPG论文笔记,点这里
DDPG的论文主要是介绍DQN + DPG的结合,然后给出一套伪代码以及实验,全文比较简单,读者可以自行去简要看下。
DPG:引入点,随机策略对于高维动作空间不适用,即上述DPG的第②个贡献点。
确定性指的是策略网络输出的动作是确定性的,当然后期为了在这个确定性的基础上,会有一定的上下浮动,即噪声,用于增强一定的探索能力。在之前的softmax或者高斯策略中,一个用于离散动作,一个用于连续动作,其动作实在这两个策略的输出分布中采样获取,是随机性策略。而Determinister就好像说:“softmax兄弟,既然你最终都是要输出一个动作的,为啥要这么犹豫去随机选取呢,直接输出一个确定的动作不就好啦”。
DDPG核心思想:如上图框架结构所示,将Nature DQN的思想与policy gradient结合在一起,构建四个网络:策略网络、策略目标网络、Q估计网络、Q目标网络。
DDPG由DQN和DPG组成,DQN(指Nature DQN)采用了Experience Reply以及Target Network两项关键技术,分别解决了RL中样本输入连续、相关性强,导致无法通过nn训练的问题以及TD目标值和Q估计值难以靠近的不收敛问题。
DDPG是DQN的扩展版本,专门用于解决DQN解决不了的连续动作空间问题。其两大网络Actor和Critic网络(就是上述的DQN)都采用了Target Network技术,以及用Experience Reply来打破输入样本连续性问题,以便更好地去训练网络。
因此DDPG由策略网络、策略目标网络、Q估计网络、Q目标网络四大网络组成。具体网络结构如下:
Note:
Note:
总结:DDPG中。Critic给Actor提供准确的Q值,从而更新参数θ。Actor给Critic提供行为策略和目标策略(max化Q),两者相辅相成,共同进步,最终Critic能估计出Q真实值,而Actor能输出最优策略。
DDPG实战,点这里
TD3算法是DDPG的进阶版,训练稳定性更强,且缓解了AC算法Critic过估计问题。
TD3理论部分:TD3论文笔记
TD3实战部分:TD3实战
Smoothie算法引入了一种新的 Q Q Q——平滑 Q Q Q,其策略网络是多维高斯分布,要训练三个网络 μ 、 Σ 、 ω \mu、\Sigma、\omega μ、Σ、ω,分别是高斯分布的均值网络、协方差网络以及Critic网络。总的来说其结构还是基于DDPG。
Smoothie论文笔记,点这里
和Smoothie算法一样,SAC系列算法引入了新的 Q Q Q—— Q s o f t Q_{soft} Qsoft,而且其改变了RL的目标函数为——最大化含熵目标,因此需要重新设计软贝尔曼等式。
SQL论文笔记,点这里
SAC论文笔记,点这里
SAC提升版算法笔记,点这里
PPO系列算法旨在设计一种策略单调不减的算法,是为了解决PG中学习率大小的算法。这个系列算法的不直接优化传统的RL目标 η \eta η,而是去优化 η \eta η的近似替代函数。
TRPO论文笔记,点这里
PPO比TRPO更加实用,对于TRPO我们只要掌握其理论即可,实战还得靠PPO,因此我们详细介绍PPO
PPO论文笔记,点这里
Note:
PPO,即Proximal Policy Optimization(近端策略优化),根据OpenAI的官博,PPO已经成为他们在RL上的默认算法。在OpenAI提出TRPO(Trust Region Policy Optimization)后,DeepMind和OpenAI先后发布了DPPO(Distributed PPO)和PPO算法。PPO算法是一种On-policy算法,即和环境交流的策略与目标(训练用的)策略不是一个策略。
PPO = Policy-Gradient + Importance Sampling + KL散度,意思就是说PPO是一种在on-policy PG算法上使用IS技术,并用KL散度消除因IS新旧分布相差过大导致方差较大缺陷的一种算法。
因此,PPO算法的推出需要历经2个步骤:
这里我们使用对PG改进版本的PG算法,即用优势函数A代替G:
通过重要性采样(关于IS,可查看我的另一篇博客),我们可以将上面这个on-policy改成:
Note:
进一步转换:这里第二步到第三步是直接忽略掉了,不是啥数学原因,纯粹为了方便计算。此外,看到什么状态往往跟你会采取什么样的动作是没有太大的关系的。比如说你玩不同的 Atari 的游戏,其实你看到的游戏画面都是差不多的,所以也许不同的策略对状态的概率是差不多的,比值为1。
因此我们可以通过求导的链式法则和 ∇ f ( x ) = f ( x ) ⋅ ∇ log f ( x ) \nabla f(x)=f(x)\cdot\nabla\log f(x) ∇f(x)=f(x)⋅∇logf(x),推导出目标函数:接下来,我们将这个新旧策略的比值看成是新策略 θ n e w \theta_{new} θnew和旧策略(当前策略) θ o l d \theta_{old} θold的比值。
IS采样的缺陷在于2个新旧分布不能相差太大,否则会导致方差相差很大(即稳定性降低),从而使得两者的样本均值不一样。PPO为了解决这个问题,使得2个分布相差不大,就引入了一个约束条件,这个约束就是KL散度,用来衡量和有多相似。
KL散度就相当于L2正则化项一样,像约束着 ω \omega ω尽量小一样约束 θ o l d \theta_{old} θold和 θ n e w \theta_{new} θnew尽量相似。
PPO的前身是TRPO,两者不同在于KL的位置,TRPO将constrain放在约束条件上,PPO略微简单,像加L2正则化一样将约束加到了performance objective一起优化。具体如下图所示:
引入KL后,上图就是PPO算法!KL的引入使得方差不会相差很大,也就是保证了算法的稳定性。
Note:
PPO设定了可自动调节的 K L KL KL因子 β \beta β:
我们一开始会自己设定一个 K L m a x 、 K L m i n KL_{max}、KL_{min} KLmax、KLmin,如果参数更新完后,我们的KL项比我们设定的值大,那么就增加,否则就减小。这个就叫做Adaptive KL Penalty。
这个算法比上面这个算法更容易实现,因为他用clip函数巧妙避开了KL的计算。
顾名思义,PPO-Clip中涉及到了Clip函数,就是如果x大于max值,则输出max,x小于min值,输出为min值,否则输出为x。
Clip版本目标函数:
那么它是如何使得2个动作分布相差不大的呢?
A是优势函数,A>0说明我们需要加强这个动作,A<0,代表这个动作相对不太好,我们要抑制这个动作的概率。
如上面2张图所示,绿色线是蓝色线是
,红色线就是他们当中的最小值,也就是我们直接去利用的数,这里简记为Target。
分析:假设 ϵ = 0.2 \epsilon=0.2 ϵ=0.2
总结:
PPO是一个实现起来较容易且在连续动作空间环境下表现效果不错的算法,是一个很不错的baseline。