强化学习论文Ada开放式任务空间中的人类时间尺度适应
Posted Wwwilling
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了强化学习论文Ada开放式任务空间中的人类时间尺度适应相关的知识,希望对你有一定的参考价值。
- 文章题目:Human-Timescale Adaptation in an Open-Ended Task Space
- 作者:Deepmind
- 时间:2013
摘要
- 基础模型在监督和自我监督学习问题中表现出令人印象深刻的适应性和可扩展性,但到目前为止,这些成功还没有完全转化为强化学习 (RL)。 在这项工作中,我们证明了大规模训练 RL 智能体会产生一种通用的上下文学习算法,该算法可以像人类一样快速地适应开放式新颖的具身 3D 问题。 在广阔的环境动态空间中,我们的自适应代理 (AdA) 展示了即时假设驱动的探索、对所获得知识的有效利用,并且可以通过第一人称演示成功地得到提示。 适应性来自三个要素:(1) 在广泛、平滑和多样化的任务分布中进行元强化学习,(2) 参数化为大规模基于注意力的记忆架构的策略,以及(3) 一种有效的自动化课程,可以优先考虑代理人能力前沿的任务。 我们展示了关于网络大小、内存长度和训练任务分布丰富度的特征缩放法则。 我们相信我们的结果为越来越通用和自适应的 RL 代理奠定了基础,这些代理在越来越大的开放域中表现良好。
引言
- 在几分钟内适应的能力是人类智能的一个决定性特征,也是通向通用智能道路上的一个重要里程碑。 给定任何级别的有限理性,都会有一个任务空间,在这个任务空间中,智能体不可能仅通过概括其策略零样本来取得成功,但是如果代理能够从反馈中非常快速地进行上下文学习,那么进展是可能的。 为了在现实世界中以及与人类的互动中发挥作用,我们的人工智能体应该能够在仅进行少量互动的情况下进行快速灵活的适应,并且应该随着更多数据的可用而继续适应。 为了使这种适应概念实用化,我们试图训练一个代理人,在测试时在一个看不见的环境中给定几个情节,可以完成一项需要反复试验探索的任务,然后可以改进其解决方案以实现最佳行为。
- Meta-RL 已被证明对快速的上下文适应有效(例如 Yu 等人 (2020);Zintgraf (2022))。 然而,元强化学习在奖励稀疏且任务空间广阔且多样化的环境中取得的成功有限(Yang 等人,2019 年)。 在 RL 之外,半监督学习中的基础模型引起了极大的兴趣(Bommasani 等人,2021 年),因为它们能够适应广泛任务中演示的少量镜头。 这些模型旨在提供坚实的常识和技能基础,可以通过微调或演示提示来建立和适应新情况(Brown 等人,2020 年)。 这一成功的关键是基于注意力的内存架构,如 Transformers(Vaswani 等人,2017 年),它显示了性能随参数数量的幂律缩放(Tay 等人,2022 年)。
- 在这项工作中,我们为训练 RL 基础模型铺平了道路; 也就是说,一个代理已经在大量任务分布上进行了预训练,并且在测试时可以使少量镜头适应广泛的下游任务。 ==我们介绍了自适应代理 (AdA),这是一种能够在具有稀疏奖励的巨大开放式任务空间中进行人类时间尺度适应的代理。 AdA 不需要任何提示(Reed 等人,2022 年)、微调(Lee 等人,2022 年)或访问离线数据集(Laskin 等人,2022 年;Reed 等人,2022 年)。 相反,AdA 表现出假设驱动的探索行为,使用即时获得的信息来改进其策略并实现接近最佳的性能。 AdA 有效地获取知识,在几分钟内适应具有挑战性的稀疏奖励任务,==在具有第一人称像素观察的部分可观察的 3D 环境中。 一项人类研究证实,AdA 适应的时间尺度与受过训练的人类玩家相当。 AdA 在具有代表性的保留任务中的适应行为如图 1 所示。AdA 还可以通过第一人称演示的零样本提示来提高性能,类似于语言领域的基础模型。
- 图 1 | 人类时间尺度适应。 我们的智能体 (AdA) 在测试时间经验的几分钟内解决复杂 3D 环境中的保留任务的示例轨迹,无需任何进一步的智能体培训。 初始试验(探索)显示了一种揭示隐藏环境动态的策略。 经过几秒钟的测试时间经验(成功)后,AdA 找到了任务的有效解决方案。 后来(改进),它改进了这个解决方案,逐渐找到更有价值的行为。 白色实线表示代理移动。 彩色虚线表示携带相应颜色物体的代理。 有关任务的完整描述,请参见图 B.1。 AdA 行为的视频可在我们的微型网站和随附的结果卷轴上找到。
- 我们使用 Transformers 作为架构选择,通过基于模型的 RL2 扩展上下文快速适应(Duan 等人,2017 年;Melo,2022 年;Wang 等人,2016 年)。 基础模型通常需要大型、多样化的数据集来实现它们的通用性(Brown 等人,2020 年;Mahajan 等人,2018 年;Schuhmann 等人,2022 年;Sun 等人,2017 年;Zhai 等人,2022 年)。 为了在智能体收集自己的数据的 RL 设置中实现这一点,我们扩展了最近的 XLand 环境(OEL Team 等人,2021 年),生成了一个包含 1040 多个可能任务的广阔开放世界。 这些任务需要一系列不同的在线适应能力,包括实验、导航、协调、分工和应对不可逆性。 鉴于可能的任务范围很广,我们使用自适应自动课程,它会优先考虑智能体能力前沿的任务(Jiang 等人,2021a;OEL Team 等人,2021)。 最后,我们利用蒸馏(Schmitt et al., 2018),它可以扩展到具有超过 500M 参数的模型,据我们所知,这是发布时使用 RL 从头开始训练的最大模型(Ota et al., 2021 年)。 图 2 显示了我们方法的高级概述。
- 图 2 | 训练我们的自适应代理 (AdA)。 我们在 XLand 中使用元强化学习训练大型 Transformer 模型。 在训练过程中,任务被统一采样,随后进行过滤,以在代理能力的前沿产生一个不断变化的任务训练池。 在对这些任务进行培训后,代理能够像人类一样有效和高效地适应看不见的手写任务。
- 我们的主要贡献如下:
- • 我们介绍了 AdA,它是一种能够在各种具有挑战性的任务中进行人类时间尺度适应的代理。
- • 我们在具有自动化课程的开放式任务空间中使用元强化学习大规模训练 AdA。
- • 我们表明适应受记忆结构、课程以及训练任务分布的大小和复杂性的影响。
- • 我们在模型大小和内存中生成比例定律,并证明 AdA 通过零样本第一人称提示提高了性能。
Adaptive Agent (AdA)
- 为了在广阔而多样的任务空间中实现人类时间尺度适应,我们提出了一种通用且可扩展的基于内存的元 RL 方法,生成自适应代理 (AdA)。 我们在 XLand 2.0 中训练和测试 AdA,这是一个支持程序生成多样化 3D 世界和多人游戏的环境,具有需要适应的丰富动态。 我们的训练方法结合了三个关键组成部分:指导代理学习的课程、基于模型的 RL 算法来训练具有大规模基于注意力的记忆的代理,以及蒸馏以实现扩展。 我们的方法概述如图 2 所示。在以下部分中,我们将描述每个组件以及它如何有助于高效的少镜头自适应。
Open-ended task space: XLand 2.0
- 为了展示在开放式任务空间中的快速适应,我们扩展了程序生成的 3D 环境 XLand(OEL Team 等人,2021),我们在这里将其称为 XLand 1.0。 在 XLand 中,任务由游戏、世界和合作玩家策略列表(如果有)组成。 游戏由每个玩家的目标组成,定义为环境状态的布尔函数(谓词)。 当且仅当目标得到满足时,代理才会收到奖励。 目标以合成语言定义,代理接收编码。 世界指定静态地板拓扑、玩家可以与之交互的对象以及玩家的生成位置。 智能体通过第一人称像素观察来观察世界,以及其中的任何合作者。 游戏、世界和合作玩家系统的所有基本细节都继承自最初的 XLand; 参见 OEL 团队等。 (2021) 获取完整说明,附录 A.1 获取我们添加的新功能的详细信息。
- XLand 2.0 使用称为生产规则的系统扩展了 XLand 1.0。 每个生产规则都表达了一个额外的环境动态,导致比 XLand 1.0 中更丰富、更多样化的不同转换函数。 生产规则系统可以被认为是一种领域特定语言(DSL)来表达这种多样化的动态。 每个生产规则包括:
- 一个条件,也就是一个谓词,比如near(yellow sphere,black cube),
- 生成物列表(可能为空),它们是对象,如紫色立方体、黑色立方体。
- 当条件满足时,存在于条件中的对象将从环境中移除,并且出现在生成中的对象。 每个游戏可以有多个生产规则。 生产规则可以被玩家观察到,或者部分或完全被屏蔽,具体取决于任务配置。 更准确地说,有三种不同的机制可以向玩家隐藏生产规则信息:
- 隐藏完整的生产规则,玩家只能得到规则存在的信息,但既不知道条件也不知道生成什么。
- 隐藏对象,其中特定对象对所有生产规则都是隐藏的。 隐藏的对象被编号,如果隐藏了多个对象,代理可以区分它们。
- 隐藏条件的谓词,让代理知道需要满足的对象
一些谓词,但它不知道是哪一个。 隐藏的谓词也被编号。
- 我们不是按程序即时生成任务,而是对大量任务进行预采样。 有关我们用于预采样任务的具体机制的更多详细信息,请参阅附录 A.2。 我们在图 3 中可视化 XLand 2.0 任务空间。
- 图 3 | XLand 2.0:适应问题的广阔、平滑和多样化的任务空间。 不同的任务有不同的适应要求,例如实验、工具使用或分工。 例如,在一项需要实验的任务中,玩家可能需要确定哪些对象可以有效地组合,避免死胡同,然后优化他们组合对象的方式,就像实验化学的玩具版本。 每个任务都可以运行一次或多次试验,在试验之间重置环境,但代理内存不会。 突出显示的是两个示例任务,Wrong Pair Disappears 和 Pass Over Wall Repeatedly,显示了目标、初始对象、生产规则(图中的“规则”)以及代理需要如何与它们交互以解决任务。 有关完整的任务描述,请参阅附录 F.1。
Meta-RL
- 我们使用黑盒元强化学习问题设置(Duan 等人,2017 年;Wang 等人,2016 年)。 我们将任务空间 M 定义为一组部分可观察的马尔可夫决策过程 (POMDP)。 对于给定的任务𝑚∈M,我们将试验定义为从初始状态𝑠0 到终端状态𝑠𝑇 的任何转换序列。请注意,我们使用与Duan 等人(2017)相反的命名约定。 在我们的惯例中,术语“试验”很好地映射到人类行为文献中的相关概念 (Barbosa et al., 2022)。 在 XLand 中,任务终止当且仅当某个时间段𝑇∈[10s,40s]已经过去,每个任务指定。 环境以每秒 30 帧的速度滴答,代理每 4 帧观察一次,因此以时间步长为单位的任务长度在 [75, 300] 范围内。
- 一个episode 由给定任务 𝑚 的一系列 𝑘 试验组成。 在试验边界,任务被重置为初始状态。 在我们的领域中,初始状态是确定性的,除了代理的旋转,它是随机均匀采样的。 试验和剧集结构如图 3 所示。
- 在黑盒元 RL 训练中,代理使用与广泛分布的任务交互的经验来更新其神经网络的参数,该参数参数化代理在给定状态观察的动作上的策略分布。== 如果代理拥有动态内部状态(记忆),则元强化学习训练会通过利用重复试验的结构,为该记忆赋予隐式在线学习算法==(Mikulik 等人,2020 年)。
- 在测试时,这种在线学习算法使代理能够调整其策略,而无需进一步更新神经网络权重。 因此,agent 的记忆不会在试验边界重置,而是在情节边界重置。 为了生成一个情节,我们对一对 (𝑚, 𝑘) 进行采样,其中 𝑘 ∈ 1, 2, . . . 6。 正如我们稍后将讨论的那样,在测试时,AdA 会针对各种 𝑘 值的未见、保留任务进行评估,包括在训练期间未看到的保留 𝑘。 有关 AdA 的元强化学习方法的完整详细信息,请参阅附录 D.1。
Auto-curriculum learning
- 鉴于我们预采样任务池的广泛性和多样性,代理人通过均匀采样有效地学习是一项挑战。 大多数随机抽样的任务可能会太难(或太容易)而无益于代理的学习进度。 相反,我们使用自动方法在代理能力的前沿选择“有趣”的任务,类似于人类认知发展中的“最近发展区”(Vygotsky,1978)。 我们建议对两种现有方法进行扩展,这两种方法都可以显着提高代理性能和样本效率(见第 3.3 节),并导致出现课程,选择随着时间的推移复杂性增加的任务。
- No-op filtering。 我们将 OEL Team 等人(2021,第 5.2 节)中提出的动态任务生成方法扩展到我们的设置中。 当从池中抽取新任务时,首先对其进行评估以评估 AdA 是否可以从中学习。 我们评估了 AdA 的政策和“No-op”控制政策(在环境中不采取任何行动)的一些情节。 当且仅当两个策略的分数满足多个条件时,该任务才用于训练。 我们从原始的无操作过滤中扩展了条件列表,并使用归一化阈值来说明不同的试验持续时间。 有关详细信息,请参阅附录 D.5。
- 优先级别重播 (PLR)。 我们修改“Robust PLR”(此处称为 PLR,Jiang 等人 (2021a))以适应我们的设置。 与空操作过滤相比,PLR 使用适应度分数 (Schmidhuber, 1991),该分数近似于代理对给定任务的遗憾。 我们考虑了代理后悔的几种潜在估计,范围从 Jiang 等人 (2021b) 中使用的 TD 错误,到使用 AdA 中的动力学模型错误的新方法(参见附录 D.5 和图 D.1)。
- PLR 通过维护一个固定大小的存档来运行,其中包含具有最高适应性的任务。 我们只在从档案中抽样的任务上训练 AdA,这种情况的发生概率为 𝑝。 以概率 1 − 𝑝 随机抽样和评估新任务,并将适应度与档案中的最低值进行比较。 如果新任务具有更高的适应度,则将其添加到存档中,并丢弃适应度最低的任务。 因此,PLR 也可以看作是一种过滤形式,使用动态标准(档案的最低适应值)。 它与 no-op 过滤的不同之处在于,任务可以从存档中重复采样,只要它们保持高适应性。 为了在我们的异构任务空间中应用 PLR,我们通过使用滚动均值和方差对每个试验指数的适应度进行归一化,并使用每个时间步长的平均适应度值而不是总和来解释不同的试验持续时间。 最后,由于我们对跨试验适应后代理能力前沿的任务感兴趣,因此我们仅使用上次试验的适应度。 有关详细信息,请参阅附录 D.5。
RL agent
- 学习算法。 我们使用 Muesli(Hessel 等人,2021)作为我们的 RL 算法。 我们在这里简要描述了该算法,但请读者参阅原始出版物以了解详细信息。 将依赖于历史的编码作为输入,在我们的例子中是 RNN 或 Transformer 的输出,AdA 学习序列模型(LSTM)来预测值𝑣ˆ𝑖、动作分布𝜋ˆ𝑖 并为接下来的𝐼 步骤奖励𝑟ˆ𝑖。 这里,𝑖 = 0, . . . , 𝐼 表示预测 𝑖 前进的步骤。 𝐼 通常很小,在我们的例子中𝐼 = 4。对于每个观察到的步骤𝑡,模型展开𝐼 步骤并更新到各自的目标:
- 这里,𝑟𝑡+𝑖 指的是观察到的奖励。 𝐺𝑡+𝑖 是指基于从模型的一步预测中获得的 Q 值使用 Retrace(Munos 等人,2016)获得的价值目标。
- 行动目标 𝜋𝑡 CMPO 是通过使用剪裁的、归一化的、指数转换的优势重新加权当前策略 2 获得的。 Muesli 还基于这些优势结合了额外的辅助策略梯度损失,以帮助优化动作概率的即时预测。 最后,Muesli 维护一个跟踪序列模型的目标网络,用于执行和计算 Retrace 目标和优势。
- 内存架构。 记忆是适应的重要组成部分,因为它允许代理存储和回忆过去学习和经历的信息。 为了让智能体有效地适应任务要求的变化,记忆应该允许智能体回忆起最近和更久远的过去的信息。 虽然缓慢的基于梯度的更新能够捕获后者,但它们通常不够快以捕获前者,即快速适应。 基于记忆的元强化学习的大部分工作都依赖于 RNN 作为快速适应机制(Parisotto,2021)。 在这项工作中,我们表明 RNN 无法适应我们具有挑战性的部分可观察的体现 3D 任务空间。 我们试验了两种内存架构来解决这个问题:
- 带注意力的 RNN 在情景记忆中存储了一些过去的激活(在我们的例子中是 64 个)并关注它,使用当前的隐藏状态作为查询。 然后将注意力模块的输出与隐藏状态连接起来并送入 RNN。 我们通过仅在其情景记忆中存储每 8 次激活来增加代理的有效记忆长度。
我们得出这些数字是性能和速度之间的折衷。 请注意,生成的架构比同等大小的 Transformer 慢 - Transformer-XL (TXL)(Dai et al., 2019)是 Transformer 架构(Vaswani et al., 2017)的一个变体,它允许使用更长的、可变长度的上下文窗口来增加模型捕获的能力 长期依赖。 为了提高使用 RL 训练 Transformer 的稳定性,我们遵循 Parisotto 等人 (2020) 在每一层之前执行归一化,并像 Shazeer (2020) 一样在前馈层上使用门控。
- 两个内存模块都对一系列学习的时间步长嵌入进行操作,并生成一系列输出嵌入,这些嵌入被馈送到 Muesli 架构中,如图 4 中的 Transformer-XL 模块所示。 在第 3.2 节中,我们展示了两种基于注意力的记忆模块在需要适应的任务中都显着优于普通 RNN。 Transformer-XL 表现最好,因此除非另有说明,否则在我们的所有实验中都用作默认内存架构。
- 图 4 | 代理架构。 对于每个时间步,我们将像素观察、目标、手、试验和时间信息、生产规则、先前的动作和先前的奖励嵌入并组合到一个向量中。 这些观察嵌入按顺序传递给 Transformer-XL,其输出嵌入馈送到 MLP 值头、MLP 策略头和 Muesli LSTM 模型步骤(为简洁起见在图中省略)。 有关我们的代理架构的更多详细信息,请参阅附录 C.1。
- Going beyond few shots.。 我们建议对我们的 Transformer-XL 架构进行简单修改,以增加有效内存长度而无需额外的计算成本。 由于视觉 RL 环境中的观察结果往往在时间上高度相关,我们建议按照 RNN 中描述的注意力对序列进行子采样,允许代理参加 4 倍以上的试验。 为了确保仍然可以关注落在子采样点之间的观察结果,==我们首先使用 RNN 对整个轨迹进行编码,==目的是在每一步总结最近的历史记录。 我们表明,额外的 RNN 编码不会影响我们的 Transformer-XL 变体的性能,但可以实现更长范围的记忆(参见第 3.7 节)。
Distillation
- 对于前 40 亿步的训练,我们使用额外的蒸馏损失(Czarnecki 等人,2019 年;Schmidhuber,1992 年;Schmitt 等人,2018 年)通过预训练教师的策略来指导 AdA 的学习,在 称为启动的过程; 迭代此过程会产生代际训练机制(OEL Team 等人,2021 年;Wang 等人,2021 年)。 教师通过 RL 从头开始预训练,使用与 AdA 相同的训练程序和超参数,除了缺少初始蒸馏和更小的模型大小(教师的 23M Transformer 参数和多智能体 AdA 的 265M)。 与上述先前的工作不同,我们在前几代中不采用塑造奖励或基于人口的培训(PBT,Jaderberg 等人(2017))。 在蒸馏过程中,AdA 根据自己的策略行事,教师根据 AdA 观察到的轨迹提供目标 logits。 蒸馏使我们能够分摊原本昂贵的初始训练期,并且它允许代理人克服在训练初始阶段获得的有害表征; 参见第 3.6 节。
- 为了将蒸馏损失与Muesli相结合,我们从学生观察到的每个转变中展开模型。 我们最小化模型预测的所有动作概率与教师策略在相应时间步预测的动作概率之间的 KL 散度。 类似于 (1) 中定义的 Muesli 策略损失 L𝜋,我们定义
- 其中 π ^ \\hat\\pi π^ 对应于教师在给定相同观察历史的情况下提供的预测动作逻辑。 此外,我们发现在蒸馏过程中添加额外的 L 2 L^2 L2 正则化很有用。
复现一篇深度强化学习论文之前请先看了这篇文章!
去年,OpenAI和DeepMind联手做了当时最酷的实验,不用经典的奖励信号来训练智能体,而是根据人类反馈进行强化学习的新方法。有篇博客专门讲了这个实验 Learning from Human Preferences,原始论文是《 Deep Reinforcement Learning from Human Preferences》(根据人类偏好进行的深度增强学习)。
链接:https://arxiv.org/pdf/1706.03741.pdf
过一些深度强化学习,你也可以训练木棍做后空翻
我曾经看到过一些建议:复现论文是提高机器学习能力的一种很好的方法,这对我自己来说是一个有趣的尝试。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(https://www.youtube.com/watch?v=8EcdaCk9KaQ) 中有一些很好的建议。对于策略梯度方法,我发现策略熵是一个很好的指标,它可以很好地反映训练是否再进行,比每一次训练的奖励都要敏感得多。
不健康和健康的策略熵图。失败模式1(左):收敛到常量熵(随机选择一个行为子集);失败模式2(中间):收敛到零熵(每次选择相同的动作)。右:成功的乒乓球训练运行的策略熵
当你在记录的度量中看到一些可疑的东西时,记住要注意困惑,宁愿错误地假设它是重要的东西,而不仅仅把它当做一些数据结构的低效实现。(我忽略了每秒的帧中一个微小但莫名的衰变,从而导致几个月的多线程错误。)
如果能在一个地方看到所有的度量标准,调试就容易得多。我喜欢尽可能多得使用Tensorboard。使用Tensorflow记录度量标准比较困难,所以考虑使用查看easy-tf-log(https://github.com/mrahtz/easy-tf-log),它提供了一个简单的没有任何额外的设置界面的接口 tflog(key, value) 。
第二件看起来很有意义的是花时间尝试和提前预测失败。
多亏了后视偏差在回顾实验时失败原因往往是显而易见的。但真正令人沮丧的是,在你观察到它是什么之前,失败模式已经显而易见了。当你开始训练一个模型,等你第二天回来一看它失败了,甚至在你研究失败原因之前,你就意识到“哦,那一定是因为我忘了设置frobulator”?
简单的是有时你可以提前触发这种半事后认知(half-hindsight-realisation)。它需要有意识的努力,在开始运行之前先停下来思考五分钟哪里可能出错。我认为最有用的脚本是: 2
1、问问自己,“如果运行失败了自己会有多惊讶?”
2、如果答案是“不是很惊讶”,那么设想自己处于未来场景中——这次运行已经失败了,然后问问自己,“如果失败了,哪些地方错了?”
3、修正想到的任何地方
4、重复上述步骤知道问题1的答案是“非常惊讶”(或者至少“要多惊讶有多惊讶”)
总是会有一些你无法预测的错误,并且有时你仍然会忽略一些明显可以避免的错误,但是这个方法至少看起来能够减少一些你会因为没有事先想到而犯的非常愚蠢的错误。
· · ·
最后,该项目最令人惊讶的是花费的时间,以及所需的计算资源。
我最初估计作为一个业余项目,它会耗费3个月的时间。但是实际上它耗费了大约8个月时间。(最初的估计其实已经很悲观了!)部分原因是低估了每个阶段可能花费的时间,但是最大的低估是没有预测到该项目之外出现的其他事情。很难说这个推论有多么严谨,但是对于业余项目来说,将你初始的预估时间(已经悲观估计的)加倍或许是个不错的经验方法。
更令人感到意外的是:每个阶段实际花费的时间。我初始的项目计划中主要阶段的时间表基本如下:
这是每个阶段实际花费的时间
不是写代码花费了很长时间,而是调试代码。实际上,在一个所谓的简单环境上运行起来花费了4倍最初预想的实现时间。(这是第一个我连续花费数小时时间的业余项目,但是所获得的经验与过去机器学习项目类似。)
(备注:从一开始就仔细设计,你想象中强化学习的“简单”环境。尤其是,要仔细考虑:a)你的奖励是否能够真正传达解决任务的正确信息;b)奖励是否只仅依赖之前的观测结果还是也依赖当前的动作。实际上,如果你在进行任意的奖励预测时,后者可能也是相关的,例如,使用一个critic)
另一个是所需的计算资源总量。我很幸运可以使用学校的集群,虽然机器只有 CPU ,但对一些工作来说已经很好了。对于需要 GPU 的工作(如在一些小部分上进行快速迭代)或集群太繁忙的时候,我用两个云服务进行实验:谷歌云计算引擎的虚拟机(https://console.cloud.google.com/projectselector/compute/instances?supportedpurview=project&pli=1)、FloydHub(https://www.floydhub.com/)。
如果你只想通过shell访问GPU机器,谷歌云计算引擎还是不错的,不过我更多是在FloydHub上进行尝试的。FloydHub基本上是一个专门面向机器学习的云计算服务。运行floyd run python awesomecode.py 命令,FloydHub会初始化一个容器,将你的代码上传上去,并且运行你的代码。FloydHub如此强大有两个关键因素:
- 容器预装了GPU驱动和常用库。(甚至在2018年,我仍然在谷歌云计算引擎虚拟机上花费了好几个小时处理更新TensorFlow时CUDA的版本问题。)
- 每次运行都是自动存档的。对于每次运行,使用的代码、用来运行代码的命令、命令行任意输出以及任何输出的数据都会自动保存,并且通过一个网页接口建立索引。
如图为FloydHub的网页接口。上面:历史运行的索引,和单次运行的概观。下面:每次运行所使用的代码和运行输出的任意数据都被自动存档。
第二点的重要程度我难以言表。对于任何项目,这种长期且详细记录操作和复现之前实验的能力都是绝对有必要的。虽然版本控制软件也能有所帮助,但是a)管理大量输出非常困难;b)需要非常勤奋。(例如,如果你开始运行了一些,然后做了一点修改后又运行了另一个,当你提交首次运行的结果时,能否清楚使用了哪份代码?)你可以仔细记笔记或者检查你自己的系统,但是在FloydHub上,它都自动完成压根不需要你花费这么多精力。
我喜欢FloydHub的其他一些方面还有:
- 一旦运行结束,容器会自动关闭。不用担心地查看运行是否完成、虚拟机是否关闭。
- 付费比谷歌云更加直接。比如说你支付了10小时的费用,你的虚拟机立马就被充值了10个小时。这样使得每周的预算更加容易。
我用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上快速原型是有帮助的。)
这个项目总共花费了:
- 谷歌计算引擎上150个小时GPU运行时间,和7700小时(实际时间x核数)的CPU运行时间,
- FloydHub上292小时的GPU运行时间,
- 和我大学集群上 1500 小时的CPU运行时间(实际时间,4到16核)。
我惊讶地发现在实现这个项目的8个月时间里,总共花费了大约850美元(FloydHub上花了200美元,谷歌云计算引擎上花了650美元)。
其中一些原因是我笨手笨脚(见上文慢迭代思想章节)。一些原因是强化学习仍然是如此低效,运行起来需要花费很长时间(每次都需要花费多达10小时的时间来训练一个Pong代理)。
但其中很大一部分原因是我在这个项目最后阶段遇到意外:强化学习可能不太稳定,我们需要使用不同的随机种子重复运行多次以确定性能。
举例来说,一旦我认为基本完成了所有事情,我就会在这个环境上进行端到端测试。但是即使我一直使用最简单的环境,当训练一个点移动到正方形中央上,仍然遇到了非常大的问题。因此我重新回到 FloydHub 进行调整并运行了三个副本,事实证明我认为优秀的超参数在三次测试中只成功了一次。
2/3 的随机种子出现失败(红/蓝)并不罕见
对需要的计算量,我给你一个直观的数字:
- 使用 A3C和16名人员,Pong 需要花费 10 小时训练;
- 花费160小时CPU时间;
- 运行3个随机数种子, 需要CPU花费480小时(20天)。
成本方面:
- FloydHub 每小时收费 $0.50 美金,使用8核的设备;
- 所以每运行10小时收费5美金;
- 同时运行3个不同的随机数种子,每运行一次需要花费15美元。
就相当于每验证一次你的想法就需要花费3个三明治的钱。
再次,从 《Deep Reinforcement Learning Doesn’t Work Yet》这篇文章中可以看到,这种不稳定貌似正常也可接受。事实上,即使“ 五个随机种子 (一种通用标准) 可能不足以说明结果有意义, 通过仔细选择,你会得到不重叠的置信区间。”
(突然之间,OpenAI学者计划提供的25,000美元的AWS学分看起来并不那么疯狂,这可能与你给予某人的数量有关,因此计算完全不用担心。)
我的意思是,如果你想要解决一个深入的强化学习项目,请确保你知道你在做什么。确保你准备好需要花费多少时间,花多少钱。
· · ·
总的来说,复现一篇强化学习方面的论文作为业余项目还是很有趣的。反过来看,也可以想想从中学到了什么技能,我也想知道花费几个月时间复现一篇论文是否值得。
另一方面, 我感觉到我在机器学习方面的研究能力并没有很大提升 (回想起来,这实际上是我的目标),反而应用能力得到了提升,研究中相当多的困难似乎会产生出很多有趣和具体的想法;这些想法会让你觉得为此花费的时间是值得的。 产生一个有趣的想法似乎是一个问题 a) 需要大量可供利用的概念, b) 对好的想法或创意拥有敏锐的嗅觉 (例如,什么样的工作会对社区有用)。为了达成以上目的,我认为一个好的做法是阅读有影响力论文,总结并批判性分析这些论文。
所以我认为我从这个项目中得到的主要结论是,无论你是想提高工程技能还是研究技能都值得仔细思考。并不是说没有两者兼得的情况; 但是如果某方面是你的弱项的话,你可以找一个专门针对此项的项目做,来提高你的水平。
如果这两项技能你都想提升,比较好的方法或许是阅读大量论文,寻找你感兴趣且有清晰代码的论文,并尝试实现或扩展它。
· · ·
如果你想做深度强化学习的项目,这里有一些细节需要注意。
找些研究论文来复现
找一些知识点相对单一的论文,避免需要多个知识点协同工作的论文;
强化学习
- 如果你做的项目是将强化学习算法作为大型系统的一部分,不要尝试自己编写强化学习算法,尽管这是一个有趣的挑战,你也可以学到很多东西,但是强化学习目前还不足够稳定,你有可能会无法确定你的系统不工作是因为你的强化学习算法有bug,还是因为你的这个系统有Bug。
- 做任何事之前, 检查如何在你的环境中使用基线算法简化智能体训练。
- 不要忘记标准化观察,这些观察有可能使用在所有地方。
- 一旦你觉得你做出了什么,就尽快写一个端到端的测试。成功的训练可能比你期望的要更脆弱。
- 如果你使用 OpenAI Gym 环境,注意使用 -v0 环境, 有25%的可能,当前的操作被忽略,反而重复之前的操作 (降低环境的确定性)。如果你不希望出现那么多随机性的话,请使用 -v4 环境 。另外注意默认的环境每次只提供给你从仿真器得到的4帧,与早期的DeepMInd论文一致。如果你不想这样的话,请使用 NoFrameSkip 环境。因为这是一个完全稳定的环境,它实际呈现出的和仿真器上给你的完全一致,例如可以使用 PongNoFrameskip-v4。
通用机器学习
- 端到端测试需要运行很长时间,如果后面要进行大规模的重构,你将浪费大量时间。 第一次运行时就做好总比先计算出来然后保存重构留着后面再说要好。
- 初始化一个模块需要花费20秒。比如因为语法错误而浪费时间,确实让人头疼。如果你不喜欢IDE开发环境,或者因为你只能在shell的命令行窗口进行编辑,就值得花时间为你的编辑器创建一个Linter。(对 Vim来说, 我喜欢带Pylint 和 Flake8的ALE. Flake8更像一个格式检查器, 它可以发现Pylint不能发现的问题,比如传递错误参数给某个函数。)不管怎样,花点时间在linter工具上,可以在运行前发现一个愚蠢的错误。
- 不仅仅dropout你要小心,在实现权分享网络中时,你也需要格外小心 - 这也是批规范化。 别忘了网络中有很多规范化统计数据和额外的变量需要匹配。
- 经常看到运行过程中内存的峰值? 这可能是你的验证批量规模太大了。
- 如果你在使用Adam作为优化器使用时看到了奇怪的事情发生,这可能是由于 Adam 的动量参数引起。 尝试使用没有动量参数的优化器,比如RMSprop,或者通过设置 β1 =0 屏蔽动量参数。
TensorFlow
- 如果你想调试看计算图中间的一些节点发生了什么,使用 tf.Print,可以将每次运行的输入值打印出来。
- 如果你正在保存推断的检查点,你可以通过忽略优化器参数来节省大量空间。
- session.run() 很烧钱。尽量批量调用。
- 如果您在同一台机器上运行多个TensorFlow实例时,会出现GPU内存不足的错误, 这很可能是因为其中一个实例试图占用所有内存空间导致的,并不是因为你的模型太大。这是TensorFlow的默认做法,你需要告诉TensorFlow只按需使用内存空间,可以参考 allow_growth 操作。
- 如果你想在正在运行的的很多东西的时候,及时访问一个图表,就像你从多个进程访问同一个图表一样,但是有一种锁只允许同一时间只能有一个进程进行进行相关操作。这似乎与Python的全局解释锁明显不同,TensorFlow会在执行繁重工作前释放锁。对此我不敢确定,也没有时间做彻底调试。但如果你也遇到相同状况,可以使用多进程,并用分布式TensorFlow将图表分复制每个进程,将会比较简便。
- 使用Python不用担心溢出,但应用TensorFlow时,你就需要格外小心了:
当不能使用GPU时,请注意使用 allow_soft_placement 切换到CPU。如果你偶尔写的代码无法在GPU上运行时,它可以平滑切换到CPU。例如:
我不清楚有多少像这样无法在GPU上运行的操作,但安全起见,手动切换到CPU,例如:
健康的心理
- 不要对TensorBoard上瘾。 我是认真的。这是一个关于不可预知的奖励上瘾的完美例子:你检查自己的操作是如何运行的时候,而且它在不停的运行,有时检查时你会突然中大奖!这是件超级兴奋的事。 如果你每过一段时间就有检查 TensorBoard 的冲动,这时对你来说,应该设置一个规则,规定合理的检查时间间隔。
· · ·
如果你毫不犹豫地读了这篇文章,那就太棒了!
如果你也想进入深度强化学习领域,这里有一些资源供你入门时参考:
- Andrej Karpathy的 Deep Reinforcement Learning: Pong from Pixels 是一份关于建立动机和直觉方面很好的介绍文章。
- 想了解更多关于强化学习方面的理论,可以参考 David Silver的演讲 。这篇演讲没有过多关于深度强化学习的内容( 基于神经网络的强化学习 ),但至少教会了你很多词汇,帮助你理解相关论文。
- John Schulman的 Nuts and Bolts of Deep RL talk 有很多实际应用方面的建议,这些问题你在后面都可能遇到。
想了解目前深度强化学习领域发生了什么,可以参考一下这些内容:
- Alex Irpan的 Deep Reinforcement Learning Doesn’t Work Yet 对目前的状况有一个很好的概述。
- Vlad Mnih的 Recent Advances and Frontiers in Deep RL ,有很多关于实际例子,用以解决 Alex 文章中提到的问题。
- Sergey Levine的 Deep Robotic Learning 谈话,聚焦改善机器人的泛化和样本效率问题。
- Pieter Abbeel 在2017 NIPS会议上 Deep Learning for Robotics 主题演讲, 提到很多最新的深度强化学习技术。
以上是关于强化学习论文Ada开放式任务空间中的人类时间尺度适应的主要内容,如果未能解决你的问题,请参考以下文章