资讯 人工智能
此为临时链接,仅用于文章预览,将在时失效

呵,我复现一篇深度强化学习论文容易吗

作者:AI研习社-译站
2018/05/03 10:13

雷锋网按:本文为雷锋字幕组编译的技术博客 Lessons Learned Reproducing a Deep Reinforcement Learning Paper,作者Amid Fish。

翻译 | 黄达  Moonsea  赵鹏飞   校对 |  陈俊雅   整理 |  吴璇

去年,OpenAI和DeepMind联手做了当时最酷的实验,不用经典的奖励信号来训练智能体,而是根据人类反馈进行强化学习的新方法。有篇博客专门讲了这个实验 Learning from Human Preferences,原始论文是《 Deep Reinforcement Learning from Human Preferences》(根据人类偏好进行的深度增强学习)

呵,我复现一篇深度强化学习论文容易吗

通过一些深度强化学习,你也可以训练木棍做后空翻 

我曾经看到过一些建议:复现论文是提高机器学习能力的一种很好的方法,这对我自己来说是一个有趣的尝试。Learning from Human Preferences 的确是一个很有意思的项目,我很高兴能复现它,但是回想起来这段经历,却和预期有出入。

如果你也想复现论文,以下是一些深度强化学习的注意事项:

· · ·

首先,通常来说,强化学习要比你预期的要复杂得多

很大一部分原因是,强化学习非常敏感。有很多细节需要正确处理,如果不正确的话,你很难判断出哪里出了问题。

情况1:完成基本实现后,执行训练却没有成功。对于这个问题,我有各种各样的想法,但结果证明是因为激励的正则化和关键阶段1的像素数据。尽管事后我知道是哪里出了问题,但也找不到可循的通关路径:基于像素数据的激励预测器网络准确性的确很好,我花了很长时间仔细检查激励预测器,才发现注意到激励正则化错误。找出问题发生的原因很偶然,因为注意到一个小的差错,才找到了正确的道路。

情况2:在做最后的代码清理时,我意识到我把Dropout搞错了。激励预测器网络以一对视频片段作为输入,每个视频片段由两个具有共享权重的网络进行相同的处理。如果你在每个网络中都添加了Dropout,并且不小心忘记给每个网络提供相同的随机种子,那么对于每个网络,Dropout出的网络都是不同的,这样视频剪辑就不会进行相同的处理了。尽管预测网络的准确性看起来完全一样,但实际上完全破坏了原来的网络训练。

呵,我复现一篇深度强化学习论文容易吗

哪一个是坏的?嗯,我也看不明白

我觉得这是经常会发生的事情 (比如:《Deep Reinforcement Learning Doesn’t Work Yet 》)。我的收获是,当你开始一个强化学习项目的时候,理论上会遇到一个像被数学题困住了一样的困境。这并不像我通常的编程经验:在你被困的地方,通常有一条清晰的线索可以遵循,你最多可以在几天之内摆脱困境。 这更像是当你试图解决一个难题时,问题没有明显的进展,唯一的方法就是各种尝试,直到你找到关键的证据,或者找到重要的灵感,让你找到答案。

所以结论是在感到疑惑时应该尽可能注意到细节。

在这个项目中有很多要点,唯一的线索来自于注意那些微不足道的小事情。 例如,有时将帧之间的差异作为特征会很有效。直接利用新的特征是很有诱惑力的,但是我意识到,我并不清楚为什么它对我当时使用的简单环境产生如此大的影响。 只有处在这样的困惑下,才能发现,将背景归零后取帧之间的差异会使得正则化问题显现出来。 

我不太确定怎么样能让人意识这些,但我目前最好的猜测是:

还有,最好做好每几周就会陷入困境的准备。如果你坚持下去,注意那些小细节并且充满信心,你就能到达彼岸。

· · ·

说到过去编程经验的不同,第二个主要的学习经验是在长迭代时间下工作所需的思维方式的差异

调试似乎涉及四个基本步骤:

在我以前做过的大多数编程中,我已经习惯了快速反馈。如果有些东西不起作用,你可以做一个改变,看看它在几秒钟或几分钟内会产生什么不同。收集这些证据很容易。

事实上,在快速反馈的情况下,收集证据比形成假设要容易得多。当你能在短时间内验证第一个想法时,为什么要花15分钟仔细考虑所有的事情,即使它们可能是导致现象的原因?换句话说:如果你能获得快速反馈的话,不用经过认真思考,只要不停尝试就行了。

如果你采用的是尝试策略,每次尝试都需要花10小时,是种非常浪费时间的做法。如果最后一次都没有成功呢?好吧,我承认事情有时候就是这样。那我们就再检查一次。第二天早上回来:还是没用?好吧,也许是另一种,那我们就再跑一次吧。一个星期过后,你还没有解决这个问题。

同时进行多次运行,每次尝试不同的事情,在某种程度上都会有所帮助。但是  a) 除非你能够用集群,否则你最终可能会在云计算上付出大量的代价(见下文); b) 由于上面提到的强化学习的困难,如果你试图迭代得太快,你可能永远不会意识到你到底需要什么样的证据。

从大量的实验和少量的思考,转变为少量的尝试和大量的思考,是生产力的一个关键转变。在较长的迭代时间进行调试时,你确实需要投入大量的时间到建立假设--形成步骤--思考所有的可能性是什么,它们自己看起来有多大的可能性,以及根据到目前为止所看到的一切,它们看起来有多大的可能性。尽可能多地花你时间在上面,即使需要30分钟或一个小时。一旦你把假设空间尽可能完善了充实了,知道哪些证据可以让你能够最好地区分不同的可能性才可以着手实验。

(如果你把该项目作为业余项目,那么仔细考虑这个问题就显得尤为重要了。 如果你每天只在这个项目上工作一个小时,每次迭代都需要一天的时间,那么每周运行的次数更像你必须充分利用的稀有商品。每天挤出工作时间来思考怎么样改善运行结果,会让人感觉压力非常大。所以转变思路,花几天的时间思考,而不是开始任何运行,直到我对“问题是什么”的假设非常有信心为止。)

要想更多地思考,坚持做更详细的工作日志是非常重要的一环。当进展时间不到几个小时的时候,没有工作日志也无关紧要, 但是如果再长一点的话,你就很容易忘记你已经尝试过的东西,结果只能是在原地打转。 我总结的日志格式是:

Log 1: 我现在在做的有什么具体的输出?

Log 2: 大胆思考,例如关于当前问题的假设,下一步该做什么?

Log 3: 对当前的运行做个记录,并简短地提醒你每次运行应该回答哪些问题。

Log 4: 运行的结果 (TensorBoard 图, 任何其他重要的观察结果), 按运行类型分类 (例如:根据智能体训练时的环境)

一开始,我的日志相对较少,但在项目结束时,我的态度更倾向于“记录我所想的一切”。 虽然付出的时间成本很高,但我认为是值得的,部分原因是有些调试需要相互参照的结果和想法,往往要间隔数天或数周,部分是因为(至少这是我的印象)从大规模升级转变为有效的思维的整体改进。

呵,我复现一篇深度强化学习论文容易吗

典型的日志

· · ·

为了将实验成果效益最大化,在实验过程中我做了两件事情,这些事也许会在未来发挥作用。

首先,记录所有指标,这样你能最大限度提升每次运行时收集的证据数量。其中有一些明显的指标,比如训练/验证准确性。当然,用大量时间来头脑风暴,研究其他指标对于诊断潜在的问题也很重要。

我之所以提出这个建议,部分是因为后视偏差,因为我知道应该更早地开始记录哪些指标。很难预测哪些指标在高级阶段会有用。不过,可能有用的策略方法是:

对于系统中的每一个重要组件,考虑一下可以测量什么。如果有一个数据库,测量它在大小上增长的速度。如果有队列,测量处理项目的速度。

对于每一个复杂的过程,测量它的不同部分花了多长时间。如果你有一个训练循环,测量每一批运行所需的时间。如果你有一个复杂的推理过程,测量每个子推理所花费的时间。这些时间对以后的性能调试会有很大帮助,有时还会发现一些其他很难发现的错误。 (例如,如果你看到某些结果的时间越来越长,可能是因为内存泄漏。)

同样,请考虑分析不同组件的内存使用情况。小内存泄漏可以指向各种事情。

另一种策略是观察其他人在衡量什么。在深入强化学习的背景下,John Schulman在他的研究 Nuts and Bolts of Deep RL talk 中有一些很好的建议。对于策略梯度方法,我发现策略熵是一个很好的指标,它可以很好地反映训练是否再进行,比每一次训练的奖励都要敏感得多。

不健康和健康的策略熵图。失败模式1(左):收敛到常量熵(随机选择一个行为子集);失败模式2(中间):收敛到零熵(每次选择相同的动作)。右:成功的乒乓球训练运行的策略熵

当你在记录的度量中看到一些可疑的东西时,记住要注意困惑,宁愿错误地假设它是重要的东西,而不仅仅把它当做一些数据结构的低效实现。(我忽略了每秒的帧中一个微小但莫名的衰变,从而导致几个月的多线程错误。)

如果能在一个地方看到所有的度量标准,调试就容易得多。我喜欢尽可能多得使用Tensorboard。使用Tensorflow记录度量标准比较困难,所以考虑使用查看easy-tf-log,它提供了一个简单的没有任何额外的设置界面的接口 tflog(key, value) 。

第二件看起来很有意义的是花时间尝试和提前预测失败

多亏了后视偏差在回顾实验时失败原因往往是显而易见的。但真正令人沮丧的是,在你观察到它是什么之前,失败模式已经显而易见了。当你开始训练一个模型,等你第二天回来一看它失败了,甚至在你研究失败原因之前,你就意识到“哦,那一定是因为我忘了设置frobulator”?

简单的是有时你可以提前触发这种半事后认知(half-hindsight-realisation)。它需要有意识的努力,在开始运行之前先停下来思考五分钟哪里可能出错。我认为最有用的脚本是: 2

1、问问自己,“如果运行失败了自己会有多惊讶?”

2、如果答案是“不是很惊讶”,那么设想自己处于未来场景中——这次运行已经失败了,然后问问自己,“如果失败了,哪些地方错了?”

3、修正想到的任何地方

4、重复上述步骤知道问题1的答案是“非常惊讶”(或者至少“要多惊讶有多惊讶”)

总是会有一些你无法预测的错误,并且有时你仍然会忽略一些明显可以避免的错误,但是这个方法至少看起来能够减少一些你会因为没有事先想到而犯的非常愚蠢的错误。

· · ·

最后,该项目最令人惊讶的是花费的时间,以及所需的计算资源。

我最初估计作为一个业余项目,它会耗费3个月的时间。但是实际上它耗费了大约8个月时间。(最初的估计其实已经很悲观了!)部分原因是低估了每个阶段可能花费的时间,但是最大的低估是没有预测到该项目之外出现的其他事情。很难说这个推论有多么严谨,但是对于业余项目来说,将你初始的预估时间(已经悲观估计的)加倍或许是个不错的经验方法。 

更令人感到意外的是:每个阶段实际花费的时间。我初始的项目计划中主要阶段的时间表基本如下:

呵,我复现一篇深度强化学习论文容易吗

这是每个阶段实际花费的时间

不是写代码花费了很长时间,而是调试代码。实际上,在一个所谓的简单环境上运行起来花费了4倍最初预想的实现时间。(这是第一个我连续花费数小时时间的业余项目,但是所获得的经验与过去机器学习项目类似。)

(备注:从一开始就仔细设计,你想象中强化学习的“简单”环境。尤其是,要仔细考虑:a)你的奖励是否能够真正传达解决任务的正确信息;b)奖励是否只仅依赖之前的观测结果还是也依赖当前的动作。实际上,如果你在进行任意的奖励预测时,后者可能也是相关的,例如,使用一个critic)

另一个是所需的计算资源总量。我很幸运可以使用学校的集群,虽然机器只有 CPU ,但对一些工作来说已经很好了。对于需要 GPU 的工作(如在一些小部分上进行快速迭代)或集群太繁忙的时候,我用两个云服务进行实验:谷歌云计算引擎的虚拟机FloydHub。  

如果你只想通过shell访问GPU机器,谷歌云计算引擎还是不错的,不过我更多是在FloydHub上进行尝试的。FloydHub基本上是一个专门面向机器学习的云计算服务。运行floyd run python awesomecode.py 命令,FloydHub会初始化一个容器,将你的代码上传上去,并且运行你的代码。FloydHub如此强大有两个关键因素:

如图为FloydHub的网页接口。上面:历史运行的索引,和单次运行的概观。下面:每次运行所使用的代码和运行输出的任意数据都被自动存档。

第二点的重要程度我难以言表。对于任何项目,这种长期且详细记录操作和复现之前实验的能力都是绝对有必要的。虽然版本控制软件也能有所帮助,但是a)管理大量输出非常困难;b)需要非常勤奋。(例如,如果你开始运行了一些,然后做了一点修改后又运行了另一个,当你提交首次运行的结果时,能否清楚使用了哪份代码?)你可以仔细记笔记或者检查你自己的系统,但是在FloydHub上,它都自动完成压根不需要你花费这么多精力。

我喜欢FloydHub的其他一些方面还有:

我用FloydHub遇到的一个麻烦是它不能自定义容器。如果你的代码有非常多的依赖包,你在每次运行前都需要安装这些依赖包。这就限制了短期运行上的迭代速率。但是,你可以通过创建一个包含安装这些依赖包之后文件系统变更的“dataset”,然后再每次开始运行时都从“dataset”中拷贝出来这些文件解决这个问题(例如 create_floyd_base.sh)。虽然这很尴尬,但仍然比解决GPU驱动问题要好一些。

FloydHub比谷歌云稍微贵一点:FloydHub上一个K80 GPU机器1.2美元/小时,而谷歌云上类似配置的机器只需要0.85美元/小时(如果你不需要高达61G 内存的机器的话费用更低)。除非你的预算真的有限,我认为FloydHub带来的额外便利是值这个价的。只有在并行运行大量计算的情况下,谷歌云才算是更加划算,因为你可以在单个大型虚拟机上运行多个。  

(第三个选择是谷歌的新Colaboratory服务,这就相当于提供给你了一个能够在K80 GPU 机器上免费访问的Jupyter笔记本。但不会因为Jupyter而延迟:你可以执行任意命令,并且如果你真的想的话可以设置shell访问。这个最大的弊端是如果你关闭了浏览器窗口,你的代码不会保持运行,而且还有在托管该笔记本的容器重置之前能够运行时间的限制。所以这一点不适宜长期运行,但对运行在GPU上快速原型是有帮助的。)

这个项目总共花费了:

我惊讶地发现在实现这个项目的8个月时间里,总共花费了大约850美元(FloydHub上花了200美元,谷歌云计算引擎上花了650美元)。

其中一些原因是我笨手笨脚(见上文慢迭代思想章节)。一些原因是强化学习仍然是如此低效,运行起来需要花费很长时间(每次都需要花费多达10小时的时间来训练一个Pong代理)。

但其中很大一部分原因是我在这个项目最后阶段遇到意外:强化学习可能不太稳定,我们需要使用不同的随机种子重复运行多次以确定性能。  

举例来说,一旦我认为基本完成了所有事情,我就会在这个环境上进行端到端测试。但是即使我一直使用最简单的环境,当训练一个点移动到正方形中央上,仍然遇到了非常大的问题。因此我重新回到 FloydHub 进行调整并运行了三个副本,事实证明我认为优秀的超参数在三次测试中只成功了一次。  

呵,我复现一篇深度强化学习论文容易吗

2/3 的随机种子出现失败(红/蓝)并不罕见

对需要的计算量,我给你一个直观的数字:

成本方面:

就相当于每验证一次你的想法就需要花费3个三明治的钱。 

再次,从 《Deep Reinforcement Learning Doesn’t Work Yet》这篇文章中可以看到,这种不稳定貌似正常也可接受。事实上,即使“ 五个随机种子 (一种通用标准) 可能不足以说明结果有意义, 通过仔细选择,你会得到不重叠的置信区间。”

(突然之间,OpenAI学者计划提供的25,000美元的AWS学分看起来并不那么疯狂,这可能与你给予某人的数量有关,因此计算完全不用担心。)

我的意思是,如果你想要解决一个深入的强化学习项目,请确保你知道你在做什么。确保你准备好需要花费多少时间,花多少钱。

· · ·

总的来说,复现一篇强化学习方面的论文作为业余项目还是很有趣的。反过来看,也可以想想从中学到了什么技能,我也想知道花费几个月时间复现一篇论文是否值得。

另一方面, 我感觉到我在机器学习方面的研究能力并没有很大提升 (回想起来,这实际上是我的目标),反而应用能力得到了提升,研究中相当多的困难似乎会产生出很多有趣和具体的想法;这些想法会让你觉得为此花费的时间是值得的。 产生一个有趣的想法似乎是一个问题 a) 需要大量可供利用的概念,  b) 对好的想法或创意拥有敏锐的嗅觉 (例如,什么样的工作会对社区有用)。为了达成以上目的,我认为一个好的做法是阅读有影响力论文,总结并批判性分析这些论文。

所以我认为我从这个项目中得到的主要结论是,无论你是想提高工程技能还是研究技能都值得仔细思考。并不是说没有两者兼得的情况; 但是如果某方面是你的弱项的话,你可以找一个专门针对此项的项目做,来提高你的水平。

如果这两项技能你都想提升,比较好的方法或许是阅读大量论文,寻找你感兴趣且有清晰代码的论文,并尝试实现或扩展它。

· · ·

如果你想做深度强化学习的项目,这里有一些细节需要注意。

找些研究论文来复现

找一些知识点相对单一的论文,避免需要多个知识点协同工作的论文;

强化学习

通用机器学习

TensorFlow

呵,我复现一篇深度强化学习论文容易吗

当不能使用GPU时,请注意使用 allow_soft_placement 切换到CPU。如果你偶尔写的代码无法在GPU上运行时,它可以平滑切换到CPU。例如:

呵,我复现一篇深度强化学习论文容易吗

我不清楚有多少像这样无法在GPU上运行的操作,但安全起见,手动切换到CPU,例如:

呵,我复现一篇深度强化学习论文容易吗

健康的心理

· · ·

如果你毫不犹豫地读了这篇文章,那就太棒了!

如果你也想进入深度强化学习领域,这里有一些资源供你入门时参考:

想了解目前深度强化学习领域发生了什么,可以参考一下这些内容:

雷锋字幕组正在招募中,扫描下方二维码,备注“雷锋字幕组+姓名”加入我们。雷锋网雷锋网

呵,我复现一篇深度强化学习论文容易吗

长按图片保存图片,分享给好友或朋友圈

呵,我复现一篇深度强化学习论文容易吗

扫码查看文章

正在生成分享图...

取消
相关文章