详细解读神经网络的11种常见问题:我的神经网络不工作了!我应该做什么?

2018年06月06日 由 yining 发表 318058 0
“当你正在深入研究深度学习的下一个重大突破时,或许会遇到一个不幸的挫折:你的神经网络不起作用。你去找你的老板/主管,但他们也不知道如何去解决这个问题——他们和你一样都是新手。那么现在该怎么办呢?”

神经网络的11种常见问题

因此,这里列出了所有你可能做错的11件事情,并根据相关经验,给出解决办法:

1.你忘了使数据标准化
2.你忘记检查结果了
3.你忘了预处理数据
4.你忘了使用正则化
5.你使用的批处理太大
6.你使用的是不正确的学习率
7.你在最后层使用了错误的激活函数
8.你的网络包含了不好的梯度
9.你错误地初始化了网络权重
10.你使用的网络太深了
11.你使用了错误数量的隐藏单元




1.你忘了使数据标准化


-问题描述

当使用神经网络时,关键是要准确地思考如何使数据标准化。这是一个没有商量余地的步骤——如果你没有正确地处理这件事情,并且有些疏忽大意的话,你的网络能够工作的机会就微乎其微了。由于这一步骤在深度学习社区中是非常重要的,所以在论文中很少提及,所以几乎总是会有初学者遇到这类事情不知道怎样解决。

-如何解决?

一般的标准化意味着从你的数据中减去平均值,然后除以它的标准差。通常,这是为每个输入和输出特征单独完成的,但是你可能经常想要为特征组做或者特殊处理一些特征的标准化。

-为什么?

我们需要使数据标准化的主要原因是,神经网络管道的大多数部分假设输入和输出数据都是以标准偏差约为1和约为0的均值的来分布。
这些假设在深度学习文献中随处可见,从权重初始化,到激活函数,再到训练网络的优化算法。

-还要考虑

一个未经训练的神经网络通常输出值会在-1到1的范围内。如果你期望它的输出值在其他范围内(例如,RGB图像的字节在0到255之间),你将会遇到一些问题。当开始训练时,网络将会非常不稳定,因为当预期的值为255时,它将产生-1或1的值,这会被大多数用来训练神经网络的优化算法认为是很严重的错误。它会产生巨大的梯度,并且很可能你的训练错误会爆炸。如果没有爆炸,那么训练的前几个阶段仍然是一种浪费,因为网络学习的第一件事就是将输出值调整到它所需的范围。如果你将数据标准化(在本例中,你可以简单地除以128,然后减去1),那么这一切都不会成为问题。

一般来说,在神经网络中,特征的规模也会影响到它们的重要性。如果你在输出中有一个很大的特征,那么它将会产生比其他特性更大的错误。类似地,输入的大尺度特性将主导网络,并导致下游更大的变化。由于这个原因,许多神经网络库的自动标准化总是不够,它们盲目地减去平均值,并按每个特征值除以标准偏差。你可能有一个一般范围在0.0和0.001之间的输入特征,这个特性的范围如此之小,主要是因为它是一个不重要的特征(在这种情况下,也许你不想重新调整尺寸范围),或因为与其他特征相比它有一些小的单元(在这种情况下你可能想重新调整尺寸范围)? 类似地,要注意那些具有很小范围的特征,它们的标准偏差接近或完全为零——如果将它们标准化,这些特征将会导致NaNs的不稳定。仔细考虑这些问题是很重要的——考虑一下你的每一个特征真正代表什么,并考虑将所有输入特征的“单元”相等。这是深度学习的几个方面之一,也是一个人在循环(loop)中真正需要的。




2.你忘记检查结果了


-问题描述

你已经对你的网络进行了几次训练,你可以看到错误正在减少!这是否意味着你已经完成了训练? 不幸的是——几乎可以肯定的告诉你,你的代码仍然有问题。它可能是数据预处理、训练代码,甚至是推断的bug。仅仅因为错误的减少并不意味着你的网络正在学习任何有用的东西。

-如何解决?

在管道的每个阶段检查数据看起来都是正确的,这是非常重要的。通常这意味着要找到一些方法来可视化结果。如果你有图像数据,那么它很容易——动画数据也可以被可视化,不会有太多的麻烦。如果是一些其他比较奇特的数据,你必须找到一种方法来检查它,以确保它在你的预处理、训练和推断管道的每个阶段都是正确的,并将它与地面实况(ground truth)数据进行比较。

-为什么?

与传统的编程不同,机器学习系统在几乎所有情况下都会悄无声息地失败。在传统编程的情况下,我们习惯了计算机在出错时抛出错误,并将其作为信号返回并检查错误。不幸的是这一过程与机器学习应用程序是不能工作的,所以我们应该非常小心检查我们在每个阶段的过程,这样我们就会知道,当一个错误已经产生时,我们就需要回去更彻底地检查代码。

-还要考虑

有很多方法可以检查你的网络是否正常工作。其中的一部分是找出报告的训练错误到底意味着什么。将你的网络的结果应用到训练集的数据中——你的网络的结果如何与实践中的地面实况相比较? 你可能会在训练期间将错误从100到降低至1,但是如果1的错误仍然是不可接受的结果,那么结果仍然是不可用的。如果它在训练集上对验证集进行检查,它是否仍然适用于以前没有见过的数据? 我的建议是从一开始去适应可视化,不要只有当你的网络不工作时才开始适应,这样就能确保在你开始尝试不同的神经网络结构时,你已经检查了完整的流程。这是你能准确评估多种不同方法的唯一方式。




3.你忘了预处理数据


-问题描述

大多数数据都是复杂的,而且我们所知道的相似的数据通常都有非常不同的数字表示形式。以角色动画(character animation)为例:如果我们使用相对于运动捕捉的studio中心的3D位置的角色关节来表示数据,那么在某个位置或面向某个方向执行动作时,相较于在不同的位置、或不同的方向执行同一个动作,可能会产生大量不同的数字表示我们需要做的是用不同的方式来表示数据——例如,在一些局部的参考框架中(比如相对于字符的质心),这样我们所知道的两种运动都能得到相似的数值表示。

-如何解决?

想一下你的特征是什么——是否有一些简单的转换,你可以对它们做一些简单的转换,以确保我们所知道的事物的数据点总是得到相似的数值表示? 是否有一个本地的坐标系统,可以用它来自然地表示你的数据?

-为什么?

神经网络对数据输入,只做出了几个基本假设,但这些基本假设之一是空间数据是有些连续的——大部分的空间,两个数据点之间的点至少是有点“混合”的,这两个相邻的数据点在某种意义上代表“相似”的事情。在数据空间中存在较大的不连续性,或者是表示同一事物的大量分离数据(separated data),这将使学习任务变得更加困难。

-还要考虑

另一种考虑数据预处理的方法是尝试减少可能需要的数据变化的组合爆炸。例如,如果一个训练了角色动画数据的神经网络必须在每个位置和方向上学习相同的动作,那么网络的很多能力就被浪费了,很多学习过程都被重复了。




4.你忘了使用正则化


-问题描述

正则化通常以dropout、noise或网络随机过程的某种形式为主,这是训练现代神经网络的另一个不可改变的方面。即使你认为你的数据比参数多得多,或者你在某些情况下认为过度拟合并不重要,或者看起来不可能,你仍然应该增加dropout或其他形式的noise。

-如何解决?

使神经网络正则化的最基本的方法是在你的网络中每一个线性层(卷积或密集)前添加一个dropout。从中等到高等的保留概率,例如0.75或0.9。根据你认为过度拟合的可能性进行调整。如果你仍然认为过度拟合是不可能的,那么将保留概率设置为非常高的数字,比如0.99。

-为什么?

正则化并不仅仅是控制过度拟合。通过在训练过程中引入一些随机过程,你在某种意义上“平滑”了cost landscape。这可以加速训练,帮助处理数据中的异常值,并防止网络的极端权重配置。

-还要考虑

数据增加或其他类型的noise也可以像dropout一样进行正则化。常见的dropout的预测技术结合了许多随机子网,dropout也可以被视为通过在训练过程中产生许多类似输入数据的变化来动态地扩展训练集大小的方法。正如我们所知道的,避免过度拟合和提高网络准确度的最好方法就是拥有更多的数据,从而确保神经网络不会两次碰到相同的错误!




5.你使用的批处理太大


-问题描述

使用过大的批处理会对你的网络的准确性产生负面影响,因为它减少了梯度下降的过程。

-如何解决?

找到你可以忍受训练的时间的最小的批处理。最适合使用GPU并行度的批处理大小可能不是最好的,因为在某种程度上,更大的批处理将需要对网络进行更多的训练,以达到同样的精度。不要害怕从很小的批处理开始训练,比如16、8、甚至是1。

-为什么?

使用越小的批处理,会产生越多的随机权重更新。这可以有两个积极的效果。首先,它可以帮助训练“跳出”原本可能被卡住的局部极小值,其次它可以使训练在“更平坦”的最小值中得到满足,这通常意味着更好的泛化性能。

-还要考虑

数据中的其他一些元素有时可以有效地充当批处理大小。例如,处理图像的分辨率是以前的两倍,会产生把批处理大小×4的效果。为了对此进行直观的理解,请考虑在CNN中,每一个过滤器的权重更新将被平均用于输入图像的所有像素,以及在批处理中的每一个图像。如果将批处理大小增加4倍,那么图像分辨率会提高2倍,将产生4倍像素以上的平均效果。总的来说,重要的是要考虑在每次迭代中,最终的梯度更新将会被平均多少,并且确保你平衡了与使用尽可能多的GPU的潜在并行性所带来的不利影响。




6.你使用的是不正确的学习率


-问题描述

学习速率会对训练你的网络有很大的影响,如果你是新手,几乎可以肯定的是,常见的深度学习框架中使用的各种默认选项会使你不能正确地设置它。

-如何解决?

把梯度剪裁(gradient clipping)关掉。找到在训练时不会发生错误的最高的学习率的值。把学习速率设得比这个低一点——这可能接近于最佳的学习速率。

-为什么?

许多深度学习框架在默认情况下开启了梯度裁剪。这个选项可以防止在训练过程中最优化,通过执行一个最大的数量,权重在每一个步骤中都可以改变。这可能是有用的,特别是如果你的数据包含许多异常值,这些异常会产生较大的错误,从而导致大量的梯度和权重更新,但是在默认情况下,它也会使你很难找到最佳的学习速率。大多数初入深度学习的人的学习速率都设置的太高了,并且在梯度剪裁方面也有这样的考虑,使得整体的训练行为变慢,而改变学习率的影响是不可预测的。

-还要考虑

如果你已经正确地清洗了数据,删除了大部分的异常值,并且正确地设置了学习速率,那么你就不需要进行梯度裁剪了。如果没有它,你会发现你的训练错误偶尔会突然爆炸。你的训练错误正在爆发的原因几乎总是表明你有一些错误的数据——而裁剪只是一个临时的修正办法,不能总是有效。




7.你在最后层使用了错误的激活函数


-问题描述

在最后层使用激活函数有时意味着你的网络不能生成所需值的全部范围。最常见的错误是在最后层使用ReLU,导致网络只能产生正值作为输出。

-如何解决?

如果你正在进行回归,那么大多数情况下,你不希望在最后层使用任何类型的激活函数,除非你知道某些特定于你希望生成的值作为输出值。

-为什么?

再考虑一下数据值实际代表什么,以及它们在标准化之后的范围。最可能的情况是你的输出值是无限的正数或负数——在这种情况下,你不应该在最后层使用激活函数。如果你的输出值在某些范围内可能是有意义的,例如,它由0-1范围内的概率组成,那么很有可能是一个特定的激活函数,例如一个S型的激活函数。

-还要考虑

在最后层使用激活函数有很多微妙之用。也许你知道你的系统最终会将输出裁剪到[-1,1],这是由神经网络产生的。然后,将这个裁剪过程添加为最后层激活似乎是有意义的,因为这将确保你的网络错误函数不会对大于1或小于-1的值进行惩罚。但是,没有任何错误意味着这些值的值不会大于1或小于-1,在某些情况下,这些值将使你的网络不可能进行训练。或者你可能想在最后层使用tanh,因为这个激活函数输出值范围为[-1, 1],但是这可能会导致问题,这个函数的梯度在1或-1范围附近变得很小,而为了产生-1或1可能使你的权重变得非常大。一般来说,保险起见,在最后层不要使用任何激活函数。




8.你的网络包含了不好的梯度


-问题描述

使用ReLU激活函数的深层网络通常会受到所谓的“死神经元”的影响,这种“死神经元”是由不好的梯度引起的。这可能会对网络的性能产生负面影响,或者在某些情况下使其完全不可能进行训练。

-如何解决?

如果你发现你的训练错误并没有随着时间的改变而改变,那可能是因为你的所有神经元都因为使用了相关的激活函数而死亡。
试着切换到另一个激活函数,如leaky ReLU或ELU,看看是否会发生同样的事情。

-为什么?

ReLU激活函数的梯度对于正值为1,对于负值为0。这是因为当输入小于0时,输入的一个很小变化不会影响输出。由于正值的梯度很大,这似乎不是一个问题,但是,层与层是可以叠在一起的,负的权重可以将那些梯度很大的正值变为梯度为0的负值。通常来说,无论输入是什么,一部分甚至所有隐藏单元对于成本函数都具有零梯度。在这种情况下,我们说网络已经“死了”,因为权重完全无法更新。

-还要考虑

任何具有零梯度的操作,如剪裁、舍入或取最大值/最小值,如果它们被用于计算成本函数对权值的导数,也会产生不好的梯度。如果它们出现在你的符号图中的任何地方,都要非常小心,因为它们通常会导致无法预料的困难,例如,如果它们被用于作为成本函数的一部分会提供自定义的错误度量。




9.你错误地初始化了网络权重


-问题描述

如果你没有正确地初始化你的神经网络权重,那么你的神经网络根本就不可能训练。神经网络中的许多其他组件都假设了某种形式的正确或标准化的权重初始化,并将权重设置为零,使用自定义的随机初始化是不可行的。

-如何解决?

“he”,“lecun”或“xavier”的权重初始化都是很受欢迎的选择,在任何情况下都能很好地发挥作用。在它们三个中选择一个(我最喜欢的是“lecun”),一旦你的神经网络开始运作,你就可以自由地尝试,直到你找到最适合你的任务。

-为什么?

你可能听说过你可以用“小随机数”来初始化神经网络的权重,但这并不是那么简单。以上所有的初始化都是用复杂和详细的数学方法发现的,这就解释了为什么它们是最优的。更重要的是,其他的神经网络组件已经建立在这些初始化的基础上,并在经验上使用它们——使用你自己的初始化可能会使其他研究人员的结果复现变得更加困难。

-还要考虑

其他层可能也需要小心地初始化。网络偏差被初始化为0,而其他更复杂的层,比如参数化激活函数,可能会有它们自己的初始化,这对于获得正确结果来说同样重要。




10.你使用的网络太深了


-问题描述

更深层次的网络是更好的对吧? 其实也不一定……。当我们拼命刷新基准,把某些任务的精度提升1%时,更深的神经网络一般来说更好。但是如果你的3,4,5层小网络都没有学到任何东西的话,那么我可以向你保证,你使用一个100层的网络也会失败。

-如何解决?

从一个有3到8层的浅层神经网络开始训练。只有当你已经有了良好的工作,并且开始研究如何提高准确度时,再开始尝试更深入的网络。

-为什么?

虽然看起来似乎是这样,但当有人决定将数百层叠起来的时候,神经网络并不是突然就开始有了突破性的结果。过去十年来研究的神经网络的所有改进都是微小的、最根本性的变化,这些变化同样适用于小型网络的性能。如果你的网络不能正常工作,那么除了深度以外,其他的事情更有可能是错误的。

-还要考虑

从小的网络开始也意味着训练你的网络将会更快,推断将会更快,并且在不同的设计和设置上迭代也会更快。一开始,所有这些都会对你的准确性产生更大的影响,而不是简单地叠加几层。




11.你使用了错误数量的隐藏单元


-问题描述

在某些情况下,使用太多或太少的隐藏单元会使你的网络难以进行训练。太少的单元可能没有能力来表达所需要的任务,而太多的单元可能会变得缓慢而难以训练,无法用残余noise清除。

-如何解决?

从256到1024个隐藏单元开始。然后,看看那些研究类似应用程序的人们所使用的数据,并将其作为灵感。如果其他研究人员使用的数字与上面给出的数字大不相同,那么可能会有一些特定的原因解释。

-为什么?

在决定隐藏单元数量时,要考虑的是,你认为可能是表达你希望通过网络的信息所需要的真实值的最少数量。你应该把这个数字放大一点。对于使用更多冗余表示的网络,dropout可以。如果你正在进行分类,可能会使用5到10倍的类作为一个良好的初始猜测,而如果你正在进行回归,那么你可能会使用2到3倍数量的输入或输出变量。当然,所有这些都是高度依赖于环境的,并且没有简单的自动解决方案——拥有好的直觉仍然是决定隐藏单元数量的最重要的因素。

-还要考虑

实际上,与其他因素相比,隐藏单元的数量对神经网络的性能有很大的影响,在许多情况下,高估隐藏单元的数量除了使训练速度变慢以外将不会产生什么负面影响。一旦你的网络工作了,如果你还在担心,那就试试一大堆不同的数字,然后测量它的准确性,直到找到你认为最有效的那个。
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
写评论取消
回复取消