Auto Byte

专注未来出行及智能汽车科技

微信扫一扫获取更多资讯

Science AI

关注人工智能与其他前沿技术、基础学科的交叉研究与融合发展

微信扫一扫获取更多资讯

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

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

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

在本文中,我们将根据自身经验(主要基于 TensorFlow)向大家提供一些训练深度神经网络的实用秘诀。有些建议可能对你来说可能已经很熟悉了,但是其他人可能并不太了解。另外还有些建议可能并不适用,甚至可能对于特定的任务来说是不好的建议,所以请谨慎使用!

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

通用秘诀

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

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

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

为每一层添加一个偏置项。这是机器学习的入门知识:本质上,偏置项将一个平面转换到最佳拟合位置。在 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。

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

检查你矩阵的重构「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 函数控制高方差的输入值。

我们希望这些基本的诀窍在你对构建深度神经网络更加熟悉的时候能够提供帮助。通常,正是简单的事情让一切变得不同。

工程神经网络
12
相关数据
池化技术

池化(Pooling)是卷积神经网络中的一个重要的概念,它实际上是一种形式的降采样。有多种不同形式的非线性池化函数,而其中“最大池化(Max pooling)”是最为常见的。它是将输入的图像划分为若干个矩形区域,对每个子区域输出最大值。直觉上,这种机制能够有效的原因在于,在发现一个特征之后,它的精确位置远不及它和其他特征的相对位置的关系重要。池化层会不断地减小数据的空间大小,因此参数的数量和计算量也会下降,这在一定程度上也控制了过拟合。通常来说,CNN的卷积层之间都会周期性地插入池化层。

激活函数技术

在 计算网络中, 一个节点的激活函数定义了该节点在给定的输入或输入的集合下的输出。标准的计算机芯片电路可以看作是根据输入得到"开"(1)或"关"(0)输出的数字网络激活函数。这与神经网络中的线性感知机的行为类似。 一种函数(例如 ReLU 或 S 型函数),用于对上一层的所有输入求加权和,然后生成一个输出值(通常为非线性值),并将其传递给下一层。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

高斯分布技术

正态分布是一个非常常见的连续概率分布。由于中心极限定理(Central Limit Theorem)的广泛应用,正态分布在统计学上非常重要。中心极限定理表明,由一组独立同分布,并且具有有限的数学期望和方差的随机变量X1,X2,X3,...Xn构成的平均随机变量Y近似的服从正态分布当n趋近于无穷。另外众多物理计量是由许多独立随机过程的和构成,因而往往也具有正态分布。

重构技术

代码重构(英语:Code refactoring)指对软件代码做任何更动以增加可读性或者简化结构而不影响输出结果。 软件重构需要借助工具完成,重构工具能够修改代码同时修改所有引用该代码的地方。在极限编程的方法学中,重构需要单元测试来支持。

收敛技术

在数学,计算机科学和逻辑学中,收敛指的是不同的变换序列在有限的时间内达到一个结论(变换终止),并且得出的结论是独立于达到它的路径(他们是融合的)。 通俗来说,收敛通常是指在训练期间达到的一种状态,即经过一定次数的迭代之后,训练损失和验证损失在每次迭代中的变化都非常小或根本没有变化。也就是说,如果采用当前数据进行额外的训练将无法改进模型,模型即达到收敛状态。在深度学习中,损失值有时会在最终下降之前的多次迭代中保持不变或几乎保持不变,暂时形成收敛的假象。

学习率技术

在使用不同优化器(例如随机梯度下降,Adam)神经网络相关训练中,学习速率作为一个超参数控制了权重更新的幅度,以及训练的速度和精度。学习速率太大容易导致目标(代价)函数波动较大从而难以找到最优,而弱学习速率设置太小,则会导致收敛过慢耗时太长

损失函数技术

在数学优化,统计学,计量经济学,决策理论,机器学习和计算神经科学等领域,损失函数或成本函数是将一或多个变量的一个事件或值映射为可以直观地表示某种与之相关“成本”的实数的函数。

TensorFlow技术

TensorFlow是一个开源软件库,用于各种感知和语言理解任务的机器学习。目前被50个团队用于研究和生产许多Google商业产品,如语音识别、Gmail、Google 相册和搜索,其中许多产品曾使用过其前任软件DistBelief。

张量技术

张量是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数,这些线性关系的基本例子有内积、外积、线性映射以及笛卡儿积。其坐标在 维空间内,有 个分量的一种量,其中每个分量都是坐标的函数,而在坐标变换时,这些分量也依照某些规则作线性变换。称为该张量的秩或阶(与矩阵的秩和阶均无关系)。 在数学里,张量是一种几何实体,或者说广义上的“数量”。张量概念包括标量、矢量和线性算子。张量可以用坐标系统来表达,记作标量的数组,但它是定义为“不依赖于参照系的选择的”。张量在物理和工程学中很重要。例如在扩散张量成像中,表达器官对于水的在各个方向的微分透性的张量可以用来产生大脑的扫描图。工程上最重要的例子可能就是应力张量和应变张量了,它们都是二阶张量,对于一般线性材料他们之间的关系由一个四阶弹性张量来决定。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

梯度下降技术

梯度下降是用于查找函数最小值的一阶迭代优化算法。 要使用梯度下降找到函数的局部最小值,可以采用与当前点的函数梯度(或近似梯度)的负值成比例的步骤。 如果采取的步骤与梯度的正值成比例,则接近该函数的局部最大值,被称为梯度上升。

卷积神经网络技术

卷积神经网路(Convolutional Neural Network, CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。卷积神经网路由一个或多个卷积层和顶端的全连通层(对应经典的神经网路)组成,同时也包括关联权重和池化层(pooling layer)。这一结构使得卷积神经网路能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网路在图像和语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比较其他深度、前馈神经网路,卷积神经网路需要考量的参数更少,使之成为一种颇具吸引力的深度学习结构。 卷积网络是一种专门用于处理具有已知的、网格状拓扑的数据的神经网络。例如时间序列数据,它可以被认为是以一定时间间隔采样的一维网格,又如图像数据,其可以被认为是二维像素网格。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

随机梯度下降技术

梯度下降(Gradient Descent)是遵循成本函数的梯度来最小化一个函数的过程。这个过程涉及到对成本形式以及其衍生形式的认知,使得我们可以从已知的给定点朝既定方向移动。比如向下朝最小值移动。 在机器学习中,我们可以利用随机梯度下降的方法来最小化训练模型中的误差,即每次迭代时完成一次评估和更新。 这种优化算法的工作原理是模型每看到一个训练实例,就对其作出预测,并重复迭代该过程到一定的次数。这个流程可以用于找出能导致训练数据最小误差的模型的系数。

OpenCV技术

OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。

过拟合技术

过拟合是指为了得到一致假设而使假设变得过度严格。避免过拟合是分类器设计中的一个核心任务。通常采用增大数据量和测试样本集的方法对分类器性能进行评价。

深度神经网络技术

深度神经网络(DNN)是深度学习的一种框架,它是一种具备至少一个隐层的神经网络。与浅层神经网络类似,深度神经网络也能够为复杂非线性系统提供建模,但多出的层次为模型提供了更高的抽象层次,因而提高了模型的能力。

优化器技术

优化器基类提供了计算梯度loss的方法,并可以将梯度应用于变量。优化器里包含了实现了经典的优化算法,如梯度下降和Adagrad。 优化器是提供了一个可以使用各种优化算法的接口,可以让用户直接调用一些经典的优化算法,如梯度下降法等等。优化器(optimizers)类的基类。这个类定义了在训练模型的时候添加一个操作的API。用户基本上不会直接使用这个类,但是你会用到他的子类比如GradientDescentOptimizer, AdagradOptimizer, MomentumOptimizer(tensorflow下的优化器包)等等这些算法。

推荐文章
暂无评论
暂无评论~