DRL解决的是从过去经验中学习有用知识,并用于后续决策的问题。比起视觉方面的检测、识别等,决策是一个更高层的行为,所以对环境要求更为严苛,导致DRL十分依赖过拟合,并且泛化能力非常差(唯一被允许在训练集上测试的算法的称号不是盖的)。此外,由于训练过程中缺乏直接监督的信号,DRL对数据量的要求也非常巨大。
所以在DRL训练中,Value函数去过拟合环境转移特性与reward函数,而Policy函数去过拟合Value函数。所以当环境特性发生改变时,Value和Policy就会失效,DRL自然也就不具备泛化能力。
DRL有所为,有所不为。知道算法不能做什么(能力边界)与知道算法能做什么同样重要。
场景固定是指决定系统动态演化趋势的主要因素保持恒定。即MDP(p(s’ | s, a))在训练过程中是否变化。我们要保证训练环境尽可能与测试环境相同
任务要达到何种效果清晰具体,最好可以量化。目标越明确,设计优质的reward函数就越容易,从而训练得到更接近预期的policy。
我们知道DRL目前最成功的领域是视频游戏,它在运行过程中收集数据是十分方便的,所以DRL才能大施拳脚。而对于牵涉导硬件的应用,DRL算法就显得非常不友好。
们用DRL的目的无非是看中了其处理复杂场景的能力,人类看不透,DRL来凑。如果任务太简单,依靠规则和启发式就能解决问题了,相当于拿到了“解析解”,还用神经网络拟合个什么劲儿。
自由度高指的是选择空间大、限制少,通过大量探索总能拟合出不错的value函数指导policy做选择。自由度越高,DRL优势越明显,自由度越低,越有利于规则。因此在决定用DRL之前,一定要认真评估任务场景是否有足够的优化空间,千万不要拎着锤子找钉子,否则即使训出了policy,性能也不如传统算法,白忙活一场。
目前DRL巨人最厚实的肩膀大致是TD3 PPO SAC,其他算法多是在它们的基础上添砖加瓦。对于一个特定的任务,我们可以分别测试三种算法的效果,并从中择优选取。
这里贴两篇文章作为参考:
https://zhuanlan.zhihu.com/p/342919579
https://zhuanlan.zhihu.com/p/96010395
在将DRL应用于实际项目时,可能最轻松愉快的部分就是动作空间定义了。因为agent的控制方式往往早就定死了,留给我们发挥的空间很小。
如果可以设计动作空间,算法对动作空间有以下三个要求:
动作空间首先要提供实现预期目标的可能性,避免在任务解空间中出现无法触及的“状态盲区”,尤其是要保证高性能区域的充分可达性。它要求动作空间具备功能完备性与时效完备性。
动作空间应该尽可能简单高效,从而有效降低训练难度和提升算法性能。一方面,可以将连续动作空间化整为零,在满足基本控制精度的前提下将其转化为离散动作空间,这样可以显著压缩解空间维度,提高探索效率;另一方面,可以根据实际情况,将一些基本动作进行有机组合构成宏动作,直接学习这些动作可能难度很大,但如果能将这些技巧直接作为常备选项,由算法学习如何合理运用它们,将起到事半功倍的效果。
在DRL应用中并不是所有action在任何state下都有效,比如AlphaGo就不能在棋盘上已经被占据的位置落子,自动驾驶车辆遇到行人时绝对不能撞上去。对于特定状态下规则不允许出现的action或者引发严重后果的action,我们应该直接屏蔽掉。DRL与其他AI算法一样,都属于统计学范畴,我们在理解policy输出时也应该使用概率思维,即使agent学会在99.99%的情况下输出合法action,但仍存在0.01%的可能性输出非法action,与其寄希望于DRL完全学会遵守规则,不如加一层“硬保险”来得靠谱。
状态信息是agent制定决策和评估其长期收益的依据,而状态设计的好坏直接决定了DRL算法能否收敛、收敛速度以及最终性能,兹事体大,不可不察。增加一个优秀的新状态信息所带来的性能提升明显高于其他方面的工作(如调参),性价比非常高,因此状态空间的优化工作几乎贯彻项目始终。
直接进行端到端的学习,让DNN挑选有用的状态信息并学习与决策之间的关系当然也可以,但强化学习本来数据利用率就低,这样会使学习效率更低。而且一些不相关的干扰信息还会起到反作用,影响训练效果。因此,要想尽量提高算法的学习效率,需要人为地筛选出一些好的状态信息,可以是raw infomation,也可以是经过二次加工的信息,帮助DNN更轻松准确地建立起决策相关性。
状态空间设计过程可以分为以下步骤:
任务分析是状态设计的灵魂,好的状态信息建立在对任务逻辑的深入理解之上。我们需要对达到最终目标的过程进行分解,研究该目标的本质为何,有哪些重要环节,每个环节有什么影响因素,每个因素又由哪些信息体现。
在所有可用信息中找出与任务目标、子目标有关的那些。神经网络的作用是将原始状态信息经过层层非线性提炼后转化为与长期收益高度关联的形式,并进一步指导生成action决策。理想情况下,状态空间应该完全由筛选出的相关信息组成。某个状态信息所代表的事件在越短时间内得到反馈,神经网络就越容易学会如何对其进行加工并建立起决策相关性。按照这个反馈时间的长短,我们还可以粗略地将这些相关信息分为直接相关信息和间接相关信息。
与某个reward奖励项或惩罚项即时联动的信息。比如为了更有效地避免小车之间发生碰撞,回报函数里设计了“最近小车距离反比”惩罚项-α * max(D - dmin) ,其中D是靠近惩罚阈值,当agent与周围最近小车距离dmin小于D时,即开始反比惩罚,靠得越近罚得越多。这里的dmin相对于该惩罚项就属于直接相关信息,agent在每一步都能收到与dmin线性相关的反馈,很容易建立起决策相关性。
直接相关信息不仅对DRL算法学习很友好,在有对口reward奖励/惩罚项的前提下,对算法工作者来说也更容易设计。事实上,DRL的状态空间设计往往和reward设计同时进行,为了达到某个目的需要增加一项奖励/惩罚,并相应增加一个或多个直接相关状态信息,帮助模型识别现象与反馈之间的因果关系,这一设计理念很直观也很有效。
reward中没有即时联动项的状态信息,其所代表的事件需要一段时间后才得到反馈。相对于直接相关信息,DRL利用它们建立决策相关性的难度更高,学习效率更差。
间接相关信息通过某些手段可以转化为直接相关信息,从而提高DRL的学习效率。最简单的方法是对任务目标做更详细的credit assignment并增加相应的reward奖励/惩罚项,如果某状态信息恰好与之即时联动,相应状态信息就成为了直接相关信息。
无论是直接相关还是间接相关,原始信息都要经过神经网络的提炼才能转化为action输出,提炼难度与学习效率和最终性能呈反向相关。如果我们提前对原始信息做些二次加工,人为提炼出与学习目标更相关的因素,相当于替神经网络干了一部分活儿,虽然不那么elegant,但往往能收到奇效。我们在状态空间上多下一点功夫,DRL学习的难度就降低一点。在资源有限的情况下这很有可能就是训不出来和训得出来的区别,也有可能是性能不达标与性能达标的区别。
我们必须合理设计状态信息使其对环境主要因素的改变有最起码的兼容性,我把它称之为统一性考虑。具体地,这里的统一性又包含形式统一和逻辑统一。
为了保证输入向量长度恒定,我们需要找到一种统一形式把不同信息填到对应的位置。比如小车周围装了一圈测距雷达,按固定顺序输出一维距离向量,那么无论把小车放到什么地方,这些信息所代表的含义也不会变。
状态空间只做到外在形式统一是不够的。比如我们把小车当前位置(x0, y0)和终点位置坐标(x1, y1)作为状态信息同时输入网络,按照DRL的过拟合天性,神经网络最终会记住这张地图每个坐标处的特征以及在这里通行的最佳路线,policy在这幅地图里测试性能会很高,但换幅地图就完全不能用了。通常情况下,我们并不希望DRL用这种方式获得高性能,而是希望它能学会应对不同地形的通用知识,即使换张地图也至少能达到“勉强能用”的地步,再通过在新地图中finetune即可快速具备实用价值。因此,更合理的方式是将两个绝对坐标合并为一个相对坐标(x1 - x0, y1 - y0),即终点位置在小车坐标系中的坐标,这样就可以使policy与具体地图“脱钩”,从而学习到更加通用的导航知识。可见,要想让网络学到我们希望它学到的知识,前提是输入正确形式的状态信息。
通过实验验证其是否达到预期效果。验证方法可以分为三类:模仿学习验证,直接验证和缺省验证。
如果项目已经有一个较好的baseline,可以搭建一个policy网络,专门模仿该baseline在各种状态下的action,如果状态中包含了正确决策所需的相关信息,那么得到的policy性能就会越接近baseline。考虑到有监督学习的高效性,这是验证状态信息有效性的一种较快方式,尤其适用于项目初期一片懵懂的时候。
如果没有这样的baseline,那就只能用直接验证了,即用DRL训练一个policy并验证其效果。为了提升效率,也可以只比较训练中途(固定步数、固定样本量)的性能,因为很多时候好状态和差状态的won-lost关系在较早的时候就确定了,当然这必须建立在对特定任务和特定算法训练过程较为熟悉的基础上,在DRL训练中,早期的性能优势无法保持到最后的情形也时有发生。另外可以优先选择收敛速度较快的DRL算法(先不考虑绝对性能),从而快速验证新状态相对旧状态的改进效果。
当我们已经训练得到一个不错的policy时,可以用缺省的方式验证每个状态信息的作用大小,即正常输入其他信息,而将目标信息取合理区间内的定值(如区间中点),测试性能损失的百分比。损失越大说明该状态信息越关键,反之则说明作用越边缘化,有时候甚至会发现性能不降反升,说明该信息有干扰作用,还是去掉的好。缺省验证的意义在于,剔除那些无用或起反作用的状态,为进一步优化关键状态和弱作用状态提供指导。
回报函数(reward)设计在DRL应用中是极其重要的一环,通过将任务目标具体化和数值化,reward就如同一种特殊语言,实现了目标与算法之间的沟通,算法工作者在这里面承担了翻译的角色,翻译的好坏体现了其对任务逻辑的理解深度,决定了agent最终是否能学到期望的技能,并直接影响算法的收敛速度和最终性能。
当我们拿到一个任务目标,往往能够简单分析就能找出与该目标紧密联系的主线事件。这就是我们的第一个reward项,也就是主线reward,一般是正奖励,当主线事件发生时反馈给agent。
理论上,只要有主线reward就可以进行训练了。在简单任务中,agent只靠随机地探索就可能可以遇到主线事件,并进一步更新policy逐渐提升得到奖励的概率,直到收敛。但是当问题稍微复杂一点,只靠随机探索几乎不可能遇到主线事件时,算法就会收敛很慢,甚至难以收敛,因为中间缺乏有效信号来指导agent向正确的方向前进。这就是稀疏回报问题(sparse reward problem),它对数据效率低下的RL算法而言,学习难度是很大的,因为大部分状态信息对主线reward来说都是间接相关信息。
我们接下来就要将原始任务目标进一步分解成子目标,并分别给予合理的奖励或惩罚,从而达到引导agent趋利避害提高主线事件发生概率的目的。学术界一般称该过程为credit assignment,说的是某个子目标在达成总目标的过程中起了多大作用,是正向作用还是负向作用。这些子目标对应的reward可以称之为辅助reward,它们使reward不再稀疏。通常情况下,为了保证主线奖励的核心地位和吸引力,各种辅助reward的绝对值都设得相对较小,以免喧宾夺主。
agent在环境中探索时需要获得反馈,即刚刚的决策好不好,反馈越及时学得越快,理想情况是每一步都有反馈。还以小车导航到终点的应用为例,除了抵达终点+10分,如果每次靠近终点也+1分,那么小车在抵达终点之前就学会主动靠近终点,这样探索到抵达终点的概率也大大提高了,DRL算法收敛速度自然会加快。
除了抵达终点,小车还要避免与障碍物和其他小车发生碰撞,我们还要对碰撞事件做出惩罚。为了使agent更好地学会避免碰撞,我们除了对已经发生的碰撞事件给予惩罚,还可以再增加一个预防式的靠近惩罚,并利用状态空间里的直接相关信息——与最近邻居的距离,提高算法学习效率。
辅助reward的设计建立在对任务逻辑的深刻分析和理解之上,有很多细节都会对最终目标的实现产生正向或负向的影响,值得我们深入挖掘。此外,由于将最终目标分解成了子目标,在设计对应辅助reward时往往很容易找到与之即时联动的直接相关状态信息,或者相关性较强的间接相关信息。事实上,我们每设计一个reward项,就应该回过头去检查状态空间中是否包含了直接或间接相关信息,已经包含的信息是否足够直接高效,有没有改进的空间。
应该避免reward项的不合理取值及多项reward之间的不合理相对大小,导致agent学到异常行为。因为不合理reward造成的常见异常行为主要包括三种类型:鲁莽、贪婪和胆怯。
鲁莽行为指的是reward中漏掉了针对某个不希望出现的事件的惩罚项或者惩罚力度太小,被其他reward项盖过,导致agent无法学到主动规避该事件或者权衡利弊后仍然选择接受该事件的惩罚以换取更大收益。在小车导航的例子中,碰撞惩罚相对于远离惩罚过小,小车可能为了尽快到达终点宁愿撞到其他小车上也不愿意绕远。
靠近终点奖励使reward变稠密了,但这样做就够了吗?我们说过RL追求的是长期收益,事实上对小车来说收益最高的选择不是尽快抵达终点,而是不断重复“靠近-远离”的动作,如此一点点地累加,收益远超过抵达终点的一锤子买卖!很显然,agent钻了reward设计漏洞的空子,变得不思进取,贪得无厌。为了防止这种情况发生,我们还要对原地不动或远离终点的行为进行惩罚,而且相对于靠近奖励,扣分太少也不行,否则agent仍然会发现钻空子是划算的。一劳永逸的办法是,将靠近终点的正向奖励改成微小惩罚,绝对值小于原地不动或远离惩罚,这样做的好处是不仅不给agent钻空子的机会,而且还能督促小车尽快向终点行驶。
实际上,除了主线reward应该提供正向奖励以外,其他辅助reward最好都设置为惩罚项。除非某个子目标与主线事件之间存在强关联,而且该子目标的达成是一次性的或者数量可控,否则不应轻易设置额外奖励项,因为这样很容易诱导agent学习到短视的贪婪策略,只捡芝麻,不要西瓜。
如果惩罚项很多且绝对值相对于主线reward太大,那么agent在探索过程中会收到大量负反馈,从而变得畏首畏尾,学习到各种意想不到的“绥靖”策略。比如在小车到终点的例子中,假如碰撞惩罚和转弯惩罚绝对值过大,agent有可能宁愿选择原地不动,这是因为训练初期policy很差,需要经历大量转弯和碰撞后才可能出现主线事件(到达终点),而收到的负反馈完全湮没了主线奖励,因此在agent看来原地不动的长期累计收益暂时不比到终点差,尽管只是暂时的,但agent很可能陷在这个局部最优里出不来了。
在上述情况下,你会发现只需要将惩罚项绝对值减小,突出主线奖励的影响,其他什么也不用干,DRL模型就能顺利收敛了。当然,还可以适当降低折扣因子,让agent变成“近视眼”,更多关注眼前利益,忽略长期的负收益期望(靠后的负反馈都被折扣掉了),只要agent“迈开腿”出来探索,就有更大可能遇到主线事件,并在主线reward的奖励下学习到目标技能。
在原有reward基础上增加一项shaping reward,该项代表某种势能函数,与最终目标的差距决定了势能大小。这样做还可以让RL算法收敛得更快一些。
reward设计的原则是:尽可能稠密(最好每步都有反馈),能够反映任务目标/子目标逻辑,与状态空间相呼应,控制好各项取值和相对大小,避免异常行为,适时采用reward shaping。
如果条件允许,开始训练前最好先可视化一个随机环境,观察是否会出现你希望的状态(即上一篇里的主线事件)。如果靠随机选择action都能以一定概率探索到目标状态,那说明该任务难度比较低,心里就可以更有底;如果从来不会出现目标状态,说明该任务难度较高,需要在状态空间和reward函数设计时特别下功夫,从而更好地引导agent向目标状态前进。
还可以实时打印出state和reward,看看它们是否在合理范围内取值,是否存在幅值过大的情况,如果是则需要增加必要的归一化操作。事实上,可以无条件进行状态空间归一化和reward rescale & clipping,实践证明这两个操作无论在收敛速度还是最终性能上都会带来明显提升。
reward rescale & clipping,该操作尤其适合基于episode的A3C/A2C/PPO算法,参考形式为r=clip(r/(std(Return)+ eps ),-10,10),其中Return = ∑γt * rt ,是一段episode内reward的折扣累加和,也就是V网络拟合的对象,而V网络输出又为policy优化提供参考,使用该值的统计方差对reward进行rescale,可以反过来有效降低Return的variance,有助于V网络和policy网络进行更加无偏地学习。训练过程中通常采用Return的running std来rescale当前reward。最外层的clip操作可以滤除那些绝对值过大的reward,作用类似。
折扣因子通常以符号γ表示,在强化学习中用来调节近远期影响,即agent做决策时考虑多长远,取值范围(0,1]。γ越大agent往前考虑的步数越多,但训练难度也越高;γ越小agent越注重眼前利益,训练难度也越小。我们都希望agent能“深谋远虑”,但过高的折扣因子容易导致算法收敛困难。还以小车导航为例,由于只有到达终点时才有奖励,相比而言惩罚项则多很多,在训练初始阶段负反馈远多于正反馈,一个很高的折扣因子(如0.999)容易使agent过分忌惮前方的“荆棘丛生”,而宁愿待在原地不动;相对而言,一个较低的折扣因子(如0.9)则使agent更加敢于探索环境从而获取抵达终点的成功经验;而一个过低的折扣因子(如0.4),使得稍远一点的反馈都被淹没了,除非离终点很近,agent在大多数情况下根本看不到“光明的未来”,更谈不上为了抵达终点而努力了。
折扣因子的取值原则是,在算法能够收敛的前提下尽可能大。在实践中,有个经验公式1/(1-γ),可以用来估计agent做决策时往前考虑的步数。根据对特定任务的分析,合理选择γ值,避免“近视”和“远视”。比如可以根据观察或统计agent到达终点所需的步数分布,选择合适的步数使得agent在该步数内的探索下有一定概率到达终点(正样本),注意这个概率越高训练难度就越小,然后利用经验公式把该步数换算成γ即可。
DRL算法中的网络结构也属于超参数,然而DRL绝不应该片面追求网络的复杂化,否则你会发现训练根本无法收敛。对于网络结构的选择,DRL有自己的规矩——契合状态,够用就好。前者针对网络类型,后者针对网络深度。
网络类型的选择主要取决于状态空间设计,如果状态信息是向量式的,即一组拉成一维的标量,比如位置、角度、速度等,那就适合采用全连接(MLP)网络;如果状态信息是imagelike的,比如图像,或者其他以二维形式重组的信息,就适合采用卷积神经网络(CNN)。实际应用中往往同时包含这两种状态信息,因此网络类型也可以既有CNN也有MLP,处理完各自对应的输入信息后,在高层通过concat操作汇集在一起,再通过若干层全连接,最后输出action或Q/V值。
对于on-policy算法,episode形式的数据天然适合采用RNN来挖掘更多时序信息,但同时也会显著提高训练难度,用与不用取决于决策对时序相关性的依赖程度。换句话说,如果之前的经验对当前决策很有参考意义(比如Dota)就适合用RNN,反之仅依靠即时信息做应激式决策就足以应付就没必要用RNN。实践中经常采取折中方案,将最近几个step的原始状态信息叠加到一起作为当前时刻的实际状态信息输入policy,既可以挖掘一定范围内的时序信息,又避免增加训练难度。
虽然深层网络的表征能力更强,但训练难度非常高,更适合有监督训练。DRL算法由于数据效率低下又缺乏直接监督信号,并不擅长以end-to-end的方式训练过深的网络,如果还同时采用了RNN结构,那就是相当不擅长了。
当然,如果任务逻辑和状态信息确实非常复杂,浅层网络不足以提供所需的特征提取和加工能力,那么可以考虑适当加深网络,但仍应以够用为准则,不可矫枉过正。
也是贴两个网站作为参考:
https://zhuanlan.zhihu.com/p/345353294
Value网络越精确,由其计算得到的advantage越有意义,也就越有利于policy的优化。
注意精度和loss都是相对概念,与reward函数中各项的绝对值息息相关。一般说来,在DRL中对reward进行等比例缩放不会改变policy的最终特性,即(+10,-2,-1,-0.5)与(+100,-20,-10,-5)的作用是一样的,但体现在value loss上就差了10倍。对拟合精度更可靠的评估标准是explained variance,计算公式是1 - Var(return - value) / Var(return) ,取值区间(-∞, 1],该值越接近1说明拟合精度越高。
假如policy输出10维categorical分布,其entropy有两种极端情况:(1) 完全随机,每个维度概率均为0.1,此时entropy最大等于10*[-0.1*log(0.1)]=2.3;(2) 完全确定,其中一维为1.0其余都是0.0,此时entropy最小等于0。整个训练过程,entropy从2.3开始逐渐下降,当训练收敛后,entropy应该稳定在较低水平。如果太高则说明policy对决策信心不足,如果不是任务本身太复杂那就是entropy系数过大造成的,应该适当降低该系数增加exploitation的力度,很有可能继续提升模型性能。当然,entropy很少能降到0,除非是极其简单的任务。