过拟合与正则化
🎙️ Alfredo Canziani过拟合(Overfitting)
当我们考虑一个回归问题时,一个模型可以欠拟合,正好拟合,或者过拟合。
如果一个模型无法充分表达数据,那么它将会欠拟合。如果一个模型过度表达了数据(比如使用深度神经网络),那么它将会承受过拟合的风险。
在这种情况下,一个模型会强大到可以同时拟合原始训练数据以及 训练数据中的噪声,最后在真实任务中表现较差。
在理想情况下,我们希望我们的模型拟合数据而非噪声,从而得到一个良好的拟合结果。我们还特别希望可以达到这个目标而不损失模型的表达能力。深度学习模型十分强大,而它常常会比学习数据所实际需要的模型强大很多。我们希望可以保持这种表达能力(而能更容易训练),但也希望网络能够对抗过拟合。
通过过拟合检查错误
过拟合在有些情况下十分有用,比如在查错的过程中。我们可以在一小部分训练数据上(即使只是一个批次或者一些随机噪音张量)训练一个网络,从而确认这个网络可以过拟合这些数据。如果网络无法学习到这些数据的特点,那么这就是一个网络中可能存在错误的信号。
正则化 (Regularization)
我们尝试通过引入正则化来对抗过拟合。正则化的程度会影响到模型在验证数据集上的表现。过小的正则化会无法解决过拟合的问题,而过大的正则化会导致模型没有那么有效。
正则化 给模型添加了先验知识,一个对于参数的先验分布。它可以限制可能学到的表达函数。
另一个来自Ian Goodfellow的正则化的定义:
正则化是一项可以使我们减少泛化误差而非训练误差的修正。
初始化方法
我们可以通过根据特定分布初始化网络权重,从为我们的网络参数选择一个先验。其中以一种选项: Xavier 优化
权重衰减正则化 (Weight Decay Regularization)
权重衰减是我们的第一种正则化技术。权重衰减在机器学习领域广泛应用,但在神经网络中的应用相对较少。在PyTorch中,权重修改是优化器的一个参数。(比如SGD中的weight_decay
参数)。
这又被成为:
- L2
- Ridge
-
高斯先验
我们可以考虑带参数的目标函数
\[J_{\text{train}}(\theta) = J^{\text{old}}_{\text{train}}(\theta)\]然后我们更新参数
\[\theta \gets \theta - \eta \nabla_{\theta} J^{\text{old}}_{\text{train}}(\theta)\]我们添加了一个惩罚项以实现权重衰减:
\[J_{\text{train}}(\theta) = J^{\text{old}}_{\text{train}}(\theta) + \underbrace{\frac\lambda2 {\lVert\theta\rVert}_2^2}_{\text{penalty}}\]它也产生了一个更新量
\[\theta \gets \theta - \eta \nabla_{\theta} J^{\text{old}}_{\text{train}}(\theta) - \underbrace{\eta\lambda\theta}_{\text{decay}}\]新添加的项通过在每次更新中引入一些权重的“衰减”使得参数 $\theta$ 略微更趋近 $0$。
L1 正则化
在PyTorch optimizers 中,这是一个可用的选项。
也可以被称作:
-
LASSO: 最小绝对值收敛和选择算子
-
Laplacian先验
-
稀疏先验
我们可以把看作一个Laplace分布先验,这种正则化比高斯分布能使更多的概率质量分布于 $0$ 附近。
我们可以从上述(权重衰减正则化)的更新步骤开始,并将这个步骤视为添加另一个惩罚项。
\[J_{\text{train}}(\theta) = J^{\text{old}}_{\text{train}}(\theta) + \underbrace{\lambda{\lVert\theta\rVert}_1}_{\text{penalty}}\]它会产生一个更新量。
\[\theta \gets \theta - \eta \nabla_{\theta} J^{\text{old}}_{\text{train}}(\theta) - \underbrace{\eta\lambda\cdot\mathrm{sign}(\theta)}_{\text{penalty}}\]不同于 $L_2$ 权重衰减,$L_1$ 正则化会“清除”靠近参数空间的轴的部分, 而非只是减少参数向量的长度。
Dropout
Dropout会在训练过程中随机置零一部分神经元,这样可以防止网络只学习到一条从输入到输出的路径。相似的,由于神经网络的庞大参数两,神经网络有可能会有效地“记住”输入。然后,Dropout使得“记住”输入变得更难,因为Dropout使每次训练的网络都不一样。因此,Dropout可以有效地控制过拟合,并且对于输入中的微小扰动更加鲁棒。
图 1: 不采用Dropout的网络
图 2: 采用Dropout的网络
在PyTorch中,我们可以为神经元设置一个随机Dropout率。
图 3: Dropout 代码
在训练之后,Dropout不会在推理阶段使用。为了获得一个完整的可推理的网络,我们对所有采用了Dropout的网络取平均。我们可以简单地对所有权重乘以 $1/1-p$ , 其中 $p$ 是Dropout率。
早停法
在训练过程中,如果验证损失开始增加,我们可以停止训练并且使用已经发现的最好的权重。这样可以防止权重过多增长以至于在某一时刻开始影响验证结果。在实践中,一般根据特定的间隔时间来计算验证结果,并在一定迭代次数内验证误差都停止继续下降的情况下终止训练。
图 4: 早停法(Early stopping)
间接防止过拟合
还存在一些其他非正则化的技术可以间接起到对参数正则化的作用。
批量归一化
提问:批量归一化是如何使训练更有效的?
回答:当采用批量归一化时,我们可以使用更高的学习率。
批量归一化被用于防止神经网络的内部协变量漂移,但学界也存在很多关于它是否真的达成了这点以及它的真正好处是什么的争辩。
图 5: 批量归一化(Batch normalization)
批量归一化将归一化网络输入的理念扩展到了归一化网络中每一隐藏层的输入。这背后基本的想法是:因为固定的概率分布可以有更好的学习效果,所以我们希望网络的每一层输入都有固定的概率分布。为了达到这个目标,我们在遇到每一隐藏层前都计算当前数据流的平均值和方差,并根据这一批次特定的统计数据归一化这一批次的输入数据。这样就可以在训练阶段减少数据最终的漂移量。
关于正则化的效果,由于每一批次的数据都不同,每一个样本都会根据它所在的批次被略微不同的统计数据归一化。因此,网络最终会遇到同一个输入的略微不同的多个版本。这样的操作帮助网络对于输入的轻微改变更加鲁邦,并且可以防止过拟合。
批量归一化的另一个好处是可以使训练快很多。
更多数据
获得更多的数据是一种简单的防止过拟合的方法,但是这种方法过于昂贵或是不太可行。
数据增强
使用Torchvision对输入数据进行变换可以通过教网络学到如何对扰动不敏感,从而起到正则化的作用。
图 6: 使用Torchvision进行数据增强
迁移学习 (TF) 微调 (FT)
迁移学习指只训练预训练网络最顶层的分类器。(一般用于只有较少数据的情况下)
迁移学习也指只训练预训练网络的部分或全部结构。(一般用于拥有很多数据的情况下)
提问:一般来说,我们什么时候应该冻结预训练网络的网络层?
回答:如果我们只有很少的训练数据。
四种一般情况:
1)如果我们有很少的数据,它们具有相似的分布,我们可以只进行迁移学习。
2)如果我们有很多的数据,它们具有相似的分布,我们可以进行微调从而也提升特征提取模块的性能。
3)如果我们有很少的数据,它们具有不同的分布,我们应该从特征提取模块删除最后一些已训练的网络层,因为它们都过于针对预训练数据了。
4)如果我们有很多的数据,它们具有不同的分布,我们可以直接训练全部的网络。
注意,对于不同的网络层我们应该采用不同的学习率以提升性能。
让我们来看看下图的可视化结果以延伸我们关于过拟合和正则化的讨论。这些可视化由Notebook中的代码生成。

图 7: 不采用Dropout的损失函数曲线

图 8: 采用Dropout的损失函数曲线

图 9: 正则化对权重的效果
从图7和图8, 我们可以裂解Dropout对于泛化误差的巨大影戏,其中泛化误差指的是训练损失函数和验证损失函数之间的差别。在图7中,在没有Dropout的情况下存在很明显的过拟合,训练损失函数远低于验证损失函数。然后,在图8中,在有Dropout的情况下,训练损失函数和验证损失函数几乎持续地保持重合。这代表着模型在代表着不包含训练数据的集合的验证集上泛化良好。
在图9中,我们对(L1和L2)正则化对于网络模型权重的影响进行观察。
-
当我们采用L1正则化时,从零位置的红色峰,我们可以发现大多数权重为零 。在靠近零处的一些小红点是模型的非零权重。
-
相反的,在L2正则化中,从靠近零处的紫峰我们可以看出大多数的权重靠近零而非零。
-
当未采用正则化(蓝)时,权重分布更加灵活,并且在零位置附近散布形成正态分布。
贝叶斯神经网络:估计预测值的不确定度
我们关心神经网络中的不确定性,因为网络需要知道它对于预测结果的确信度。
例子:如果你搭建了一个神经网络以预测汽车的转向控制量,你需要知道网络的预测有多可靠。
我们可以训练一个带有Dropout的神经网络来获得我们的预测值附近的置信范围。让我们来训练一个带有Dropout的网络,$r$ 是Dropout率。
通常,在推理过程中,我们会将网络设置为验证模式并使用所有的神经元来得到最终的预测结果。在预测的过程中,我们将权重 $\delta$ 乘上 $\dfrac{1}{1-r}$ 以抵消训练过程中丢弃神经元带来的影响。
这种方法可以对于每一个输入给予我们一个单独的预测值。然而,为了获得预测值附近的置信度,我们需要对同一输入进行多次预测。相比较于在推理过程中将网络设置为验证模式,我们将其保持为训练模式,意味着我们随机丢弃一些神经元并得到一个测试结果。当我们使用这个Dropout网络进行多次预测时,对于相同的输入,我们会根据神经元被丢弃的情况获得不同的预测结果。我们使用这些预测结果来估计一个平均的最终输出,以及一个置信区间。
在下面的两张图中,我们估计网络预测值附近的置信区间。这些可视化结果是通过Bayesian Neural Networks Notebook中的代码生成的。红线代表着预测值,预测值周围的紫色阴影区间代表着不确定度,也就是预测值的方差。

图 10: 使用ReLU激活的不确定度估计

图 11: 使用Tanh激活的不确定度估计
正如你在上图中观察到的,这些不确定度的估计是未被校准的。对于不同的激活函数,它们都不同。在图片中我们可以注意到,数据点附近的不确定度较低。更进一步,我们可以发现这些方差是可微函数。所以我们可以通过推理梯度下降来最小化这些方差,从而我们可以获得更确信的预测结果。
如果我们的EBM模型的总损失由多项构成,它们之间会如何影响?
在EBM模型中,我们可以简化并简单地将不同项加起来以估计总损失函数。
题外话 一个惩罚隐变量长度的项可以成为损失函数中的一项。一个向量的长度一般大致和它的维度成正比。所以如果你减少了维度,那么向量的长度也会减少,最终向量编码的信息也会减少。在自编码器的设定中,这能保证模型保留了最重要的信息。所以,限制隐空间中的信息量的一种方法是减少隐空间的维度。
我们如何确定正则化的超参数?
从实践的角度,我们可以使用以下方法确定最优的超参数(比如正则化强度)
-
贝叶斯超参数优化
-
网格搜索
-
随机搜索
在采用这些搜索技术时,前几轮的结果就应该足够可以让我们理解正则化是如何运行的。所以我们需要花很多时间训练模型。
📝 Karl Otness, Xiaoyi Zhang, Shreyas Chandrakaladharan, Chady Raach
Yang Zhou
5 May 2020