构建深度神经网络,我有20条「不成熟」的小建议

选自PCC,做者:Matt H、Daniel R,机器之心编译。网络

本文介绍了构建深度神经网络的一些基本技巧,从通用技巧、神经网络调试和案例研究三方面展开。

在咱们的机器学习实验室中,咱们已经在许多高性能的机器上进行了成千上万个小时的训练,积累了丰富的经验。在这个过程当中,并不仅有电脑学习到了不少的知识,事实上咱们研究人员也犯了不少错误,而且修复了不少漏洞。架构

在本文中,咱们将根据自身经验(主要基于 TensorFlow)向你们提供一些训练深度神经网络的实用秘诀。有些建议可能对你来讲可能已经很熟悉了,可是其余人可能并不太了解。另外还有些建议可能并不适用,甚至可能对于特定的任务来讲是很差的建议,因此请谨慎使用!机器学习

这些都是一些广为人知的方法,咱们也是站在了巨人的肩膀上!本文的目的只是高屋建瓴地对如何在实践中使用它们进行总结。编辑器


通用秘诀函数

使用 ADAM 优化器。它确实颇有效,相对于较传统的优化器(如原版梯度降低),咱们更喜欢使用 ADAM。在 TensorFlow 环境下使用 ADAM 时,请注意:若是你想要保存和恢复模型权重,请记住在设置完 AdamOptimizer 后设置 Saver,这是由于 ADAM 也有须要恢复的状态(即对应于每一个权重的学习率)。工具

ReLU 是最好的非线性(激活函数),这就比如 Sublime 是最好的文本编辑器。但说实话,ReLU 确实是运行速度最快、最简便的,并且使人惊讶的是,它们在工做时梯度并不会逐渐减少(从而可以防止梯度消失)。尽管 sigmoid 是一个经常使用激活函数,可是它在 DNN 中传播梯度的效果并不太好。oop

不要在输出层使用激活函数。这应该是显而易见的,可是若是你经过一个共用的函数构建每一层,那这多是一个很容易犯的错误:请确保在输出层不要使用激活函数。性能

为每一层添加一个偏置项。这是机器学习的入门知识:本质上,偏置项将一个平面转换到最佳拟合位置。在 y=mx+b 式中,b 是偏置项,使直线可以向上或向下移动到最佳的拟合位置。学习

使用方差缩放初始化。在 TensorFlow 中,该方法写做 tf.contrib.layers.variance_scaling_initializer()。根据咱们的实验,这种初始化方法比常规高斯分布初始化、截断高斯分布初始化及 Xavier 初始化的泛化/缩放性能更好。粗略地说,方差缩放初始化根据每一层输入或输出的数量(在 TensorFlow 中默认为输入的数量)来调整初始随机权重的方差,从而帮助信号在不须要其余技巧(如梯度裁剪或批归一化)的状况下在网络中更深刻地传播。Xavier 和方差缩放初始化相似,只不过 Xavier 中每一层的方差几乎是相同的;可是若是网络的各层之间规模差异很大(常见于卷积神经网络),则这些网络可能并不能很好地处理每一层中相同的方差。测试

白化(归一化)输入数据。在训练中,令样本点的值减去数据集的均值,而后除以它的标准差。当网络的权重在各个方向上延伸和扩展的程度越小,你的网络就能更快、更容易地学习。保持数据输入以均值为中心且方差不变有助于实现这一点。你还必须对每一个测试输入也执行相同的归一化过程,因此请确保你的训练集与真实数据相似。

以合理地保留动态范围的方式对输入数据进行缩放。这个步骤和归一化有关,可是应该在归一化操做以前进行。例如,在真实世界中范围为 [0, 140000000] 的数据 x 一般能够用「tanh(x)」或「tanh(x/C)」来进行操做,其中 C 是某个常数,它能够对曲线进行拉伸,从而在 tanh 函数的动态倾斜(斜率较大)部分对更大输入范围内的数据进行拟合。尤为是在输入数据在函数的一端或者两端都不受限的时候,神经网络将在数据处于 (0,1) 时学习效果更好。

通常不要使用学习率衰减。在随机梯度降低(SGD)中,下降学习率是很常见的,可是 ADAM 自然地就考虑到了这个问题。若是你真的但愿达到模型性能的极致,请在训练结束前的一小段时间内下降学习率;你可能会看到一个忽然出现的很小的偏差降低,以后它会再次趋于平缓。

若是你的卷积层有 64 或 128 个滤波器,这就已经足够了。特别是对于深度网络来讲,好比 128 个滤波器就已经不少了。若是你已经拥有了大量的滤波器,那么再添加更多的滤波器可能并不会提高性能。

池化是为了变换不变性(transform invariance)。池化本质上是让网络学习到图像「某个部分」的「通常概念」。例如,最大池化可以帮助卷积网络对图像中特征的平移、旋转和缩放具有必定的鲁棒性。


神经网络的调试

若是网络学习效果不好(指网络在训练中的损失/准确率不收敛,或者你得不到想要的结果),你能够试试下面的这些秘诀:

过拟合!若是你的网络学习效果不佳,你首先应该作的就是去过拟合一个训练数据点。准确率基本上应该达到 100% 或 99.99%,或者说偏差接近 0。若是你的神经网络不能对一个数据点达到过拟合,那么模型架构就可能存在很严重的问题,但这种问题多是十分细微的。若是你能够过拟合一个数据点,可是在更大的集合上训练时仍然不能收敛,请尝试下面的几条建议。

下降学习率。你的网络会学习地更慢,可是它可能会找到一个以前使用较大的步长时没找到的最小值。(直观地说,你能够想象一下你正在走过路边的沟渠,此时你想要走进沟的最深处,在那里模型的偏差是最小的。)

提升学习率。这将加快训练速度,有助于增强反馈回路(feedback loop)。这意味着你很快就能大概知道你的网络是否有效。尽管这样一来网络应该能更快地收敛,可是训练结果可能不会太好,并且这种「收敛」状态可能其实是反复震荡的。(使用 ADAM 优化器时,咱们认为在许多实验场景下,~0.001 是比较好的学习率。)

减少(小)批量处理的规模。将批处理大小减少到 1 能够向你提供与权重更新相关的更细粒度的反馈,你应该将该过程在 TensorBoard(或者其余的调试/可视化工具)中展现出来。

删掉批归一化层。在将批处理大小减少为 1 时,这样作会暴露是否有梯度消失和梯度爆炸等问题。咱们曾经遇到过一个好几个星期都没有收敛的网络,当咱们删除了批归一化层(BN 层)以后,咱们才意识到第二次迭代的输出都是 NaN。在这里使用批量归一化层,至关于在须要止血带的伤口上贴上了创可贴。批归一化有它可以发挥效果的地方,但前提是你肯定本身的网络没有 bug。

加大(小)批量处理的规模。使用一个更大的批处理规模——还以为不够的话,若是能够,你不妨使用整个训练集——能减少梯度更新的方差,使每次迭代变得更加准确。换句话说,权重更新可以朝着正确的方向发展。可是!它的有效性存在上限,并且还有一些物理内存的限制。咱们发现,这条建议一般不如前两个建议(将批处理规模减少到 一、删除批归一化层)有用。

检查你矩阵的重构「reshape」。大幅度的矩阵重构(好比改变图像的 X、Y 维度)会破坏空间局部性,使网络更不容易学习,由于这时网络也必须学习重构。(天然特征变得支离破碎。事实上天然特征呈现出空间局部性也是卷积神经网络可以如此有效的缘由!)使用多个图像/通道进行重构时要特别当心;可使用 numpy.stack() 进行适当的对齐操做。

仔细检查你的损失函数。若是咱们使用的是一个复杂的函数,能够试着把它简化为 L1 或 L2 这样的形式。咱们发现 L1 对异常值不那么敏感,当咱们遇到带有噪声的批或训练点时,能够进行稍小幅度的调整。

若是能够,仔细检查你的可视化结果。你的可视化库(matplotlib、OpenCV 等)是否调整数据值的范围或是对它们进行裁剪?你能够考虑使用一种视觉上均匀的配色方案。


案例研究

为了使上文描述的过程更有关联性,下面给出了一些用于描述咱们构建的卷积神经网络的部分真实回归实验的损失图(经过 TensorBoard 进行可视化)。

最初,网络彻底没有学习:

咱们试着裁剪数据值,防止它们超越取值范围:

看看这些没有通过平滑的值有多么「疯狂」!学习率过高了吗?咱们试着下降学习率,而且在一组输入数据上进行训练:

你能够看到学习率最初的几个变化发生在哪里(大约训练了 300 步和 3000 步时)。显然,这里咱们进行的学习率降低调整太快了。因此若是给它更长的学习率衰减时间,它将表现得更好(损失更低):

能够看到,学习率在第 2000 步和第 5000 步时降低。这种状况更好,可是仍然不够完美,由于损失并无降到 0。

而后咱们中止学习率衰减,而且尝试经过 tanh 函数将输入值移动到一个更狭窄的范围内。这很显然将偏差值带到了 1 如下,可是咱们始终不能过拟合训练集:

在这里咱们发现了,经过删除批归一化层,网络很快地在一两次迭代以后输出 NaN。咱们禁用了批归一化,并将初始化方法改成方差缩放法。这让一切都不同了!咱们能够过拟合仅仅包含一两个输入的测试集。然而,下面的图对 Y 轴进行了裁剪。初始偏差值远远高于 5,这说明偏差减少了近 4 个数量级:

上方的图是很是平滑的,可是你能够看到,它极其迅速地过拟合了测试输入,而且随着时间推移,整个训练集的损失降到了 0.01 如下。这个过程没有下降学习率。以后,咱们在学习率下降了一个数量级以后继续训练,获得了更好的结果:

这些结果要好得多!可是若是咱们以几何级别下降学习率,而不是将训练分红两部分,会如何呢?

在每一步中将学习率乘以 0.9995,结果不是很好:

这大概是由于学习率降低地太快了。乘数若是取 0.999995 会更好,可是结果和彻底不衰减相差无几。咱们从这个特定的实验序列中得出结论:批归一化隐藏了糟糕的初始化致使的梯度爆炸;而且除了在最后故意设计的一个学习率衰减可能有帮助,减少学习率对 ADAM 优化器并无特别的帮助。与批归一化同样,对值进行裁剪掩盖了真正的问题。咱们还经过 tanh 函数控制高方差的输入值。

咱们但愿这些基本的诀窍在你对构建深度神经网络更加熟悉的时候可以提供帮助。一般,正是简单的事情让一切变得不一样。

相关文章
相关标签/搜索