当前位置: 首页 > 科技观察

我有20个构建深度神经网络的“不成熟”技巧_0

时间:2023-03-18 14:25:04 科技观察

在我们的机器学习实验室,我们在许多高性能的丰富经验上训练了数千小时。在这个过程中,不仅计算机学到了很多知识,其实我们的研究人员也犯了很多错误,修复了很多漏洞。在本文中,我们将根据自己的经验(主要基于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)时神经网络会学习得更好。一般不使用learningratedecay。降低学习率在随机梯度下降(SGD)中很常见,但ADAM很自然地考虑到了这一点。如果真的想最大化模型性能,在训练结束前短时间降低学习率;您可能会看到误差突然下降,然后又会趋于平稳。如果您的卷积层有64或128个过滤器,这就足够了。特别是对于深度网络,比如说128个过滤器就很多了。如果您已经有大量过滤器,添加更多过滤器可能不会提高性能。池化是为了变换不变性。池化本质上是让网络学习图像“某一部分”的“一般概念”。例如,池化可以帮助卷积网络对图像中特征的平移、旋转和缩放具有鲁棒性。神经网络的调试如果网络的学习效果不好(意思是网络的loss/accuracy在训练的时候没有收敛,或者得不到想要的结果),可以试试下面的tips:Overfitting!如果你的网络学习不好,你应该做的第一件事就是过拟合一个训练数据点。准确率基本上应该是100%或者99.99%,或者说接近0误差。如果你的神经网络不能过拟合到一个数据点,那么模型架构可能存在严重的问题,但这个问题可能非常微妙。如果您可以过度拟合一个数据点,但在更大的数据集上训练时仍然不收敛,请尝试下面的一些建议。降低学习率。您的网络将学习得更慢,但它可能会找到使用较大步长时未找到的最小值。(直观上,你可以想象你正沿着路边穿过一条水沟,此时你想走到水沟的最深处,那里模型的误差最小。)增加学习速度。这将加快培训速度并有助于加强反馈循环。这意味着您可以快速了解您的网络是否正常工作。虽然网络应该收敛得更快,但训练结果可能不会那么好,而且这种“收敛”状态实际上可能是振荡的。(当使用ADAM优化器时,我们认为~0.001是许多实验场景的良好学习率。)减少(小)批量大小。将批量大小减少到1可以为您提供有关权重更新的更细粒度的反馈,您应该在TensorBoard(或其他调试/可视化工具)中可视化该过程。删除批量归一化层。这样做会暴露出批量大小为1时梯度消失和爆炸等问题。我们曾经遇到过一个网络几周都没有收敛,当我们移除批量归一化层(BN层)时,我们意识到第二个的输出迭代都是NaN。在这里使用批量归一化层就像在需要止血带的伤口上贴创可贴。批量归一化有其用武之地,但前提是您确定您的网络没有错误。增加(小)批处理的大小。使用更大的批量大小——如果这还不够,如果可以的话,你还不如使用整个训练集——减少梯度更新的方差,使每次迭代更加准确。换句话说,权重更新能够朝着正确的方向发展。但!它的有效性有一个上限,并且有一些物理内存限制。我们发现这个建议通常不如前两个有用(将批量大小减少到1,删除批量归一化层)。检查矩阵的重塑。大的矩阵重建(比如改变图像的X、Y维度)破坏了空间局部性,使网络更难学习,因为此时网络也必须学习重建。(自然特征变得支离破碎。自然特征表现出空间局部性的事实也是ConvNet如此有效的原因!)使用多个图像/通道进行重建时要小心;这可以使用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函数控制高方差输入值。我们希望这些基本技巧能在您更加熟悉构建深度神经网络时对您有所帮助。通常,是简单的事情让一切变得不同。【本文为栏目组织《机器之心》微信公众号《机器之心(id:almosthuman2014)》原文翻译】点击此处查看作者更多好文