Press "Enter" to skip to content

简单的人构建花哨的神经网络的简单考虑

简单的人构建花哨的神经网络的简单考虑 四海 第1张

Henry & Co. on Unsplash 的照片

随着机器学习在行业中的不断渗透,神经网络从未像现在这样受到如此高度的关注。例如,像GPT-3这样的模型在过去几周一直在社交媒体上炒得沸沸扬扬,并且以恐吓标题的形式持续登上科技新闻以外的头条。

与此同时,深度学习框架、工具和专用库通过使最先进的研究变得比以往更易于使用,使机器学习研究走向了民主化。我们经常看到这些几乎像魔术一样的/即插即用的5行代码,承诺(几乎)最先进的结果。作为Hugging Face 🤗的工作人员,我承认我在其中部分有罪。😅这可能会给一个没有经验的用户产生误导,让他们错误地认为神经网络现在是一种成熟的技术,而事实上,这个领域仍在不断发展。

实际上,构建和训练神经网络往往是一种极其令人沮丧的经历

  • 有时很难确定性能是因为模型/代码中的错误还是仅仅是由于模型的表达能力有限。
  • 在整个过程的每一步中,你可能会犯很多细微的错误,但一开始可能并没有意识到,而你的模型仍然可以训练并给出不错的性能。

在本文中,我将尝试强调构建和调试神经网络时的一些心路历程。通过“调试”,我是指确保你所构建的内容与你心中所想的内容是一致的。我还将指出一些你可以参考的事项,当你不确定下一步应该怎么做时,我会列举一些我常常问自己的典型问题。

很多这些思考都源于我在自然语言处理方面的研究经验,但是大多数这些原则也可以应用于机器学习的其他领域。

1. 🙈 首先将机器学习放在一边

这听起来可能有些违反直觉,但构建神经网络的第一步是将机器学习放在一边,只专注于你的数据。查看示例、它们的标签、词汇的多样性(如果你正在处理文本)、它们的长度分布等等。你应该深入研究数据,对你正在处理的原始产品有第一手的了解,并着重提取模型可能能够捕捉到的一般模式。希望通过查看几百个示例,你能够识别出高层次的模式。一些你可以问自己的标准问题:

  • 标签是否平衡?
  • 是否有一些金标签你不同意?
  • 数据是如何获得的?在这个过程中可能存在哪些噪声来源?
  • 是否有任何自然的预处理步骤(分词、URL或标签的删除等)?
  • 示例之间的差异有多大?
  • 在这个问题上,哪种基于规则的算法会表现得不错?

重要的是要对数据集有一个高层次的感觉(定性)以及细致的分析(定量)。如果你正在使用公共数据集,其他人可能已经深入研究过数据并报告了他们的分析结果(在Kaggle竞赛中这是非常常见的),所以你应该一定要看一下这些报告!

2. 📚 接着,像你刚开始学习机器学习一样继续

一旦你对数据有了深入广泛的了解,我总是建议将自己置身于刚开始学习机器学习时的状态,并观看Andrew Ng在Coursera上的介绍课程尽可能简单地开始,以了解你的任务的难度以及标准基准的表现如何。例如,如果你处理的是文本,用于二元文本分类的标准基准可以包括在word2vec或fastText嵌入之上训练的逻辑回归。使用当前的工具,运行这些基线模型与运行BERT(可以说是许多自然语言处理问题的标准工具之一)一样容易(如果不是更容易)。如果有其他基准模型可用,运行(或实现)其中一些也是很有帮助的,它们将帮助你更加熟悉数据。

作为开发者,在构建一些花哨的东西时很容易感到满意,但有时很难合理地证明它的价值,特别是当它只比简单的基准高出几个点时,所以确保你有合理的比较点是很重要的:

  • 随机预测器会表现如何(尤其是在分类问题中)?数据集可能不平衡…
  • 对于随机预测器,损失会是什么样子?
  • 哪些指标是衡量我的任务进展的最佳指标?
  • 这个指标的局限性是什么?如果它是完美的,我能得出什么结论?我不能得出什么结论?
  • 在“简单方法”中达到完美分数还缺少什么?
  • 我的神经网络工具箱中是否有适合建模数据的归纳偏差的架构?

3. 🦸‍♀️ 不要害怕查看这些5行代码模板的内部

接下来,你可以根据之前获得的洞察和理解来开始构建你的模型。正如之前提到的,实现神经网络可能很复杂:有许多相互协作的组件(优化器、模型、输入处理流程等),在实现这些组件并将它们连接在一起时,许多小细节可能出错。挑战在于你可能犯下这些错误,训练一个模型而它从未崩溃,并且仍然能够表现出良好的性能…

然而,一个好的习惯是当你认为你已经完成实现时,尝试过拟合一小批示例(例如16个)。如果你的实现(几乎)正确,你的模型将能够通过显示0损失来过拟合和记忆这些示例(确保移除任何形式的正则化,如权重衰减)。如果不行,很有可能是你在实现中做错了什么。在一些罕见的情况下,这意味着你的模型表达能力不够或者容量不足。再次强调,先使用小规模模型(例如更少的层):你想要调试你的模型,所以需要快速的反馈循环,而不是高性能。

专业提示:根据我与预训练语言模型的经验,将嵌入模块冻结为预训练值对微调任务的性能影响不大,同时显著加快了训练速度。

一些常见的错误包括:

  • 索引错误…(这些真是最糟糕的 😅)。确保你按正确的维度收集张量…
  • 在评估模式下忘记调用 model.eval()(在PyTorch中)或 model.zero\_grad() 来清除梯度
  • 输入预处理出了问题
  • 损失函数传入错误的参数(例如传入概率而期望逻辑回归的结果)
  • 初始化没有打破对称性(通常发生在你用单个常数值初始化整个矩阵时)
  • 某些参数在前向传递中从未被调用(因此没有梯度)
  • 学习率始终为0等不正常的值
  • 你的输入以次优的方式被截断

专业提示:当你处理语言时,认真地观察分词器的输出。我无法计算因为分词出了问题而重现结果(有时甚至是我自己的旧结果)的时间浪费。🤦‍♂️

另一个有用的工具是深入研究训练动态,并通过绘制多个标量值(例如在Tensorboard中)来观察它们在训练过程中的变化。至少,你应该关注损失值、参数及其梯度的动态。

随着损失的减少,你还想观察模型的预测:可以通过在开发集上评估,或者我的个人喜好,打印一些模型的输出。例如,如果你正在训练一个机器翻译模型,看到生成的结果在训练过程中变得越来越令人信服是相当令人满意的。你要特别注意过拟合问题:训练损失继续减少,而评估损失则在不断增加。💫

4. 👀 调整但不要盲目调整

一旦您将所有内容设置好并运行起来,您可能希望调整超参数以找到最适合您设置的配置。在实践中,我通常使用随机网格搜索,因为它在实践中非常有效。

有些人报告成功使用诸如贝叶斯优化之类的高级超参数调整方法,但根据我的经验,与合理手动定义的网格搜索相比,随机搜索仍然是一个难以超越的基准。

最重要的是,没有必要用不同的超参数(或架构微调,例如激活函数)启动1000次运行:通过比较使用不同超参数的几次运行,了解哪些超参数具有最大的影响,但一般来说,仅通过调整少量值来期望获得最大性能提升是一种幻想。例如,如果您的最佳模型是使用学习率为4e2训练的,那么可能在您的神经网络内部发生了更基本的事情,您希望识别和理解这种行为,以便在当前特定上下文之外重复使用这些知识。

平均而言,专家使用更少的资源找到更好的解决方案。

总之,一条对我有帮助的一般性建议是:尽可能地(大部分时间)深入理解神经网络的每个组件,而不是盲目地(甚至可以说是不可思议地)调整架构。保持简单,避免那些您无法在尝试很努力后合理证明的小调整。当然,在“试错法”和“分析法”之间需要找到正确的平衡,但是随着您积累实践经验,许多这些直觉会变得更自然。 您也在训练您的内部模型。 🤯

以下是一些相关指南,供您阅读:

  • 来自Joel Grus的机器学习中的可重现性作为工程最佳实践的手段
  • 来自Cecelia Shao的神经网络调试清单
  • 来自Chase Roberts的机器学习代码单元测试方法
  • 来自Andrej Karpathy的训练神经网络的方法
Leave a Reply

Your email address will not be published. Required fields are marked *