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

这些深度学习的坑你都遇到过吗?神经网络的11个常见陷阱及应对方法

时间:2023-03-22 17:00:50 科技观察

如果你的神经网络不起作用怎么办?本文作者列出了构建神经网络时可能遇到的11个常见问题,包括预处理数据、正则化、学习率、激活函数、网络权重设置等,并提供了解决方案和解释,是深度学习的有用资料学习实践。如果你的神经网络不起作用怎么办?作者在这里列出了构建神经网络时可能做错的所有事情,以及他自己解决这些问题的经验。忘记规范化数据忘记检查结果网络太深使用错误数量的隐藏单元忘记规范化数据问题描述使用神经网络时,考虑如何正确规范化数据非常重要。这是一个无法更改的步骤-如果这一步没有仔细和正确地完成,您的网络将几乎无法工作。由于这一步在深度学习社区如此重要和众所周知,论文中很少提及,因此初学者经常在这一步出错。如何解决?通常,归一化意味着:从数据中减去均值并除以其方差。通常这是针对每个输入和输出特征单独完成的,但您可能经常希望对特征组或特定特征进行归一化。为什么?我们需要对数据进行归一化的主要原因是大多数神经网络管道假设输入和输出数据的分布标准偏差约为1,均值约为0。这些假设在深度学习文献中无处不在,从权重初始化和激活函数以优化训练网络的算法。另请注意,未经训练的神经网络通常会输出大约-1到1范围内的值。如果要输出其他范围内的值(例如RBG图像以0-255范围内的字节存储)会有会有些问题。在训练开始时,网络会非常不稳定,因为,例如,期望值为255,而网络产生的值为-1或1-这将被用于训练神经网络的大多数优化算法视为严重错误网络。这会产生过大的梯度,可能导致梯度爆炸。如果它没有爆炸,那么前几个阶段的训练就被浪费了,因为网络首先学会了将输出值缩小到大致预期的范围。如果您对数据进行标准化(在这种情况下,您可以简单地将值除以128再减去1),这些问题就不会发生。通常,神经网络中特征的规模也决定了它的重要性。如果输出中的某个特征尺寸较大,则与其他特征相比,它会产生更大的误差。同样,输入中的大规模特征将主导网络并导致下游发生更大的变化。因此,使用基于每个特征盲目减去均值并除以方差的神经网络库进行自动归一化通常是不够的。你可能有一个输入特征,通常在0.0到0.001的范围内——这个特征有这么小的范围是因为它是一个不重要的特征(在这种情况下你可能不想重新缩放),或者因为其他特征有一些与它相比小单位(在这种情况下你可能想重新调整)?同样,要小心那些范围很小以至于方差接近或等于0的特征,如果对它们进行归一化,会导致NaN不稳定。仔细考虑这些问题很重要——考虑你的每个特征真正代表什么,并均衡所有输入特征的“单位”,将这个过程视为规范化。这是我认为深度学习的人在这个循环中真正需要的几个方面之一。您忘记检查结果问题描述您已经对网络进行了几个时期的训练,发现错误正在减少。这是否意味着它完成了?很遗憾地告诉您,您的代码几乎肯定有问题。数据预处理、训练代码甚至推理都可能存在错误。仅仅因为错误率下降并不意味着您的网络正在学习有用的东西。如何?在流程的每个阶段检查数据是否正确非常重要。通常,您需要找到一些方法来可视化结果。如果是图像数据,那就简单了,动画数据不需要太多的可视化麻烦。但是对于其他类型的数据,你必须找到一种方法来检查结果,以确保每个过程在预处理、训练和推理中都是正确的,并将结果与??groundtruth数据进行比较。为什么?与传统编程不同,机器学习系统几乎在所有情况下都会悄无声息地失败。在传统的编程过程中,我们习惯于计算机在发生错误时抛出错误,并将其作为检查错误的信号返回。不幸的是,这个过程不适合机器学习,所以我们应该非常小心,在每个阶段都用人眼检查这个过程,知道什么时候有错误,什么时候我们需要回过头来更彻底地检查代码。另请注意,有许多方法可以检查网络是否正常工作。该方法的一部分是准确说明报告的训练错误的含义。将网络应用于训练集的结果可视化——你的网络结果与实践中的真实情况相比如何?你可能会在训练过程中将错误从100降低到1,但如果1的错误仍然是不可接受的结果,那么该结果仍然无法使用。如果网络在训练集上工作,检查验证集——它是否仍然在以前没有见过的数据上工作?我的建议是从一开始就习惯于可视化一切——不要只是在网络不工作时才这样做可视化——确保在开始尝试不同的神经网络架构之前检查完整的管道。这是准确评估某些潜在不同方法的唯一方法。您忘记了对数据进行预处理问题描述大多数数据都是棘手的-通常我们知道的数据是相似的,并且可以用非常不同的数字表示。以角色动画为例:如果我们用角色关节相对于动作捕捉工作室中心的3D位置来表示数据,那么在某个位置或面向某个方向执行动作会比执行动作更容易一个动作在不同的位置,或不同的方向执行相同的动作,可能会产生大量不同的数字表示。然后我们需要以不同的方式表示数据-例如在一些局部参考系中(例如相对于角色的质心),以便相似的动作具有相似的数值表示。如何?想想你的特征代表什么——是否有一些简单的转换来确保代表相似事物的数据点总是得到相似的数字表示?是否有更自然地表示数据的局部坐标系-也许是更好的色彩空间-不同的格式?为什么?对于作为输入的数据,神经网络只做了一些基本的假设,其中之一就是数据所在的空间是连续的——对于大多数空间来说,两个数据之间的点之间至少存在一些“混合”点,相邻的两个数据点在某种意义上代表着“相似”的事物。数据空间中存在大的不连续性,或者代表同一事物的大量分离数据,将使学习任务更加困难。另一种也需要注意数据预处理的方法是尝试减少所需数据更改的组合爆炸。例如,如果在角色动画数据上训练的神经网络必须在每个位置和每个方向上学习相同的动作组合,那么就会浪费大量网络容量并且重复大部分学习过程。忘记使用正则化问题描述正则化——通常以某种形式的丢失、噪声或网络随机化——是训练神经网络的另一个不可改变的方面。即使你认为你的数据比参数多得多,或者过拟合不重要,或者没有发生过拟合的情况,你仍然应该添加dropout或其他形式的噪声。如何?正则化神经网络的最基本方法是在网络的每个线性层(卷积层或密集层)之前添加dropout。从中高保留概率开始,例如0.75或0.9。针对过度拟合的可能性进行了调整。如果还是觉得不可能过拟合,可以把retentionprobability设置的很高,比如0.99。为什么?正则化不仅仅是控制过度拟合。通过在训练过程中引入一些随机过程,您在某种意义上“平滑”了损失模式。这加快了训练速度,有助于处理数据中的异常值,并防止网络的极端权重配置。另请注意,数据增强(dataaugmentation)或其他类型的噪声也可以像dropout一样用作正则化方法。虽然dropout通常被认为是一种结合有序偶数随机子网络的预测的技术,但dropout也可以被认为是一种通过在训练期间对输入数据产生许多类似的变化来动态扩展训练集大小的方法.而且我们知道,避免过度拟合和提高网络准确度的最佳方法是拥有更多网络未见过的数据。TheBatchusedistoolarge问题描述使用太大的batch可能会对网络在训练过程中的准确性产生负面影响,因为它会降低梯度下降的随机性。如何解决?找到您在训练期间可以接受的最小批次。在训练时最大化GPU并行性的批处理大小可能不是准确性的最佳选择,因为在某些时候,更大的批处理需要更多的epoch才能达到相同的准确性。不要担心从16、8甚至1等非常小的批次开始。为什么?使用较小的批次会产生更方便(更不稳定)和更随机的权重更新。这样做有两大优势。首先,它可以帮助训练“跳出”可能卡住的局部最小值;其次,它可以使训练以“更平坦”的最小值结束,这通常代表更好的泛化性能。还值得注意的是,数据的其他元素有时会像批量大小一样发挥作用。例如,在处理图像时,将分辨率加倍可能会产生与将批量大小乘以4类似的效果。直观地,在CNN中,每个滤波器的权重更新将对输入图像的所有像素以及每个图像进行平均在批次中。将图像分辨率加倍将产生超过四倍像素的平均效果,就像将批量大小加倍四倍一样。总之,重要的是要考虑每次迭代中最终梯度更新的平均程度,并通过尽可能多地利用GPU并行性来平衡负面影响。学习率不正确问题描述学习率对网络训练的效果有很大影响。如果你是新手,受常见深度学习框架各种默认选项的影响,几乎可以肯定是你没有正确设置学习率。如何解决?关闭渐变剪裁。找到训练时不会出错的最高学习率值。然后将学习率设置为比该值低一点——这可能非常接近最佳学习率。为什么?许多深度学习框架默认启用梯度裁剪。这个选项可以防止在训练过程中过度优化,它会强制权重在每一步都发生变化,让权重尽可能多地变化。这可能很有用,尤其是当数据包含许多离群值时,因为离群值会产生很大的错误,从而导致较大的梯度和权重更新。但是,默认启用此选项也使用户难以手动找到最佳学习率。我发现大多数深度学习的新手都会因为梯度裁剪而将学习率设置得太高,这会减慢整体训练行为并使改变学习率的效果不可预测。另请注意,如果您正确清理数据,删除大多数离群值并正确设置学习率,那么您实际上不需要梯度裁剪。关闭梯度裁剪后,如果你发现训练错误偶尔会爆发,那么你可以重新打开这个选项。然而,重要的是要记住,频繁训练错误的原因几乎总是表明数据中存在其他一些异常——裁剪只是一种临时补救措施。在最后一层使用错误的激活函数问题描述在最后一层使用激活函数有时可能意味着你的网络无法产生它需要的全部范围的值。最常见的错误是在最后一层使用ReLU,导致网络只输出正值。如何?如果你在做回归,那么大多数时候你不想在最后一层使用任何一种激活函数,除非你确切地知道你想要输出什么样的值。为什么?再想想你的数据值实际代表什么,以及它们的标准化范围。最有可能的是,你的输出值是无界的正数或负数——在这种情况下你不应该在最后一层使用激活函数。如果你的输出值只在一定范围内有意义,比如由0-1内的概率组成,那么最后一层应该有特定的激活函数,比如Sigmoid激活函数。另请注意,在最后一层使用激活函数有许多注意事项。也许您知道您的系统最终会将输出裁剪为[-1,1]。然后将这个裁剪过程添加到最后一层的激活中是有意义的,因为这将确保你的网络的误差函数不会惩罚大于1或小于-1的值。然而,没有错误也意味着这些大于1或小于-1的值也将没有梯度——这在某些情况下会使你的网络无法训练。或者,你可能会尝试在最后一层使用tanh,因为激活函数输出的值在[-1,1]范围内,但这也会导致问题,因为这个函数的梯度在1或-1附近变化.非常小,并且产生-1或1可能会使您的权重非常大。一般来说,最好谨慎行事,不要在最后一层使用激活函数。有时候聪明被聪明误导了。网络中的不良梯度问题描述使用ReLU激活函数的深度网络经常遭受不良梯度引起的所谓“死亡神经元”的困扰。这会对网络性能产生负面影响,在某些情况下甚至根本无法进行训练。如何解决?如果发现经过多个epoch后训练误差没有变化,可能是使用了ReLU激活函数让所有神经元死亡。尝试切换到另一个激活函数,例如leakyReLU或ELU,看看情况是否仍然如此。为什么?ReLU激活函数的梯度对于正值是1,对于负值是0。这是因为当输入小于0时,输入的微小变化不会影响输出。在短期内,这可能不是问题,因为正值的梯度很大。但是层可以层层叠叠,负权重可以把那些梯度大的正值变成梯度为零的负值;通常,一些甚至所有隐藏单元的成本函数梯度为零,无论输入是什么。在这种情况下,我们说网络“死了”,因为权重根本无法更新。另请注意,任何梯度为零的操作(例如裁剪、舍入或最大/最小值)在用于计算成本函数相对于权重的导数时都会产生不良梯度。如果它们出现在符号图中,请务必小心,因为它们通常会导致意想不到的问题。未正确初始化网络权重问题描述如果您未正确初始化神经网络权重,则神经网络根本不可能进行训练。神经网络中的许多其他组件都有一些正确或标准化的权重初始化,将权重设置为零或使用您自己的自定义随机初始化不起作用。如何?“he”、“lecun”或“xavier”的权重初始化都是流行的选择,几乎在所有情况下都能很好地工作。只需选择一个(我最喜欢的是“lecun”),当你的神经网络正常工作时,你就可以自由地进行实验了。为什么?您可能已经知道可以使用“小随机数”来初始化神经网络权重,但事情并没有那么简单。所有上述初始化都是使用复杂而详细的数学发现的,这些数学解释了为什么它们最有效。更重要的是,围绕这些初始化构建其他神经网络组件并根据经验对它们进行测试——使用您自己的初始化可能会使重现其他研究人员的结果变得更加困难。另请注意,其他层可能也需要仔细初始化。同样重要的是要做到这一点,因为网络偏差被初始化为零,而其他更复杂的层(例如参数激活函数)可能会进行自己的初始化。您是否使用了太深的问题描述?好吧,情况并非总是如此……当我们拼命试图击败基准并将某些任务的准确性提高1%、1%时,更深层次的神经网络通常会说得更好。但是,如果你有一个只有3~5层的小型网络,什么也学不到,那么我可以保证你在100层时会失败,如果不是更糟的话。如何?从3到8层的浅层神经网络开始。只有在你的神经网络开始运行并学习东西之后,然后探索提高准确性的方法并尝试加深网络。为什么?过去十年神经网络的所有改进都是小的根本性变化,仅适用于作为深层性能的较小网络。如果您的网络无法正常工作,则更有可能是深度以外的问题。另请注意,从小型网络开始意味着更快的训练、更快的推理以及更快地迭代不同的设计和设置。最初,所有这些都会对准确性产生比仅仅堆叠几层更大的影响。问题描述使用了错误数量的隐藏单元在某些情况下,使用过多或过少的隐藏单元(hiddenunits)都会使网络难以训练。隐藏单元太少,可能无法表达想要的任务,而隐藏单元太多,则可能变得缓慢且难以训练,残留噪声难以去除。如何?从256到1024个隐藏单元开始。然后,看看其他类似应用的研究使用了多少,并参考使用情况。如果其他研究人员使用的数字与您使用的数字非常不同,则可能需要一些特定的原因。为什么?在决定隐藏单元的数量时,关键是要考虑您认为向网络传递信息所必需的真值的最小数量。你应该使这个数字更大。对于使用更多冗余表示的网络,dropout很好。如果你在做分类,你可以使用五到十倍的类数,如果你在做回归,你可能需要使用两到三倍的输入或输出变量的数量。当然,所有这些都高度依赖于上下文,并且没有简单的自动解决方案-拥有良好的直觉对于决定隐藏单元的数量至关重要。同样值得注意的是,在实践中,与其他因素相比,隐藏单元的数量通常对神经网络性能的影响很小,而且在许多情况下,高估所需的隐藏单元数量不会减慢训练速度。一旦您的网络开始工作,如果您仍然担心,只需尝试许多不同的数字并测量准确性,直到找到最适合您的网络的数字。