之前没有深入和系统的学习过强化学习,最近由于科研刚需,上网查资料刚好看到知乎上面有个大佬的强化学习的系列文章,感觉写的很好,于是就把他的文章看了一遍,顺便做了一些笔记,这里记录一下。

原文: https://zhuanlan.zhihu.com/p/111895463

卧槽大佬讲的真的好,笔记记不了一点!!!建议大家都去看原文!

后面可能会自己写一下 MADDPGMATD3 的相关内容,到时候再更新。

2023/10/23 这几天把大佬的强化学习专栏看了一遍了,真的很不错,但是我觉得还是得自己总结一下重难点,且这周五和东大的联合组会轮到我讲了,刚好深入理解一下强化学习算法。所以还是写一下这篇笔记吧!

学习路线:
学习路线

马尔可夫树

强化学习的任务:

  • 希望用强化学习的方式,使某个智能体获得独立自主地完成某种任务的能力。
  • 智能体学习和工作的地方,称为环境
  • 所谓独立自主,就是智能体一旦启动,就不需要人指挥了。

经典马尔可夫链

马尔科夫链.png

  • 状态(state):智能体观察到的当前环境的部分或者全部特征。
    • 注意:环境的特征可能有许多,但只有智能体能够观察到的特征才算是状态。所以也用observation表示状态。
  • 动作(action):智能体做出的具体行为。
    • 动作空间就是该智能体能够做出的动作数量。智能体身处十字路口。那么方向就有4个。也就是说,动作空间为4个动作。
  • 奖励(reward):智能体在某个状态下采取某个动作所获得的反馈。
    • 奖励是一个标量,可以是正数,也可以是负数。奖励越大,说明智能体做的越好。奖励越小,说明智能体做的越差。

RL一般步骤

  1. 智能体在环境中,观察到状态(S);
  2. 状态(S)被输入到智能体,智能体经过计算,选择动作(A);
  3. 动作(A)使智能体进入另外一个状态(S),并返回奖励(R)给智能体。
  4. 智能体根据返回,调整自己的策略。 重复以上步骤,一步一步创造马尔科夫链。

马尔可夫树

马尔科夫链之所以是现在看到的一条链条。是因为站在现在往过去看,所以是一条确定的路径。但如果往前看,就并不是一条路径,而是充满了各种”不确定性”, 即”马尔可夫树”。

马尔科夫树.png

这种”不确定性”来自两个方面:

  • 智能体的行动选择(策略)。
  • 环境的不确定性。

RL中的Q值和V值

并不能单纯通过R来衡量一个动作的好坏,因为R只是一个瞬时的反馈,而需要的是长期的反馈。在做决策的时候,需要把眼光放远点,把未来的价值换到当前,才能做出选择。

希望可以有一种方法评估我做出每种选择价值。这样,只要看一下标记,以后的事情也不用理,选择那个动作价值更大,就选那个动作就可以了。

  • 评估动作的价值称为Q值:它代表了智能体选择这个动作后,一直到最终状态奖励总和的期望。
  • 评估状态的价值称为V值:它代表了智能体在这个状态下,一直到最终状态的奖励总和的期望。

价值越高,表示从当前状态到最终状态能获得的平均奖励将会越高。因为智能体的目标数是获取尽可能多的奖励,所以智能体在当前状态,只需要选择价值高的动作就可以了。

V值的定义

V值的定义.png

假设现在需要求某状态S的V值,可以这样:

  1. 从S点出发,并影分身出若干个自己;
  2. 每个分身按照当前的策略 选择行为;
  3. 每个分身一直走到最终状态,并计算一路上获得的所有奖励总和;
  4. 计算每个影分身获得的平均值,这个平均值就是要求的V值。

总结:从某个状态,按照策略 ,走到最终状态很多很多次;最终获得奖励总和的平均值,就是V值。

V值跟选择的策略有很大的关系

看这样一个简化的例子,从S出发,只有两种选择,A1,A2;从A1,A2只有一条路径到最终状态,获得总奖励分别为10和20。

例子1.png

策略1.png

策略2.png

可以看出不同的策略,计算出的V值是不一样的。

Q值的定义

Q值的定义.png

现在需要计算,某个状态S0下的一个动作A的Q值:

  1. 从A这个节点出发,使用影分身之术;
  2. 每个影分身走到最终状态,并记录所获得的奖励;
  3. 求取所有影分身获得奖励的平均值,这个平均值就是要求的Q值。

总结:从某个状态选取动作A,走到最终状态很多很多次;最终获得奖励总和的平均值,就是Q值。

与V值不同,Q值和策略并没有直接相关,而与环境的状态转移概率相关,而环境的状态转移概率是不变的。

V值和Q值关系

Q和V之间是可以相互换算的

Q值转V值

Q值转V值.png

从定义出发,要求的V值,就是从状态S出发,到最终获取的所获得的奖励总和的期望值。也就是蓝色框部分。

S状态下有若干个动作,每个动作的Q值,就是从这个动作之后所获得的奖励总和的期望值。也就是红色框部分。

假设已经计算出每个动作的Q值,那么在计算V值的时候就不需要一直走到最终状态了,只需要走到动作节点,看一下每个动作节点的Q值,根据策略 ,计算Q的期望就是V值了。

Q值转V值1.png

更正式的公式如下:
公式1.png

解释:一个状态的V值,就是这个状态下的所有动作的Q值,在策略下的期望。

V值转Q值

Q是V的期望。而这里不需要关注策略,这里是环境的状态转移概率决定的。

V值转Q值.png

当选择A,并转移到新的状态时,就能获得奖励,必须把这个奖励也算上!

V值转Q值1.png

更正式的公式如下:
公式2.png

折扣率 在强化学习中,有某些参数是人为主观制定。这些参数并不能推导,但在实际应用中却能解决问题,所以称这些参数为超参数,而折扣率就是一个超参数。

V值转V值

实际应用中,更多会从V到V。其实就是把Q值的公式代入V值的公式。

V值转V值.png

MC

蒙地卡罗方法(Monte-Carlo)

蒙地卡罗算法

  1. 把智能体放到环境的任意状态;
  2. 从这个状态开始按照策略进行选择动作,并进入新的状态。
  3. 重复步骤2,直到最终状态;
  4. 从最终状态开始向前回溯:计算每个状态的G值。
  5. 重复1-4多次,然后平均每个状态的G值,这就是要求的V值。

G值的意义

重要:G值是一个具体的累积奖励值,而Q值和V值是对这个累积奖励值的估计。

G值的意义.png

  • 第一步,根据策略往前走,一直走到最后,期间什么都不用算,还需要记录每一个状态转移,获得多少奖励r即可。
  • 第二步,从终点往前走,一遍走一遍计算G值。G值等于上一个状态的G值(记作G’),乘以一定的折扣(gamma),再加上r。

所以G值的意义在于,在这一次游戏中,某个状态到最终状态的奖励总和(理解时可以忽略折扣值gamma)。

当进行多次试验后,有可能会经过某个状态多次,通过回溯,也会有多个G值。 重复刚才说的,每一个G值,就是每次到最终状态获得的奖励总和。而V值是某个状态下,通过影分身到达最终状态,所有影分身获得的奖励的平均值。

理解:

  1. G的意义:在某个路径上,状态S到最终状态的总收获。
  2. V和G的关系:V是G的平均数。

V和策略相关

策略3.png

策略4.png

由于策略改变,经过某条路径的概率就会产生变化。因此最终试验经过的次数就不一样了。

蒙地卡罗算法的缺点

每一次游戏,都需要先从头走到尾,再进行回溯更新。如果最终状态很难达到,那可能每一次都要转很久很久才能更新一次G值。

MC的更新公式

上面计算V值其实相当麻烦,因为每一个状态都需要建立一个空间,记录每个轨迹下的G值。

那有没有一种方法,可以用更少的空间计算V值呢?当然有,那就是增量更新

增量更新

现在只需要记录之前的平均值V,新加进来的G,和次数N。把V和G的差,除以N,然后再加到原来的平均值V上,就能计算到新的V值。

V_new = (V_old - G) * (1 / N) + V_old

  • V_old:原来的V值
  • G:这一次回溯后,计算出来的G值
  • N: 这个状态被经过多少次
  • V_new:新计算出来的V值

更进一步

这样计算还是比较麻烦,甚至可以不用记录N,把(1/N)设置成为一个固定的数,例如0.1、0.2(还记得超参数吗?)。把这个值称为学习率

这就相当于,新来的G和V_old的差的十分之一,会被加到V_new上!也就是说,每一次G都会引导V增加一些或者减少一些,而这个V值慢慢就会接近真正的V值。

这里的G,也称为V的更新目标。

而学习率就可以理解为,每次V向目标靠近的幅度;学习率越大,表示向G靠近的幅度越大,反之则越小。

两种理解方式

两种理解方式.png

TD

时序差分算法TD(Temporal-Difference)

TD和MC的比较

TD算法对蒙地卡罗(MC)进行了改进:

  1. 和蒙地卡罗(MC)不同:TD算法只需要走N步,不用走到终点,就可以开始回溯更新。
  2. 和蒙地卡罗(MC)一样:需要先走N步,每经过一个状态,把奖励r记录下来。然后开始回溯。
  3. 那么,状态的V值怎么算呢?其实和蒙地卡罗一样,就假设N步之后,就到达了最终状态了。
    • 假设“最终状态”上之前没有走过,所以这个状态上的纸是空白的。这个时候就当这个状态为0.
    • 假设“最终状态”上已经走过了,这个状态的V值,就是当前值。然后开始回溯。

直观理解

从A状态,经过1步,到B状态。什么都不管就当B状态是最终状态了。此时N = 0,也叫做TD(0)

但B状态本身就带有一定的价值,也就是V值。其意义就是从B状态到最终状态的总价值期望。

TD(0).png

假设B状态的V值是对的,那么,通过回溯计算,就能知道A状态的更新目标了。

更新公式

TD并走走完整段路程,而是半路就截断。用半路的路牌,更新当前的路牌。 所以只需要把MC的更新目标,改为TD的更新目标即可。

在MC,G是更新目标,而在TD,只不过把更新目标从G,改成r+gamma*V

更新公式.png

Q-learning

之前用TD(0)预估状态价值V:
TD(0)更新公式.png

图解:
TD(0)图解.png

TD能够用在V值,那么也能用在计算Q值上。

TD之于Q值估算

现在用上TD的思路。 在St,智能体根据策略pi,选择动作At,进入S(t+1)状态,并获得奖励R。
用TD估计Q值.png

  • V(St+1)的意义是,在St+1到最终状态获得的奖励期望值。
  • Q(St,At)的意义是,在Q(St,At)到最终状态获得的奖励期望值。

在这里要估算两个东西,一个是V值,一个是Q值。人们想到用下一个动作的Q值代替V值。
用下一个动作的Q代替V.png

但是,这里就有个坑:虽然从状态St+1到动作At+1之间没有奖励反馈,但还是不能直接用At+1的Q价值,代替St+1的V价值。

因为马尔可夫树!
坑的解释.png

在St+1下,可能有很多动作At+1。不同动作的Q值自然是不同的。 所以Q(St+1,At+1)并不能等价于V(St+1)。

虽然不相等,但不代表不能用其中一个来代表V(St+1)。人们认为有个可能的动作产生的Q值能够一定程度代表V(St+1)。

  1. 在相同策略下产生的动作At+1。这就是SARSA
  2. 选择能够产生最大Q值的动作At+1。这就是Qlearning

SARSA

SARSA.png

其实SARSA和上一篇说的TD估算V值几乎一模一样,只不过挪了一下,从V改成Q了。

SARSA公式.png
TD(0)与SARSA对比.png

注意: 这里的At+1是在同一策略产生的。也就是说,St选At的策略和St+1选At+1是同一个策略。这也是SARSA和Qlearning的唯一区别。

Qlearning

Qlearning将能够产生最大Q值的动作At+1的Q值作为V(St+1)的替代。

Qlearning图解.png

理解:因为需要寻着的是能获得最多奖励的动作,Q值就代表能够获得今后奖励的期望值。所以选择Q值最大的,也只有最大Q值能够代表V值。
Qlearning公式.png

Q(S,a)的更新目标:在Qlearning,用下一状态St+1的最大Q值替代St+1的V值。V(St+1)加上状态转移产生的奖励R。

SARSA公式.png

Qleanring和SARSA,两者的差别仅仅在Qlearning中多了个max。

总结

  1. Qlearning和SARSA都是基于TD(0)的。不过在之前的介绍中,用TD(0)估算状态的V值。而Qlearning和SARSA估算的是动作的Q值。
  2. Qlearning和SARSA的核心原理,是用下一个状态St+1的V值,估算Q值。
  3. 既要估算Q值,又要估算V值会显得比较麻烦。所以用下一状态下的某一个动作的Q值,来代表St+1的V值。
  4. Qlearning和SARSA唯一的不同,就是用什么动作的Q值替代St+1的V值。
    • SARSA 选择的是在St同一个策略产生的动作。
    • Qlearning 选择的是能够产生最大的Q值的动作。

Qlearning 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

深度神经网络

深度强化学习:用深度神经网络辅助强化学习。

原理

假如知道X,y有关系,那么不妨先设这个关系可以通过函数Magic(X)获得。也就是说Magic(X)=y。

这在手写数字识别中,X就是需要识别的图片,y就是识别出来的数字分类。 任务就是需要求这个Magic函数。
Magic(X).png

现在假设有另外一个函数Magic’(),这个函数是由深度神经网络构成。

在刚开始的时候,很明显Magic’(X) 并不等于y,例如输入手写图片8,Magic’()计算后,认为数字8只有20%,但数字9有40%。

…但这没所谓,因为这是刚开始。任务是让Magic’(X)产生的结果y’ 和 y尽量接近。

y’和真实y之间的差距,叫损失,也就是loss。有时候也会把y称为目标(target),因为任务就是让Magic’(X)越来越靠近这个目标。

衡量loss的方法有很多,定义不同loss对神经网络学习有着重大差别,话题太大暂时不展开。

loss越大,表示和目标差距越远;loss越小,表示和目标越近,当小到一定值,那么就可以认为Magic’(X)和Magic(X)函数非常接近,可以通过Magic’(X)计算出y。

当有许许多多这样的y,经过许许多多轮后。Magic’就越来越贴近Magic。也就是说X和y之间的关系就能越来越好地表达出来。

Magic'(X).png

放大镜下的深度神经网络

数据加工厂.png

现在可以把深度神经网络的Magic函数,看成是一个数据加工厂。而X就是要进行加工的数据。

为了让这个数据加工厂运行得更快,通常需要把要加工的数据X变得更标准一些。

例如图片的尺寸大小,有多少通道的颜色等等,然后分批(batch),输入工厂。

在输入工厂的时候,会有一个‘大门’,称为输入层,去检查数据是否已经按照工厂的标准整理好。

数据工厂里有很多车间,按照流水线排列。和一般的自动化车间一样,需要定义好这个车间的操作标准。

一般称这些车间叫这些层都已经封装好在tensorflow、tensorlayer、pytorch等里面了。常用的层包括:Dense、Conv2D、LSTM、Reshape、Flatten等。

最终,数据工厂会把原数据X,加工成产品y'(也叫做:logits)。从源数据加工成产品的过程,叫正向传播

但产品y’是否是一个合格的产品,还需要真正的y(lables)作为标准去鉴定。把鉴定出来的差距就是loss

工厂根据鉴定结果,以梯度下降的方式,反向传递给每个车间,告诉车间要如何调整各自的参数,让源数据和产出y’能够对应起来。

经过N个批次(batch)的数据输入,然后鉴别,工厂调整。最后工厂就能达到生产标准了。也就是说magic函数已经被训练好了。

DQN

DQN: TD + 神经网络

在Qlearning中,有一个Qtable,记录着在每一个状态下,各个动作的Q值。

Qtable的作用是当输入状态S,通过查表返回能够获得最大Q值的动作A。也就是需要找一个S-A的对应关系。

这种方式很适合格子游戏。因为格子游戏中的每一个格子就是一个状态,但在现实生活中,很多状态并不是离散而是连续的。

用神经网络解决Qlearning中动作离散的问题,让动作变成连续的,这就是DQN。

Deep network + Qlearning = DQN

神经网络万能函数(神经网络)Magic(X)接受输入一个状态S,它能告诉我,每个动作的Q值是怎样的。

理解DQN中的神经网络

Qtable三维可视化:
Qtable三维可视化.png

图中每根柱子的高度,表示状态S下,选择动作A的Q值。

现在用函数来表示,相当于要扭曲一条曲线,这条曲线穿过了离散状态下的所有点。

扭曲的曲线.png

从二维状态看:
二维曲线.png

所以现在不但可以取状态3和状态4,还可以取状态3.5的Q值。

现在就很清楚了,其实Qlearning和DQN并没有根本的区别。只是DQN用神经网络,也就是一个函数替代了原来Qtable而已。

更新目标

更新目标就是Magic(X),最终要向这个Magix(X)靠近。

在Qlearning,用下一状态St+1的最大Q值替代St+1的V值。V(St+1)加上状态转移产生的奖励R。就是Q(S,a)的更新目标。

DQN和Qlearning一样:
DQN.png
假设需要更新当前状态St下的某动作A的Q值:Q(S,A),可以这样做:

  1. 执行A,往前一步,到达St+1;
  2. 把St+1输入Q网络,计算St+1下所有动作的Q值;
  3. 获得最大的Q值加上奖励R作为更新目标;
  4. 计算损失
    • Q(S,A)相当于有监督学习中的logits
    • maxQ(St+1) + R 相当于有监督学习中的lables
    • 用mse函数,得出两者的loss
    • Loss = (Q(S, A) - [gamma * maxQ(St+1) + R])^2
  5. 用loss更新Q网络。(反向传播)

通常会使用一个折扣因子 gamma 来考虑未来奖励的重要性。折扣因子 gamma 的作用是对未来奖励进行衰减,使得当前时刻的奖励比未来时刻的奖励更具有影响力。

也就是,用Q网络估算出来的两个相邻状态的Q值,他们之间的距离,就是一个r的距离。这个就是更新目标
Target = R + gamma * maxQ(St+1)

DQN公式.png

总结:

  1. 其实DQN就是Qlearning扔掉Qtable,换上深度神经网络。
  2. 解决连续型问题,如果表格不能表示,就用函数,而最好的函数就是深度神经网络。
  3. 和有监督学习不同,深度强化学习中,需要自己找更新目标。通常在马尔科夫链体系下,两个相邻状态状态差一个奖励r经常能够作为更新目标。

DQN 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

Double DQN

经验回放

经验回放解决了强化学习中的两个问题: 训练网络数据采集慢过度拟合

当然这个慢是对比网络训练的速度。在强化学习中,网络训练经过GPU的加速,比起游戏来时快很多的。所以训练的瓶颈一般在智能体跟环境互动的过程中。 如果能把互动过程中的数据,都存起来,当数据最够多的时候,再训练网络,那么就快很多了。

把每一步的s,选择的a,进入新的状态s’,获得的奖励r,新状态是否为终止状态。都存在一个叫回放缓存的地方(replay buffer)。
当智能体与环境互动期间,就会不断产生这样一条一条数据。 数据1: 数据2: 数据3: ….
当数据量足够,达到设定一个batch的大小,便从中抽出一个batch大小的数据,把这笔数据一起放入网络进行训练。
训练之后继续进行游戏,继续把新产生的数据添加到回放缓存里…
就这样每次都随机抽出一个batch大小的数据训练智能体。这样,以前产生的数据同样也能用来训练数据了, 效率自然更高。

使用经验回放除了使训练更高效,同时也减少了训练产生的过度拟合的问题。
过度拟合,放到人身上就是过度依赖局部经验了。
就像孩子发现爸爸有胡子,就认为所有男人都有胡子一样。
同样,在有监督学习中,如果只给模型看少量的几张图,并且告诉模型这是猫。这样模型就只会从这几张图学习到猫的特点,而更多的猫模型可能就不认得了。说这就是过度拟合造成的,导致模型不够健壮。

DQN的问题

DQN的目标:
Target = R + gamma * maxQ(St+1)

目标本身就包含一个Q网络,理论上是没有问题的,但,这样会造成Q网络的学习效率比较低,而且不稳定。

如果把训练神经网络比喻成射击游戏,在target中有Q网络的话,就相当于在射击一个移动靶,因为每次射击一次,靶就会挪动一次。相比起固定的靶,无疑加上了训练的难度。

要解决这个问题,就把移动靶弄成是固定的靶,先停止10秒。10后挪动靶再打新的靶。这就是Fixed Q-targets的思路。

Fixed Q-targets

fix-Q-targets.png

其他地方和DQN一样,唯一不同是用了两个Q网络。

  • 原来的Q网络,用于估算Q(s);
  • targetQ网络, targetQ自己并不会更新,也就是它在更新的过程中是固定的,用于计算更新目标。
    • y = r + gamma * max(targetQ(s'))
    • 进行N次更新后,就把新Q网络的参数赋值给旧Q网络,保持训练的稳定性。

Double DQN

DQN有一个显著的问题,就是DQN估计的Q值往往会偏大。这是由于Q值是以下一个s’的Q值的最大值来估算的,但下一个state的Q值也是一个估算值,也依赖它的下一个state的Q值…,这就导致了Q值往往会有偏大的的情况出现。

这个思路也很直观。如果只有一个Q网络,Q值的估计往往偏大。那就用两个Q网络,因为两个Q网络的参数有差别,所以对于同一个动作的评估也会有少许不同。选取评估出来较小的值来计算更新目标。这样就能有效避免Q网络估值偏大的情况发生了。

另外一种做法也需要用到两个Q网络:Q1网络推荐能够获得最大Q值的动作;Q2网络计算这个动作在Q2网络中的Q值。

Double DQN 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

Duel DQN

Dueling DQN原理

回到Qtable, 原来会直接预估Q值表的数据,现在改为需要预估两个值:S值和A值。即Q = S + A

  • S: 在特定状态下采取任何行动的平均价值,也就是该state下的Q值的平均数。
  • A: 在特定状态下采取特定动作相对于采取平均动作的优势。A的平均值为0。

Q=S+A表格.png

普通DQN的Q网络,可以理解用一个曲线去拟合Qtable的Q值。现在取一个截面,表示当取某个S下,各个动作的Q值。

普通DQN.png

普通DQN在提升某个状态下的S值时,只会提升某个动作。

Dueling DQN: 在网络更新的时候,由于有A值之和必须为0的限制,所以网络会优先更新S值。S值是Q值的平均数,平均数的调整相当于一次性S下的所有Q值都更新一遍。

DuelDQN.png

如上图,橙色虚线是平均值,也就是S值。 所以网络在更新的时候,不但更新某个动作的Q值,而是把这个状态下,所有动作的Q值都调整一次。这样,就可以在更少的次数让更多的值进行更新。

这样调整最后的数值是对的吗?放心,在DuelingDQN,只是优先调整S值。但最终的target目标是没有变的,所以最后更新出来也是对的。

网络架构

DuelDQN网络架构.png

可以把dueling DQN分为三部分:

  • 第一部分:和普通DQN一样,用来处理和学习数据。
  • 第二部分:计算svalue,就是让网络预估的平均值。
  • 第三部分:计算avalue,和svalue一样,都是从h2层输入到该层。然后对avalue进行归一化处理,也就是增加“A值的平均值为0”的限制。
    • 归一化的处理很简单,求A值的平均值,然后用A值减去平均值即可。A-mean(A)

DeulingDQN的实现很简单,只需要修改Q网络的网络架构就可以了。而且可以和其他DQN的技巧,例如经验回放,固定网络,双网络计算目标等可以共用。

Duel DQN 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

PG

策略梯度(Policy Gradient)

之前的MC、TD、Qlearning、DQN都是基于值的方法,就是一定要算Q值和V值。但事实上最终目的是要找一个策略,能获得最多的奖励。

这就是策略梯度(Policy Gradient)

PG原理

认识到:

DQN: TD + 神经网络
PG: MC + 神经网络

PG中的Magic(state):
当输入state的时候,输出pi,告诉智能体这个状态,应该如何应对: = magic(state)。如果智能体的动作是对的,那么就让这个动作获得更多被选择的几率;相反,如果这个动作是错的,那么这个动作被选择的几率将会减少。

复习一下蒙地卡罗:
从某个state出发,然后一直走,直到最终状态。然后从最终状态原路返回,对每个状态评估G值。 所以G值能够表示在策略下,智能体选择的这条路径的好坏。
复习MC.png

直观感受PG

从某个state出发,可以采取三个动作。 假设当前智能体对这一无所知,那么,可能采取平均策略 Pi0 = [33%,33%,33%]。智能体出发,选择动作A,到达最终状态后开始回溯,计算得到 G = 1。

直观感受PG1.png

更新策略,因为该路径选择了A而产生的,并获得G = 1;因此要更新策略:让A的概率提升,相对地,BC的概率就会降低。 计算得新策略为: Pi1 = [50%,25%,25%]。虽然B概率比较低,但仍然有可能被选中。第二轮刚好选中B。智能体选择了B,到达最终状态后回溯,计算得到 G = -1。

直观感受PG2.png

此时对B动作的评价比较低,并且希望以后会少点选择B,因此要降低B选择的概率,而相对地,AC的选择将会提高。计算得新策略为: Pi2 = [55%,15%,30%]。最后随机到C,回溯计算后,计算得G = 5。

直观感受PG3.png

C比A还要多得多。因此这一次更新,C的概率需要大幅提升,相对地,AB概率降低。 Pi3 = [20%,5%,75%]。

PG 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

AC

AC: PG + DQN(TD + 神经网络)

PG利用带权重的梯度下降方法更新策略,而获得权重的方法是MC计算G值。MC需要完成整个游戏过程,直到最终状态,才能通过回溯计算G值。这使得PG方法的效率被限制。

改为TD可以解决上面的问题。接下来又面临另一个问题:
在PG,需要计算G值;那么在TD中,应该怎样估算每一步的Q值呢?答案是用神经网络。

也就是说,Actor-Critic,其实是用了两个网络:

两网络都输入状态S,Critic比Actor多一个St+1:

  • 一个网络输出策略,负责选择动作,把这个网络成为Actor;
  • 一个网络负责计算每个动作的分数,把这个网络成为Critic。

TD-error

在DQN预估的是Q值,在AC中的Critic,估算的是V值。不估算Q值是因为效果不好。
为什么不估算Q.png

假设用Critic网络,预估到S状态下三个动作A1,A2,A3的Q值分别为1,2,10。 但在开始的时候,采用平均策略,于是随机到A1。于是用策略梯度的带权重方法更新策略,这里的权重就是Q值。于是策略会更倾向于选择A1,意味着更大概率选择A1。结果A1的概率就持续升高…

这就掉进了正数陷阱。明明希望A3能够获得更多的机会,最后却是A1获得最多的机会。这是为什么呢?
因为Q值用于是一个正数,如果权重是一个正数,那么相当于提高对应动作的选择的概率。权重越大,调整的幅度将会越大。其实当有足够的迭代次数,这个是不用担心这个问题的。因为总会有机会抽中到权重更大的动作,因为权重比较大,抽中一次就能提高很高的概率。

但在强化学习中,往往没有足够的时间去和环境互动。这就会出现由于运气不好,使得一个很好的动作没有被采样到的情况发生。要解决这个问题,可以通过减去一个baseline,令到权重有正有负。而通常这个baseline,选取的是权重的平均值。减去平均值之后,值就变成有正有负了。而Q值的期望(均值)就是V。

TD-error.png

可以得到更新的权重:Q(s,a)-V(s),Q(s,a)用gamma * V(s') + r 代替。
得到TD-error:TD-error = gamma * V(s') + r - V(s)

和之前DQN的更新公式非常像,只不过DQN的更新用了Q,而TD-error用的是V。如果Critic是用来预估V值,而不是原来讨论的Q值。那么,这个TD-error是用来更新Critic的loss了!没错,Critic的任务就是让TD-error尽量小。然后TD-error给Actor做更新。

至于为啥TD-error是用来更新Critic的loss呢?
取TD-error的方差来作为critic的loss,其实类似于DQN中的Q网络,认为下个状态的估算值比目前状态的Q值更精确,所以把下个状态的估算值作为目标,来更新Q网络。此处单看critic网络吗,其目的仅在于预测V值,所以它的估算值也要向更准确的下个阶段估算值来靠近,即TD-error越来越小。
再来看actor网络,TD-error在其中的作用仅是更新网络时的权重,其与动作的选择并无直接关系。前期TD-error较大,每次更新时,动作的概率都会进行相对较大的改动,随着不断地训练,动作的概率逐渐成熟,TD-error越来越小,所以每次更新时对动作概率的改动也随之减小。

总结

  1. 为了避免正数陷阱,希望Actor的更新权重有正有负。因此,把Q值减去他们的均值V。有:Q(s,a)-V(s)
  2. 为了避免需要预估V值和Q值,把Q和V统一;由于Q(s,a) = gamma * V(s') + r - V(s)。所以得到TD-error公式: TD-error = gamma * V(s') + r - V(s)
  3. TD-error就是Actor更新策略时候,带权重更新中的权重值
  4. 现在Critic不再需要预估Q,而是预估V。而根据马可洛夫链所学,知道TD-error就是Critic网络需要的loss,也就是说,Critic函数需要最小化TD-error。

算法

  1. 定义两个network:Actor 和 Critic
  2. 进行N次更新。
    1. 从状态s开始,执行动作a,得到奖励r,进入状态s’
    2. 记录的数据。
    3. 把输入到Critic,根据公式: TD-error = gamma * V(s’) + r - V(s) 求 TD-error,并缩小TD-error
    4. 把输入到Actor,计算策略分布。

AC算法.png

可以看出:在PG,智能体需要从头一直跑到尾,直到最终状态才开始进行学习。 在AC,智能体采用是每步更新的方式。

AC 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

PPO

PPO是基于AC框架的

正态分布

首先要想办法处理连续动作的输出问题。

  • 离散动作:离散动作就像一个个的按钮,按一个按钮就能智能体就做一个动作。
  • 连续动作:相当于按钮不但有开关的概念,而且还有力度大小的概念。就像开车,不但是前进后退转弯,并且要控制油门踩多深,刹车踩多少的,转弯时候转向转多少的问题。

在离散动作空间的问题中,最终输出的策略呈现出下面形式:
离散动作-策略分布.png

假设动作空间有只有action1 和 action2,有40%的概率选择action1 ,60%概率选择action2。即在此状态下的策略分布: pi = [0.4, 0.6]。
连续型概率分布示意图.png

在连续型,不再用数组表示,而是用函数表示。例如,策略分布函数 : P = (action)代表在策略下,选择某个action的概率P。

用神经网络预测输出的策略是一个固定的shape,而不是连续的。那又什么办法可以表示连续型的概率呢?可以假定策略分布函数服从一个概率分布,例如正态分布。

这样,只用两个参数就可以表示了。
正态分布.png

正态分布:

  • sigma:表示方差,当sigma越大,图像越扁平;sigma约小,图像越突出。而最大值所在的位置,就是中轴线。
  • mu:表示平均数,也就是整个正态分布的中轴线。mu的变化,表示整个图像向左右移动。

神经网络直接输出mu和sigma,就能获得整个策略的概率密度函数了。现在,当要按概率选择一个动作时,就只需要按照这个概率密度函数,随机抽取一个数,就能得到一个动作了。

AC的问题

上面的正态分布解决了AC处理连续状态空间的问题。但是,AC还有一个问题:AC产生的数据,只能进行1次更新,更新完就只能丢掉,等待下一次的数据。

  • 行为策略:行为策略是代理在与环境交互时采取行动的策略。它决定了代理在当前状态下选择每一个可能的行动的概率分布。不是当前策略,用于产出数据。

  • 目标策略:目标策略是代理在训练过程中试图优化的策略。它是代理最终想要学习到的最优策略,它通常被设计为最大化期望累积奖励。会更新的策略,是需要被优化的策略。

  • 在线策略:在线策略是指在与环境交互时实时地采取行动,并根据实时的反馈来更新策略。也就是说,代理在与环境互动时,采取行动并根据实际结果来调整策略。目标策略和行为策略是同一个策略,那么是在线策略。

    • 实时更新:在线策略会根据每次与环境交互的结果来进行即时更新。
    • 依赖实时反馈:在线策略依赖于实时的环境反馈来进行学习和调整。
  • 离线策略:离线策略是指在事先收集好的数据集上进行训练,而不需要实时地与环境交互。也就是说,代理使用事先收集的经验数据来训练策略,而不依赖于实时环境反馈。目标策略和行为策略不是同一个策略,那么是离线策略。

    • 离线数据:训练过程中不需要实时地与环境进行交互,可以使用先前收集的数据。
    • 无需环境互动:训练过程中不需要实时环境反馈。

例子:
如果在智能体和环境进行互动时产生的数据打上一个标记。标记这是第几版本的策略产生的数据,例如 1, 2… 10。现在智能体用的策略 10,需要更新到 11。如果算法只能用 10版本的产生的数据来更新,那么这个就是在线策略;如果算法允许用其他版本的数据来更新,那么就是离线策略。

例如PG,就是一个在线策略。因为PG用于产生数据的策略(行为策略),和需要更新的策略(目标策略)是一致。 而DQN则是一个离线策略。会让智能体在环境互动一定次数,获得数据。用这些数据优化策略后,继续跑新的数据。但老版本的数据仍然是可以用的。也就是说,产生数据的策略,和要更新的目标策略不是同一个策略。所以DQN是一个离线策略。

为什么PG和AC中的Actor更新策略,不能像DQN一样把数据存起来,只能用一次产生的数据?

看一个例子:
策略P和策略B.png

TD-error 可以理解为从状态S 到下一个状态动作的价值,所以动作1的 TD-error 大,所以希望选择动作1的概率大

假设,已知在同一个环境下,有两个动作可以选择。现在两个策略,分别是P和B: P: [0.5,0.5] B: [0.1,0.9]

现在按照两个策略,进行采样;也就是分别按照这两个策略,以S状态下出发,与环境进行10次互动。获得如图数据。那么,可以用B策略下获得的数据,更新P吗?

答案是不行,回顾PG算法,PG算法会按照TD-error作为权重,更新策略。权重越大,更新幅度越大;权重越小,更新幅度越小。

但可以从如下示意图看到,如果用行动策略B[0.1,0.9]产出的数据,对目标策略P进行更新,动作1会被更新1次,而动作2会更新9次。虽然动作1的TD-error比较大,但由于动作2更新的次数更多,最终动作2的概率会比动作1的要大。

策略P和策略B更新示意图.png

这不是期望看到的更新结果,因为动作1的TD-error比动作2要大,希望的是选择概率动作1的能更多。由此可以明白,在策略更新的时候不能使用其他策略产生的数据。

为什么DQN可以多次重复使用数据?

DQN更新的是Q值.png

两个角度:

  • 更新Q值,和策略无关。 在同一个动作出发,可能会通往不同的state,但其中的概率是状态转移概率决定的,与环境有关,而不是策略所决定的。所以产生的数据和策略并没有关系。
  • 在DQN的更新中是有”目标”的。 虽然目标比较飘忽,但每次更新,其实都是尽量向目标靠近。无论更新多少次,最终都会在目标附近徘徊。但PG算法,更新是不断远离原来的策略分布的,所以远离多少、远离的次数比例都必须把握好。

在Actor-Critic (AC) 方法中,Critic 网络更新的是状态值函数(Value Function)V,而不是动作值函数(Q函数)。

重要性采样技术

在PPO中,如果想使用策略B的数据来更新策略P,那就要把TD-error乘上一个重要性权重(importance weight)。

在这里IW = P(a)/ B(a)

就是 IW = 目标策略出现动作a的概率 / 行为策略出现a的概率

  • 目标策略:要更新的策略。
  • 行为策略:数据的策略。

这里是用策略B的数据来更新策略P,所以P是目标策略,B是行为策略。
重要性权重表格.png

现在即使用P策略: [0.5,0.5]进行更新,a1提升的概率也会比a2的更多。

PPO使用重要性采样技术把AC从在线策略变成离线策略。

N步更新

之前的TD叫做TD(0),而N步更新为TD(n)。可以看成TD(0)其实是TD(n)的一种特殊情况。

TD(N).png

如图,实际上只需要计算最后的V(s’),根据这个估算的V(s’), 反推经过的所有state的V值。这个其实和PG估算G的过程是一样的,只不过并不需要走到最后,而是中途截断,用网络估算。

V = R + gamma * V(s')

总结

实际上,P策略和B策略差异并不能太大,为了能处理这个问题,有两个做法,PPO1 和 PPO2 。主流是PPO2。

  1. 用AC来解决连续型控制问题。方法是输入mu和sigma,构造一个正态分布来表示策略;
  2. PPO延展了TD(0),变成TD(N)的N步更新;
  3. AC是一个在线算法,但为了增加AC的效率,希望把它变成一个离线策略,这样就可以多次使用数据了。为了解决这个问题,PPO使用了重要性采样。

PPO 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

DDPG

DDPG,全称是deep deterministic policy gradient,深度确定性策略梯度算法。

  • deep: 深度网络。
  • policy gradient: PG
  • deterministic: 其实DDPG也是解决连续控制型问题的的一个算法,不过和PPO不一样,PPO输出的是一个策略,也就是一个概率分布,而DDPG输出的直接是一个动作。

DDPG更接近DQN,是用一个actor去弥补DQN不能处理连续控制性问题的缺点。

回顾DQN

回顾DQN.png

从公式中也能看出,DQN不能用于连续控制问题原因,是因为maxQ(s’,a’)函数只能处理离散型的。这个就是DDPG中的Actor的功能: 用一个magic函数,直接替代maxQ(s’,a’)的功能。也就是说,期待输入状态s,magic函数返回动作action的取值,这个取值能够让q值最大。

理解DDPG

DDPG中Critic的功能,像是DQN的深度网络,用一张布去覆盖Qlearning中的Qtable。
理解DDPG1.png

当把某个state输入到DDPG的Actor中的时候,相当于在这块布上做沿着state所在的位置剪开,会看到这个边缘是一条曲线。
理解DDPG2.png

注意: 这条曲线很像概率分布,但要一定注意,这里并不是策略,也不是PPO和AC中的V值。是在某个状态state下,选择某个动作值的时候,能获得的Q值。

Actor的任务就是在寻找这个曲线的最高点,然后返回能获得这个最高点,也是最大Q值的动作。 所以,DDPG其实并不是PG,并没有做带权重的梯度更新。而是在梯度上升,在寻找最大值。 这也就解释了,为什么DDPG是一个离线策略,但可以多次更新却不用importance sampling。这是因为这个算法就是DQN,和策略没有直接的关系。

DDPG

DDPG1.png

整理下:

Critic

  1. Critic网络的作用是预估Q,虽然它还叫Critic,但和AC中的Critic不一样,这里预估的是Q不是V;
  2. 注意Critic的输入有两个:动作和状态,需要一起输入到Critic中;
  3. Critic网络的loss其还是和AC一样,用的是TD-error。

Actor

  1. 和AC不同,Actor输出的是一个动作;
  2. Actor的功能是,输出一个动作A,这个动作A输入到Critic后,能够获得最大的Q值。
  3. Actor的更新方式和AC不同,不是用带权重梯度更新,而是用梯度上升。

和DQN一样,DDPG更新的时候如果更新目标在不断变动,会造成更新困难。所以DDPG和DQN一样,用了固定网络(fix network)技术,就是先冻结住用来求target的网络。在更新之后,再把参数赋值到target网络。

所以实际做的时候使用了4个网络:actor, critic, Actor_target, cirtic_target。

DDPG2.png

目标网络只是用在求target的过程中。如果不是求target用的,就不用目标网络。

DDPG 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

TD3

Twin Delayed Deep Deterministic policy gradient algorithm,双延迟深度确定性策略梯度

TD3是对DDPG的优化,三个重要优化。

double network

DDPG起源于DQN,DQN有一个众所周知的问题就是Q值会被过高估计。这是因为用argmaxQ(s’)去代替V(s’),去评估Q(s)。当每一步都这样做的时候,很容易就会出现高估Q值的情况。

在TD3中,用了两套网络估算Q值,相对较小的那个作为更新的目标。这就是TD3的基本思路。

回顾DDPG:
DDPG2.png

通过Critic网络估算动作的A值。一个Critic的评估可能会较高。所以加一个。

TD3需要用到6个网络:
TD3.png

在目标网络中,估算出来的Q值会用min()函数求出较小值。以这个值作为更新的目标。这个目标会更新两个网络 Critic网络_1 和 Critic网络_2。 这两个网络是完全独立,他们只是都用同一个目标进行更新。 剩余的就和DDPG一样了。过一段时间,把学习好的网络赋值给目标网络。

Critic部分的学习

只有在计算Critic的更新目标时,才用target network。其中就包括了一个Policy network,用于计算A’;两个critic target Q network ,用于计算两个Q值:Q1(A’) 和Q2(A’)。

Q1(A’) 和Q2(A’) 取最小值 min(Q1,Q2) 将代替DDPG的 Q(a’) 计算更新目标,也就是说: target = min(Q1,Q2) * gamma + r

target 将会是 Q_network_1 和 Q_network_2 两个网络的更新目标。

TD-error_1 = gamma * min(Q1,Q2) + r - Q1
TD-error_2 = gamma * min(Q1,Q2) + r - Q2

既然更新目标是一样的,那么为什么还需要两个网络呢?

虽然更新目标一样,两个网络会越来越趋近与和实际q值相同。但由于网络参数的初始值不一样,会导致计算出来的值有所不同。所以可以有空间选择较小的值去估算q值,避免q值被高估。

Actor部分的学习

DDPG网络图像上就可以想象成一张布,覆盖在qtable上。当输入某个状态的时候,相当于这块布上的一个截面,能够看到在这个状态下的一条曲线。

而actor的任务,就是用梯度上升的方法,寻着这条线的最高点。

对于actor来说,其实并不在乎Q值是否会被高估,他的任务只是不断做梯度上升,寻找这条最大的Q值。随着更新的进行Q1和Q2两个网络,将会变得越来越像。所以用Q1还是Q2,还是两者都用,对于actor的问题不大。

actor延迟更新

actor更新的delay,也就是说相对于critic可以更新多次后,actor再进行更新。

为什么要这样做呢?

回到qnet拟合出来的那块”布”上。 qnet在学习过程中,的q值是不断变化的,也就是说这块布是不断变形的。所以要寻着最高点的任务有时候就挺难为的actor了。
理解DDPG1.png
理解DDPG2.png

可以想象,本来是最高点的,当actor好不容易去到最高点;q值更新了,这并不是最高点。这时候actor只能转头再继续寻找新的最高点。更坏的情况可能是actor被困在次高点,没有找到正确的最高点。

所以可以把Critic的更新频率,调的比Actor要高一点。让critic更加确定,actor再行动。

target网络噪声

TD3中,价值函数的更新目标每次都在action上加一个小扰动,这个操作就是target policy smoothing regularization

为什么要这样呢?

回到关于“布”的想象。 在DDPG中,计算target的时候,输入时s_和a_,获得q,也就是这块布上的一点A。通过估算target估算另外一点s,a,也就是布上的另外一点B的Q值。
Q'估算Q 1.png

在TD3中,计算target时候,输入s_到actor输出a后,给a加上噪音,让a在一定范围内随机。这又什么好处呢。

好处就是,当更新多次的时候,就相当于用A点附近的一小部分范围(准确来说是在s_这条线上的一定范围)的去估算B,这样可以让B点的估计更准确,更健壮。
Q'估计Q 2.png

这里注意三个地方:

  1. 在实验中,同样加上了了noise。这个时候的noise是为了更充分地开发整个游戏空间。
  2. 计算target的时候,actor加上noise,是为了预估更准确,网络更有健壮性。
  3. 更新actor的时候,不需要加上noise,这里是希望actor能够寻着最大值。加上noise并没有任何意义。

TD3 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

这里的TD3仅针对自己的实验平台实现了类似于MATD3的效果,但是实际上,没有明确的MATD3。后面再考虑在gym上实现以加深理解。

A3C

强化学习的一个难点,智能体的用于学习的数据,需要智能体和环境不断进行交互。和一般有监督学习的先比,数据数量太少了。

在算法没有更大进步的时候,有人就想出,如果有多个智能体和环境进行互动,那么每个智能体都能产出数据,这些数据就可以一起给模型进行学习了。

由此诞生了A3C。

A3C.png

注意几点:

  1. 在A3C中,worker不仅要和环境互动,产生数据,而且要自己从这些数据里面学习到“心得”。这里的所谓新的,其实就是计算出来的梯度;需要强调的是,worker向全局网络汇总的是梯度,而不是自己探索出来的数据。

    在这一点上,很容易和DPPO混淆。DPPO和A3C,也是一个分布式的架构,但work自己并不学习,而是提交数据让全局网络学习。

  2. worker向全局网络汇总梯度之后,并应用在全局网络的参数后,全局网络会把当前学习到的最新版本的参数,直接给worker。worker按照最新的网络继续跟环境做互动。互动后,再把梯度提交,获取新的参数…… 如此循环。

A3C1.png

A3C 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

DPPO

DPPO和A3C的思路其实是一致的,希望用多个智能体同时和环境互动,并对全局的PPO网络进行更新。

在A3C,需要跑数据并且计算好梯度,再更新全局网络。这是因为AC是一个在线的算法,所以在更新的时候,产生数据的策略和更新的策略需要时同一个网络。所以不能把worker产出的数据,直接给全局网络计算梯度用。

但PPO解决了离线更新策略的问题,所以DPPO的工人只需要提供数据给全局网络,由全局网络从数据中直接学习。

DPPO 实现

TODO: 这里所有算法的代码仅仅是看了一遍,还没有自己手写一遍,等这周联合组会后再说。

写在最后

到这里,传统强化学习的总结就结束了,后面由于我的科研方向是多智能体强化学习,会更新关于多智能体强化学习的算法。