机器学习的根本问题是优化和泛化之间的对立。

为了防止模型从训练数据中学到错误或无关紧要的模式, 最优解决方法是获取更多的训练数据。模型的训练数据越多,泛化能力自然也越好。如果无法获取更多数据,次优解决方法是调节模型允许存储的信息量,或对模型允许存储的信息加以约束。

这种降低过拟合的方法叫作正则化( regularization)

1. 减小网络大小

防止过拟合的最简单的方法就是减小模型大小,即减少模型中可学习参数的个数(这由层数和每层的单元个数决定)。

在深度学习中,模型中可学习参数的个数通常被称为模型的容量( capacity)。直观上来看,参数更多的模型拥有更大的记忆容量( memorization capacity),因此能够在训练样本和目标之间轻松地学会完美的字典式映射,这种映射没有任何泛化能力。 同时请记住,你使用的模型应该具有足够多的参数,以防欠拟合,即模型应避免记忆资源不足。

在容量过大与容量不足之间要找到一个折中。

一般的工作流程是开始时选择相对较少的层和参数,然后逐渐增加层的大小或增加新层,直到这种增加对验证损失的影响变得很小。

2. 添加权重正则化

奥卡姆剃刀( Occam’s razor)原理:如果一件事情有两种解释,那么最可能正确的解释就是最简单的那个,即假设更少的那个。

一种常见的降低过拟合的方法就是强制让模型权重只能取较小的值,从而限制模型的复杂度,这使得权重值的分布更加规则( regular)。这种方法叫作权重正则化( weight regularization),其实现方法是向网络损失函数中添加与较大权重值相关的成本( cost)
这个成本有两种形式:

  • L1 正则化( L1 regularization):添加的成本与权重系数的绝对值[权重的 L1 范数(norm)]成正比。
  • L2 正则化( L2 regularization):添加的成本与权重系数的平方(权重的 L2 范数)成正比。神经网络的 L2 正则化也叫权重衰减( weight decay)。不要被不同的名称搞混,权重衰减与 L2 正则化在数学上是完全相同的

在 Keras 中,添加权重正则化的方法是向层传递权重正则化项实例( weight regularizerinstance)作为关键字参数。

  1. from keras import regularizers
  2. model = models.Sequential()
  3. model.add(layers.Dense(16,
  4. kernel_regularizer=regularizers.l2(0.001),
  5. activation='relu',
  6. input_shape=(10000,)))
  7. model.add(layers.Dense(16,
  8. kernel_regularizer=regularizers.l2(0.001),
  9. activation='relu'))
  10. model.add(layers.Dense(1,
  11. activation='sigmoid'))

l2(0.001) 的意思是该层权重矩阵的每个系数都会使网络总损失增加 0.001 * weight_coefficient_value.

注意,由于这个惩罚项只在训练时添加,所以这个网络的训练损失会比测试损失大很多。

3. 添加 dropout 正则化

dropout 是神经网络最有效也最常用的正则化方法之一, 对某一层使用 dropout,就是在训练过程中随机将该层的一些输出特征舍弃(设置为 0)。假设在训练过程中,某一层对给定输入样本的返回值应该是向量 [0.2, 0.5,
1.3, 0.8, 1.1]。使用 dropout 后,这个向量会有几个随机的元素变成 0,比如 [0, 0.5, 1.3, 0, 1.1]。

dropout 比率( dropout rate)是被设为 0 的特征所占的比例,通常在 0.2~0.5 范围内。测试时没有单元被舍弃,而该层的输出值需要按 dropout 比率缩小,因为这时比训练时有更多的单元被激活,需要加以平衡。

这一方法可能看起来有些奇怪和随意。它为什么能够降低过拟合? Hinton 说他的灵感之一来自于银行的防欺诈机制。用他自己的话来说:“我去银行办理业务。柜员不停地换人,于是我问其中一人这是为什么。他说他不知道,但他们经常换来换去。我猜想, 银行工作人员要想成功欺诈银行,他们之间要互相合作才行。这让我意识到,在每个样本中随机删除不同的部分神经元,可以阻止它们的阴谋,因此可以降低过拟合。”

这种方法的核心思想是在层的输出值中引入噪声,打破不显著的偶然模式( Hinton 称之为阴谋)。如果没有噪声的话,网络将会记住这些偶然模式。

在 Keras 中,你可以通过 Dropout 层向网络中引入 dropout, dropout 将被应用于前面一层的输出。

  1. model.add(layers.Dropout(0.5))