新手教程:在新应用中实践深度学习的最佳建议

选自arXiv

作者:Leslie N. Smith

机器之心编译

参与:Jane W、黄小天

新手教程:在新应用中实践深度学习的最佳建议

本报告对希望在没有用过深度学习算法的应用软件上进行深度神经网络尝试的人群提供了实用建议。为了使项目更易于管理,这些建议被分成了几个阶段,每个阶段都包含了帮助新手的大量建议和见解。读者可点击阅读原文下载此论文。

新手教程:在新应用中实践深度学习的最佳建议

本报告针对的群体是应用程序的主题专家,但是在深度学习方面还是新手。它对希望在没有用过深度学习算法的应用软件上进行深度神经网络尝试的人群提供了实用建议。为了使你的项目更易于管理,我们建议将其分成几个阶段。对于每个阶段,本报告包含了帮助新手的大量建议和见解。

导语

虽然我的研究重点是深度学习 ( DL ),但是我发现我越发频繁地被要求帮助没有多少深度学习经验却想要在其全新应用中尝试深度学习的团体。这个 NRL 报告的动机来自于我注意到对所有这些群体的大部分建议和指导是相似的。因此,本报告讨论了更普遍相关的深度学习应用的方面。

虽然有几个有用的机器学习最佳实践建议资源 [1-5],但与本报告所涉及的深度学习有一些差异。不过,我建议读者阅读并熟悉这些参考资料,因为其中包含许多宝贵的信息。此外,有很多关于软件工程和敏捷方法学(agile methodology)(我认为读者已经熟悉)的最佳实践资源(例如 [6,7])。本报告中最为重要的内容可参见「深度学习」第 11 章「实践方法论」,但我在本报告中还讨论了该教材未涵盖的若干因素和见解。

你可以在下面看到,一个深度学习的应用项目被分为若干个阶段。然而,在实践中,你可能会发现回到较早的阶段会更有帮助。例如,在阶段 3 中找到类比时,你可能会发现你在第 1 阶段未考虑过的新指标。在项目进行时所有这些最佳实践都暗示着通过迭代返回某个阶段以及持续的提升。

阶段 1:开始准备

在本报告中,我假设你是(或可以取得)应用程序的主题专家。你应该熟悉解决相关问题的文献和研究,并了解最先进的解决方案和性能水平。我建议你从一开始考虑这一点,如果深度学习解决方案是值得的。你必须考虑现有技术的性能水平很高,是否值得在本报告中提出的建议下进行逐步改进。不要因为只是看起来像最新最伟大的方法而进行深度学习。你还应该考虑你是否有计算机资源,因为每个训练一个深度网络的进程可能需要几天或几周时间。我在自己的研究中充分利用了国防部的 HPC 系统。此外,你应该考虑机器学习是否合适——请记住,训练深度网络需要大量标签数据,如阶段 2 中所述。

第一步是量化地定义成功的情形。无论是由人类还是机器完成,如果它是成功的,你会看到什么?这有助于定义你的评估指标。想想哪些指标很重要?哪些不太重要?你需要指定在本项目成功中发挥作用的所有定量值,并确定如何权衡其中的每一个的权重。你还需要为你的指标定义目标;你的目标是否超过了人类的表现?你的目标将强烈影响项目进展。从数量上了解人在这一任务中的表现是什么将有助于指导你的目标;最先进的技术与人类的表现相比如何?同样,了解人类如何解决这个任务将提供有关机器如何解决其任务的有价值信息。

这些指标中的一些也可以用来设计损失函数(loss function),这有助于指导网络训练。不要仅仅使用 softmax / cross 熵/ log,因为这是最常见的损失函数,尽管你应该从它们开始。从定义上看,你的评估指标是对你的应用程序重要的数量。准备好将这些指标作为损失函数的加权组成部分进行测试,以指导训练(见阶段 6)。

尽管你可能出于其强大能力而考虑深度学习,那么考虑一下如何使网络的「工作」尽可能简单。这是反直觉的,但由于它是深度网络的力量,可能会激励你尝试。然而,网络必须执行的工作越简单,训练越容易,性能越好。你(或最先进的技术)目前使用的启发法/物理学是否可以在这里使用?可以预处理数据吗?虽然网络可以学习复杂的关系,但请记住:「网络工作越简单,执行效果就越好」。所以值得花时间考虑从以前的工作你可以借鉴的内容以及网络需要为你做些什么。假设你希望改进物理学高度近似的复杂过程(即「球形牛」情况);你可以选择将数据输入深度网络,以便(希望)输出所需的结果,或者你可以训练网络以在近似结果中查找更正。后一种方法几乎肯定会超过前者。另一方面,不要依赖人工努力来定义潜在的启发法——最稀缺的资源是人力时间,所以让网络学习它的表征,而不需要任何固定的人工预处理。

此外,你可能需要记下你对这一最先进的过程的任何假设或期望,因为它将证明自己的效果。

阶段 2:准备你的数据

深度学习需要大量的训练数据。你可能想知道「我需要多少训练数据」。网络中的参数数量与训练数据的数量相关。训练样本的数量将在第 6 阶段限制你的架构选择。训练数据越多,网络就越大而准确。因此,训练数据的数量取决于你在阶段 1 中定义的目标。

除了训练数据之外,你还需要更少的标签验证或测试数据。该测试数据应与训练数据相似但不一样。网络没有对测试数据进行训练,但它用于测试网络的泛化能力。

如果训练数据量非常有限,则考虑迁移学习(transfer learning)[9] 和域适应(domain adaptation)[10,11]。如果这是合适的,下载最接近你的数据的数据集用于预训练。另外,考虑创建合成数据。合成数据具有可以创建大量样本并使其多样化的优点。

项目目标也指导训练数据样本的选择。确保训练数据与任务直接相关,并且它的多样性足以覆盖问题空间。研究每个类别的统计数据。例如,类别是否平衡?平衡类别的一个例子是猫与狗,而不平衡的类别是猫与所有其它哺乳动物(如果你的问题本质上是不平衡的,向深度学习专家请教)。

什么预处理是可能的?你可以零均值并归一化数据吗?这使得网络的工作更容易,因为它消除了学习平均值的工作。通过在训练样本之间建立更大的相似性,归一化也使网络的工作更容易。

如上所述,调查是否有办法使用先验知识或已知启发法(heuristic)降低数据的维度。你不需要花时间人工确定启发法,因为目标是节省人力时间,你可以让网络学习自己的表征。只要知道网络必须筛选的无关数据越多,需要的训练数据就越多,训练网络的时间就越长。所以充分利用现有的技术。

阶段 3:找出你的应用程序与最相近的深度学习应用程序之间的相似点

专家知道不能每个项目都从头开始。这就是为什么他们被称为专家的原因。他们再使用以前的解决方案、搜索其他研究人员的深度学习文献来解决问题。即使没有人做过你想做的事情,你仍然需要利用专家的长处。

深度学习已被应用于各种应用。为了创建你的基线模型(baseline model)——即你的起点——你需要找到与你的应用程序相似的应用程序。你应该搜索深度学习文献,并考虑各种应用程序解决的「问题」与你在应用程序中需要解决的「问题」进行比较。找出这些问题之间的相似之处和类比。此外,请注意你的新应用程序与深度学习应用程序之间的差异,因为这些差异可能需要在阶段 6 中更改架构。

当你找到最相近的应用程序时,请查找代码并下载。许多研究人员在开源环境中公开发表了他们的代码,使代码可重复用于研究。你的第一个目标是在最接近的应用程序的论文中复制结果。然后在「了解」阶段修改各块代码,看看其对结果的影响。如果你幸运的话,会有几个代码可用,你应该复制所有代码的结果。这个对比将为你提供足够的信息,以便你可以在阶段 4 中创建基线。

有几种「经典」的深度学习应用程序和众所周知的解决方案。这些包括图像分类/对象识别(卷积网络)、处理如语言处理的顺序数据(RNN/LSTM/GRU)和复杂的决策制定(深度强化学习)。还有一些常见的其它应用,如图像分割(image segmentation)和超分辨率(super-resolution)(全卷积网络)以及相似匹配(孪生网络/Siamese network)。附录 A 列出了许多最近的深度学习应用程序和它们使用的架构以及描述应用程序的论文的链接。这些可以提供一些想法,但不应该作为寻找深度学习应用程序的来源。你应该仔细搜索谷歌学术(https://scholar.google.com)和 arXiv(https://arxiv.org)以获取深度学习的应用程序。

阶段 4:创建简单的基线模型

开始时始终保持简单、小巧和容易。使用比你预期需要的更小的架构。从共同的目标函数开始,使用超参数的常用设置,仅使用部分训练数据。这是一个能够部分实践敏捷软件方法论的好地方,如简单设计、单元测试(unit testing)和简短发布(short release)。现在只需要获得基本功能,并在阶段 6 中进行改进。也就是说,计划小步骤、持续更新、并迭代。

只选择一种常见的框架,如 Caffe、TensorFlow 或 MXnet。计划仅使用一种框架和一种计算机语言来最大限度地减少由不必要复杂度带来的错误。选择框架和语言可能会受到在阶段 3 中执行的复制工作的驱动。

如果网络将成为较大的框架的一部分,那么这里是检查框架 API 正常工作的好地方。

阶段 5:创建可视化和调试工具

了解模型中发生的情况将会影响项目的成功。木匠有一个说法「测量两次,切割一次」。你应该「编码一次,测量两次」。除了评估输出外,你还应该可视化你的架构并测量内部实体(internal entity),以了解为什么获得这样的结果。离开模型诊断,你将很难解决问题或提高性能。

你应该对与高偏差(收敛于错误的结果)对高方差(收敛差)相关的问题有一个一般的了解,因为每种类型的问题都有不同的解决方案;例如,你可能会用更大的网络修复高偏差问题,但是你可以通过增加训练数据集的大小来处理高方差问题。

可视化你的模型,以便你可以尽可能多地监视架构的进化过程。在可能的情况下,为每次代码修改设置单元测试(unit test)。你应该将训练错误与测试错误进行比较,并将两者与人工表现进行比较。你可能会发现你的网络会表现得很奇怪,你需要确定架构进化中发生的事情以及原因。首先开始调试最差的问题。了解问题是否与训练数据、架构或损失函数有关。

请记住,误差分析会试图解释当前性能与完美性能之间的差异。销蚀分析(ablative analysis)试图解释一些基线表现与当前表现之间的差异。使用一种或另一种或两种分析可能是有用的。

使用 TensorFlow 作为框架的一个动机是它有一个名为 TensorBoard 的可视化系统,它是框架的一部分。你可以从 TensorFlow 输出必要的文件,TensorBoard 可用于可视化你的架构,并监控权重和特征映射(feature map),探索网络创建的嵌入空间(embedded space)。因此,在框架中可用调试和可视化工具。如果使用其它框架,你需要找到这些工具(通常可以在线获得)或创建自己的工具。

阶段 6:微调你的模型

这个阶段可能需要大部分时间。你应该广泛地实验。并且不要仅使用你认为会改善结果的因素,而是尝试改变每一个因素以学习当其变化时发生了什么。改变架构设计、深度、宽度、路径、权重初始化、损失函数等。更改每个超参数,了解提高或降低数值时的效果。我建议使用学习速率范围测试(learning rate range test)[12] 了解你的网络在不同学习速率下的行为。可以进行类似的程序来研究其它超参数的影响。

尝试各种正则化方法,如数据增强(augmentation)、dropout 和权重衰减。泛化(generalization)是深度网络的关键优势之一,所以一定要测试正则化方法,以便最大限度地提高概括不可见情况的能力。

你应该测试损失函数。你在基线中使用了简单的损失函数,但也创建了多个你关心并达到(定义)成功的评估指标。评估指标和损失函数之间的唯一差异在于用于测试数据的测量指标和用于训练网络的训练数据的损失函数。更复杂的损失函数可以产生更成功的结果吗?你可以向损失函数添加加权项,以反映每个指标对结果的重要性。但是要非常小心,不要因不重要的标准而使损失函数复杂化,因为它是你模型的核心。

早些时候,你发现应用程序与现有的深度学习应用程序之间的类比,并选择最接近的作为你的基线。现在比较第二个或第三个最接近的应用程序。如果你按照另一个类比并使用该架构,会发生什么?你能设想结合两者来测试吗?

一开始,你应该从一些容易的取得成功。随着你不断深入,提高性能将变得更加困难。你在阶段 1 中定义的目标将决定你希望的性能改进的程度。或者你可能想要修改之前定义的目标。

阶段 7:端到端训练、集成与其他复杂度

如果你有时间和预算,你可以探索更复杂的方法,实际上有很多复杂的方法可供选择。有大量深度学习的文献,每天都在出现更多的论文。大多数这些论文以一种或另一种方式宣布了新的最先进的结果,有些可能帮助你提升性能。这个部分可以单独作为一份长的报告,因为有这么多架构和其它选择可以考虑,但如果你处于这个阶段,请考虑与具有大量深度学习专长的人交谈,因为在这个阶段的建议可能对你的应用程序是独一无二的。

但是,你可能会考虑两种常用的方法:端到端的训练和集成。

作为一般规则,连接系统的端到端训练将优于具有多个部分的系统,因为具有端到端训练的组合系统允许每个部分独立适应任务。因此,如果与你的应用相关,考虑这些组合的部分是有用的。

各种学习器的集合(即装袋(bagging)、提升(boosting)、堆叠(stacking))也可以提高单个模型的性能。但是,这将需要你训练和维护集合中的所有学习器。如果你的性能目标值得这样做,那么值得测试一个集合的方法。

总结

当你在以前没有使用过深度学习的应用程序上实验时,本报告为你提供了许多因素作为参考。并不是每个项目都与这些因素相关,但我希望本文能涵盖在项目期间你应该考虑的大多数因素。祝你成功。

新手教程:在新应用中实践深度学习的最佳建议

相关推荐