选自Amid Fish 作者:Matthew Rahtz 机器之心编译
瑞士卢加诺大学信息学硕士 Tim Dettmers 对本文的点评 首先,整体而言,强化学习问题要远比预期的更为棘手。 主要原因是强化学习本身非常敏感,需要纠正大量的细节,如果不这么做,后面诊断问题所在会非常难。 实例 1:基本实现完成之后,训练效果并未跟上。我对问题所在充满各种想法,但经过数月的苦思冥想,发现问题出现在关键阶段中的奖励归一化和像素数据。尽管想通了这点,却仍未搞明白整个问题:像素数据进入的奖励探测器网络的准确度刚刚好,我花了很长时间终于明白仔细检查已预测的奖励足以发现奖励归一化漏洞。一句话,搞明白发生了什么问题几乎是偶然性的,找出最终可以导向正确路径的微小的不一致性。 实例 2:最后的代码清理完成之后,我多少有些错误地实现了 dropout。奖励探测器网络需要一对视频片段作为输入,由权重共享的两个网络同等处理。如果你添加 dropout,并在每个网络中不小心给了它相同的随机种子,每个网络将获得不同的 dropout,因此视频片段将不会被同等处理。正如结果表明完全修正它会破坏训练,尽管网络的预测准确度看起来一模一样。 找出被破坏的那一个。没错,我也没找到。 在我印象中这种情况非常普遍(比如《Deep Reinforcement Learning Doesn't Work Yet》)。我的解读是你要像对待数学问题一样对待强化学习项目。它不同于编程问题,你可以在数天内完成它;它更像是你在解决一个谜题,没有规律可循,唯一的方法是不断尝试,直到灵感出现彻底搞明白。 这需要你不断尝试,并对实现过程中的困惑保有最敏锐的嗅觉。 该项目中有很多这样的点,其中唯一的线索就是那些看起来无关紧要的小事情。比如,某些时候采用不同帧之间的差异作为特征会更加奏效。通过一些新特征继续向前会非常诱人,但我很困惑当时在我工作的简单环境中会造成如此大的差异。这只有通过思考这些困惑并意识到采用不同帧之间的差异,才能给正则化问题提供线索。 我不完全确定如何使人在这方面做更多,但我目前最好的猜测是:
无论如何:做好每次卡住数周的准备。(并相信坚持下来就会攻克难关,并留意那些小的细节。) 说到和过去的编程经验的区别,第二个主要学习经验是观念模式的区别,即需要长时间的工作迭代。 调试过程大致涉及 4 个基本步骤:
在我做过的大部分编程工作都习惯于快速反馈。如果有程序不工作了,你可以在数秒或数分钟内做出改变并查看有没有奏效。收集证据是很简单的工作。实际上,在快速反馈的情况下,收集证据可能比作出假设要简单得多。当你能凭直觉想到解决方案(并收集更多证据)时,为什么还要花费那么多时间考虑所有的可能性呢?换句话说,在快速反馈的情况下,你可以通过尝试而不是仔细考虑并迅速地缩小假设空间。 但当单次运行时间达到 10 小时的时候,尝试和反馈的策略很容易使你浪费很多的时间。 并行运行多个解决方案会有帮助,如果(a)你有计算机集群的云计算资源;(b)由于上述的强化学习中的各种困难,如果你迭代得太快,可能永远无法意识到你真正需要的证据。 从「多实验、少思考」到「少实验、多思考」的转变是提高效率的关键。当调试过程需要耗费很长的迭代时间时,你需要倾注大量的时间到建立假设上,即使需要花费很长的时间,比如 30 分钟甚至 1 小时。在单次实验中尽可能详实地检验你的假设,找到能最好地区分不同可能性的证据。 转向「少实验、多思考」的关键是保持细节丰富的工作日志。当每次实验的运行时间较少的时候,可以不用日志,但在实验时间超过一天的时候,很多东西都容易被忘记。我认为在日志中应该记录的有:
我起初记录相对较稀疏的日志,但到了项目的结束阶段,我的态度转变成了「记录我头脑中出现过的所有东西」。这很费时,但也很值得。部分是因为某些调试过程需要交叉参照结果,这些结果可能是数天前或数周前做出的。部分是因为(至少我认为)思考质量的通常提升方式是从大量的更新到有效的心理 RAM。 典型日志 为了从所做的实验中得到最大的效果,我在实验整个过程中做了两件事: 首先,持记录所有可以记录的指标的态度,以最大化每次运行时收集的证据量。有一些明显的指标如训练/验证准确率,但是在项目开始时花费一点时间头脑风暴,研究哪些指标对于诊断潜在问题比较重要是很有益的。 我这么推荐的部分原因是由于事后偏见:我发现哪些指标应该更早记录。很难提前预测哪些指标有用。可能有用的启发式方法如下:
另一个策略是查看别人使用什么度量指标。在深度强化学习中,John Schulman 在其演讲《Nuts and Bolts of Deep RL Experimentation》中给出了一些好主意(视频地址:https://www./watch?v=8EcdaCk9KaQ;slides 地址:http:///docs/nuts-and-bolts.pdf;摘要:https://github.com/williamFalcon/DeepRLHacks)。对于策略梯度方法,我发现策略熵是判断训练是否开始的优秀指标,比 per-episode 奖励更加敏锐。 不健康和健康的策略熵图示例。失败模式 1(左):收敛至常数熵(随机选择动作子集)。失败模式 2(中):收敛至零熵(每次选择相同的动作)。右:成功的 Pong 训练运行中的策略熵。 如果你在记录的指标中看到了一些可疑的现象,记得注意混淆,宁可假设它很重要也不要轻视,比如一些数据结构的低效实现。(我因为忽视了每秒帧数的微小而神秘的衰减,导致好几个月没找到一个多线程 bug。) 如果你能一次性看到所有指标,那么 debug 就容易多了。我喜欢在 TensorBoard 上有尽可能多的指标。用 TensorFlow 记录任意指标有点棘手,因此考虑使用 easy-tf-log(https://github.com/mrahtz/easy-tf-log),它提供简单的 tflog(key, value) 接口,无需任何额外设置。 另一件有助于从运行中获得更多信息的事情是,花时间尝试和提前预测失败。 多亏了事后偏见,在回顾实验过程时往往很容易发现失败原因。但是真正令人挫败的是在你观察之前,失败模式就已经很明显了。开始运行后,第二天回来一看失败了,在你开始调查失败原因之前,你就已经发现:「噢,一定是因为我忘记 frobulator 了」。 简单的事情是有时你可以提前触发「半事后观察」。它需要有意识的努力——在开始运行之前先停下来思考五分钟哪里可能出错。我认为最有用的是:
总是会有很多你无法预测的失败,有时你仍然遗漏了一些明显的事情,但是这个过程至少能够减少一些因为没有提前想到而出现的愚蠢失误。 最后,该项目最令人惊讶的是花费时间,以及所需的计算资源。 前者需要从日历时间的角度来看。我最初的估计是它作为业余项目,应该花费 3 个月时间,但它实际上用了 8 个月。(而我一开始预估的时间就已经很消极了!)部分原因是低估了每个阶段可能花费的时间,但是最大的低估是没有预测到该项目之外出现的其他事情。很难说这个规律有多广泛,但是对于业余项目来说,把预估时间乘以 2 可能是不错的方法。 更有趣的是每个阶段实际花费的时间。我原本的项目计划中主要阶段时间表基本如下: 写代码不费时,费时的是调试。事实上,在一个所谓的简单环境上花费的时间 4 倍于最初的实现。(这是我第一个花了数小时的业余项目,但所得经验与过去的机器学习项目相似。) 注:从一开始就仔细设计你认为什么应该是强化学习的「简单」环境。尤其是,仔细思考:(a)你的奖励是否真正传达解决任务的正确信息,是的,这很容易弄砸;(b)奖励是仅依赖之前的观测结果还是也依赖当前的动作。在你进行任意的奖励预测时,后者都可能是相关的。 第二个令人惊讶的事情是项目所需的计算时间。我很幸运可以使用学校的机房,虽然只有 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 相比谷歌云虚拟机更贵一些:1.2 美元/小时用一台 K80 GPU 的机器,对比 0.85 美元/小时用一台配置相似的虚拟机。除非你的预算很有限,我认为 FloydHub 带来的额外便利是值得的。只有在并行运行大量计算的时候,谷歌云虚拟机才是更加划算的,因为你可以在单个大型虚拟机上堆栈。 总的来说,该项目花了:
我惊讶地发现在实现项目的 8 个月期间,总共花费了 850 美元(FloydHub 花了 200 美元,谷歌云虚拟机花了 650 美元)。 但是即使花了这么多的精力,我在项目的最后阶段仍然遇到了很大的惊(jing)喜(xia):强化学习可能不太稳定以至于我们需要使用不同的随机种子重复运行多次以确定性能。 例如当我感觉完成了基本工作,我就会直接在环境上执行端到端的测试。但是即使我一直使用最简单的环境,我仍然遇到了非常大的问题。因此我重新回到 FloydHub 进行调整并运行了三个副本,事实证明我认为优秀的超参数只在三次测试中成功了一次。 三个随机种子的两个出现失败(红/蓝)是很少见的。 为了让你确切感受到需要做的计算的量级:
至于计算开销:
从《Deep Reinforcement Learning Doesn't Work Yet》这篇文章中,我们知道,那些不稳定性是正常的、可接受的。实际上,即使「五个随机种子(常用的报告指标)也可能不足以得到显著的结果,因为通过仔细的选择,你可以得到非重叠的置信区间。」 因此在 OpenAI Scholars programme 中提供 25000 美元的 AWS 信贷实际上并不疯狂,这可能正是确保你的计算可靠的大致成本。 我要表达的意思是,如果你想要完成一个深度强化学习项目,确保你知道你正趟进的是什么浑水,确保你已经准备好付出多少时间成本和多少经济成本。 总之,复现一篇强化学习论文很有趣。但在这之后,回头看看你有哪些技能真正得到了提升。同时,我也很好奇复现一篇论文是不是对过去数月时间的最佳利用。 一方面,我确实感觉到了机器学习工程能力的提升。我在识别常见的强化学习实现错误上更有自信了;我的工作流程在整体上变得更好了;从这篇特定的论文中,我学到了关于分布式 TensorFlow 和非共时设计的很多东西。 另一方面,我并不认为我的机器学习研究能力有很大提高(这才是我当初的真正目的)。和实现不同,研究的更加困难的部分似乎总在有趣但易驾驭、具体的思想,以及你确实花费时间实现并认为得到最高回报的思想之后出现。挖掘有趣的思想似乎取决于(a)丰富的概念词汇;(b)对思想的良好品味。我认为阅读有影响力的论文、写总结,并对它们做严谨分析是兼顾两者的好办法。 因此,无论你想提高工程技能还是研究技能,深度考虑都是值得的。如果你在某方面比较欠缺,最好启动一个项目来针对性提高。 如果你想要提高两者,最好是先阅读论文,直到你找到真正感兴趣的东西,能用简洁的代码进行实现,并尝试对其进行扩展。 如果你希望处理一个强化学习项目,下面是一些更具体的注意内容。 选择需要复现的论文
强化学习
一般机器学习
TensorFlow
> a = np.array([255, 200]).astype(np.uint8)
with tf.device('/device:GPU:0'):
gpu_name = tf.test.gpu_device_name() 心理状态
以下是强化学习的一些入门资源:
想要了解深度强化学习的现状,可以查看以下文章:
|
|
来自: taotao_2016 > 《计算机》