深度强化学习落地方法论(3)—— 算法选择篇

前言

2021年2月15日更新:

考虑到这篇文章写作时间较早,这里统一更新算法选择方面的建议:对于连续控制任务,推荐SAC、TD3和PPO,三种算法都值得试一试并从中择优;对于离散控制任务,推荐SAC-Discrete(即离散版SAC)和PPO。至于TD3和SAC的详细介绍,网上资料很多,暂时就不写了,有机会再说。


虽然每年RL方向的paper满天飞,但真正具有普遍实用价值的突破性工作实在不多,大多数还是在经典框架基础上的改进和扩展。DRL常规武器库里的存货主要还是老三样:DQN,DDPG和A3C,它们是深度学习时代最成熟、最能体现智慧结晶的三个DRL框架,你可以在GitHub上找到无数相关代码,有OpenAI,DeepMind和Nvidia这些大公司的,也有个人爱好者的。对于DRL初学者,它们是最佳的敲门砖;对于算法研究者,它们是最厚实的“巨人肩膀”;对于算法工程师,它们是最顺手的试金石。你完全可以把三个框架都放到项目模拟器上跑一跑,看哪个效果好就用哪个。当然,这三个算法框架都有各自的特点和适用domain,结合对项目的分析,是可以提前评估最合适的算法的。

强化学习——探索和利用的平衡游戏

总体来说,强化学习是一个探索(Exploration)和利用(Exploitation)的平衡游戏,前者使agent充分遍历环境中的各种可能性,从而有机会找到最优解;后者利用学到的经验指导agent做出更合理的选择。两者之间可以说是相爱相杀的关系:

1. 充分的探索才能带来有效的利用,从而使RL走在正确的道路上。对于那些难度特别高的任务,改进探索策略是性价比最高的手段,比如AlphaGo使用蒙特卡洛决策树征服了围棋,Go-Explore利用状态回访打爆了Montezuma's Revenge

2. 充分的利用才能探索到更好的状态,agent往往需要掌握基本技能,才能解锁更高级的技能。就好像小孩先要学会站起来,才能学会走,然后才能学会跑。这种从易到难、循序渐进的思想在RL中也很受用,著名的Curriculum Learning就是由此而来

3. 过量的探索阻碍及时的利用。如果随机探索噪声强度过高,已经学到的知识会被噪声淹没,而无法指导agent解锁更好的状态,导致RL模型的性能停滞不前

4. 机械的利用误导探索的方向。如果刚刚学到一点知识就无条件利用,agent有可能被带偏,从而陷入局部最优,在错误道路上越走越远,在训练早期就扼杀了最好的可能性

强化学习的训练过程其实就是从以探索为主到以利用为主的过渡过程,训练早期通过广泛试错找准一个方向,然后沿着该方向一路试探下去直到达到最优。请牢牢记住这“两点一线”,因为这是所有RL算法的主要内容,任何RL算法都能以此为切入点进行解构,有助于不断加深对算法的理解。接下来我就结合实际经验,谈谈对三个主流DRL框架的一些浅见。

DQN


DQN是借助AlphaGo最早成名的深度强化学习算法,其核心思想是利用Bellman公式的bootstrap特性,不断迭代优化一个Q(s,a)函数,并据此在各种状态下选择action。其中Q(s,a)函数拟合的是一对状态-动作的长期收益评估,该算法没有显式的policy。DQN探索和利用的平衡靠的是一种称为ε-greedy的策略,针对最新的Q(s,a)函数和当前的输入状态s,agent做决策时以概率ε随机选择action,而以1-ε的概率选择使Q(s,a)最大的action,随着ε从大到小变化,DQN也相应地从“强探索弱利用”过渡到“弱探索强利用”。

DQN的原理使其天然地适合离散动作空间,也就是action可以穷举,比如走迷宫的agent只允许前后左右4个动作,下围棋的AlphaGo只允许19*19=361个落子位置(实际还要排除已经落子的网格点)。这是一个重要的特征,如果你手上是一个连续控制任务,action在某区间内有无数种可能,那就不适合用DQN了。当然,你也可以选择把区间离散化,这样就可以应用DQN了,也曾有paper报告这样做在某些任务中可以比连续控制取得更好的性能。

DQN属于off-policy方法,所谓off-policy是指用于计算梯度的数据不一定是用当前policy采集的。DQN使用一个叫replay buffer的FIFO结构,用于存储transition:(s,a,s',r),每次随机从buffer中拿出一个batch用于梯度计算和参数更新。Replay buffer是稳定DQN训练的重要措施,对历史数据的重复使用也提高了其数据利用率,对于那些数据比较“贵”的任务,比如Google的抓取应用(见需求分析篇),这一点非常重要,事实上Google除了replay buffer,还专门搞了个数据库,把之前存储的另一个抓取应用采集的数据拿出来做预训练,精打细算到了极致,真是比你有钱,还比你节约~

DQN的缺点挺多,有些是RL的通病,比如对超参数敏感,我在训练篇会详细介绍;另外利用Bellman公式的bootstrap特性更新Q值的方式自带bias,外加计算目标Q值时使用同一个网络评估和选择动作(见下式),DQN容易被overestimation问题困扰,导致训练稳定性较差,近些年学术界有不少工作是围绕这一点做出改进(比如Double DQN)。此外,DQN还有off-policy方法的通病,对历史数据的重复利用虽然可以提高数据效率,但有个前提条件是环境model不能发生变化,single agent任务较易满足这个条件,但multiagent场景就未必了,对任意agent而言,其他agent也是环境的一部分,而他们的学习进化会改变这个环境,从而使历史数据失效,这就是MARL领域著名的环境不稳定问题,除非replay buffer内的数据更新足够快,否则off-policy方法的性能往往不如on-policy方法。


DQN的Q网络更新公式

DDPG


针对DQN无法处理连续控制任务的缺点,DDPG在DQN的基础上做了改进,引入了一个输出连续action的显式policy,与Q函数组成Actor-Critic结构,更新policy网络的梯度完全来自于Q网络,目标是最大化当前的Q函数。Q函数的更新与DQN类似,只是计算s'状态下目标值时放弃了max操作,而采用当前policy网络的输出π(a|s')。DDPG名字里的第一个D是Deterministic的缩写,意思是确定性的,这是有意与正宗Actor-Critic方法(如A2C/A3C等)区分开,后者policy输出的是action的概率分布,而DDPG输出的就是确定性的action。正因为如此,DDPG采用了独特的探索方式,即在action输出直接加上一个noise,该noise的强弱决定了探索力度,本质上相当于以当前action为中心形成了一个概率分布,每次更新都使policy向该分布中更好的方向演化,直到action达到了最优,此时对应分布内其他方向都是更差的方向,policy输出也就稳定在最优action附近了,从而实现了探索和利用的平衡。


能用于连续控制任务自然是招人喜欢的,毕竟实际控制任务的变量往往都是连续取值的,比如角度、位移、速度、加速度、电流、电压等等。学者们把DDPG用在MuJoCo上,解决了很多连续domain的任务,后来也有人把它用到真实的软体章鱼机器人上,用两只触角实现了向前运动。然而,在连续区间上找到最优的确定性action输出本身是一件非常困难的事,导致DDPG在action维度较高的复杂任务中表现不佳,比如KUKA iiwa机器人有7个自由度,使得探索空间一下大了很多,训练难度陡升。同时policy网络的梯度完全来自于Q网络,Q函数的拟合误差都直接传导给了policy,致使DDPG的训练稳定性也不足。在Google的抓取应用中,干脆抛弃了独立policy网络,做决策时随机在区间里取16个点输入Q网络,然后选择Q值最大的那个作为action,实验结果表明如此粗糙的做法却大大提升了训练稳定性,且性能显著优于DDPG,有点尴尬……

总结一下,如果我们面对的问题是连续控制任务,action维度又不高,可以尝试用DDPG解决,但也不要忘了离散化动作空间并用DQN训练得到更高性能的可能性。如果action维度很高,那还是别用DDPG的好。如果数据很“贵”不得不用off-policy方法的话,那就向Google学习,拿掉policy网络,直接用Q网络+启发式搜索选择action。如果数据廉价又追求高性能,我推荐使用PPO框架——个人比较偏爱的一种框架。

2021年2月15日更新:

上述建议已经过时了,对于连续控制任务,推荐优先使用SAC,后者在训练稳定性、收敛速度和性能方面都是目前的SOTA,作为off-policy算法数据效率也相对较高,SAC作者尝试直接用实体机器人采样并在几个小时内成功收敛

A3C→A2C→PPO


在成熟版SAC出现以前,PPO曾带给我最多的成功经验。PPO从A3C的同步版本A2C的基础上演化而来。

A3C作为Actor-Critic算法,核心是REINFORCE梯度策略方法。其policy输出的不是action,而是关于action的概率分布,因此梯度无法直接从Critic(又称为V网络)流到policy网络,只能用在线样本统计出一个近似梯度。原始REINFORCE梯度形式如▽V(s) logπ(a|s),直观解释就是使状态s下返回高V值的action出现概率更大。缺点是V值绝对值不可控(与reward等因素有关),variance很大,造成训练不稳定。A3C将梯度改成▽A(s,a) logπ(a|s),A(s,a)是在线episode计算出的一对s,a的Value值与当前V网络估计值之差,并经过normalization操作,简单理解就是把log前的部分做了一个居中+归一化,variance降低,训练稳定性显著提升,这里的A(s,a)称为a在s下的advantage,是A3C名字里的第二个'A'。既然policy输出的是action概率分布,那么探索就很容易实现——按照这个分布采样即可,训练初期分布variance比较大,探索力度强,随着policy不断改善,分布variance越来越小,代表policy对所选action越来越自信,这就实现了对经验的利用。

A3C能够充分利用多核资源,在不同CPU上并行运行不同的环境种子,显著提升了训练稳定性、收敛速度以及最终性能。A3C支持多种action概率分布,如果action空间是DQN那样的离散集合,可以用Categorical分布;如果是像DDPG那样的多维连续分布,可以用Multivariate Gaussian分布,此外A3C还支持伯努利分布,如果action的每一维都是非此即彼的二值选项,或者one-hot向量太长想改用二进制表示,那就是它了。可见,A3C在通用性上是显著优于DQN和DDPG的,几乎所有任务都能拿A3C跑一跑。此外,A3C作为on-policy方法,每次更新policy的梯度都由当前policy采集的样本计算,这使得A3C在MARL任务里对环境不稳定性的抵抗能力比DQN和DDPG更强。

A3C将多核环境中计算的梯度进行异步(Asynchronous)聚合,然后统一更新主网络并将新参数分发到各环境。这种方式的运行效率较高,但计算的梯度可能与当前主网络参数在时间上“错位”,有可能损害算法性能。因此,学术界更多地沿用了A3C的同步梯度聚合版本A2C。PPO就是在A2C的基础上利用clip操作进一步限制了每次梯度更新的幅度,从而显著提升了训练稳定性。和很多paper的实验结果一致,我在实际应用中发现PPO在连续控制任务里性能显著优于DDPG,对超参数的敏感度也比DDPG低,因此训练起来更加得心应手。因此,我推荐大家在解决连续任务时首选PPO,DDPG的优先级往后放就是了。对于具有离散动作空间的任务也值得用A3C跑一下,跟DQN比一比。

2021年2月15日更新:考虑到这篇文章写作时间较早,这里统一更新算法选择方面的建议:对于连续控制任务,推荐SAC、TD3和PPO,三种算法都值得试一试并从中择优;对于离散控制任务,推荐SAC-Discrete(即离散版SAC)和PPO。至于TD3和SAC的详细介绍,网上资料很多,暂时就不写了,有机会再说。

其他算法

以上三个DRL框架是基础,大多数情况下都至少能得到一个“能用”的policy。然而,也不应奢望它们能解决一切问题。DRL领域是个大坑,里边有太多需要解决的问题和值得挖掘的方向,比如:高难度探索,稀疏reward,数据效率,训练稳定性,快速适应新环境等等,类似MARL这样的子领域还有自己特有的问题,如环境不稳定性,scalability等等。算法工作者一定要保持开放的态度,及时跟踪学术界的新趋势新方法。

每当算法性能遇到瓶颈,首先要沉下心来分析关键制约因素在哪里,如果是上述这些普遍意义上的问题造成,那就去相关方向最新paper中寻找灵感。比如探索不够充分时,可以用count-based exploration或者parameter noise来加强探索;DQN训练不稳定时,可以尝试Double-DQN,或者孪生网络,每次选择较小Q值计算目标值,从而抑制overestimation;DQN或DDPG数据效率不够时,可以用prioritized replay buffer;MARL里为了改善环境不稳定问题,可以尝试DIMAPG,……。问题无常势,算法无常形,群众智慧是无穷的,博采众长才能攻无不克。

关于算法选择就先写到这里,不同算法在训练时还有各种各样的trick和注意事项,我在训练篇里再详细介绍。

你可能感兴趣的:(深度强化学习落地方法论(3)—— 算法选择篇)