通过正则化避免过拟合
通过正则化避免过拟合。
深度神经网络通常拥有数万个参数,有时甚至有数百万个。这个深度神经网络带来了难以置信的自由度,意味着它们可以拟合各种各样的复杂数据集。
但是这种巨大的灵活性也使网络易于过拟合训练集。此时就需要正则化。
\(\ell_1\)和\(\ell_2\)正则化
可以使用\(\ell_2\)正则化来约束神经网络连接权重,如果想要稀疏模型(许多权重等于0)则可以使用\(\ell_1\)正则化。以下是使用0.01的正则化银子将\(\ell_2\)正则化应用于Keras层的连接权重的方法:
layer = keras.layers.Dense(100,
activation='elu',
kernel_initializer='he_normal',
kernel_regularizer=keras.regularizers.l2(0.01))
l2()函数返回一个正则化函数,在训练过程中的每个步骤都将调用该正则化函数来计算正则化损失。然后将其添加到最终损失中。如果需要\(\ell_1\)正则化,可以只使用keras.regularizers.l1()。如果同时需要\(\ell_1\)和\(\ell_2\)正则化,需要使用keras.regularizers.l1_l2()(同时指定两个正则化因子)
将相同的正则化函数应用与网络中的所有层,并在所有隐藏层中使用相同的激活函数和相同的初始化策略,可以尝试用循环来重构代码。另一种选择是使用Python的functools.partial()函数,该函数可以为带有一些默认参数值的任何可调用对象创建一个小的包装函数
from functools import partial
RegularizedDense = partial(keras.layers.Dense,
activation='elu',
kernel_initializer='he_normal',
kernel_regularizer=keras.regularizers.l2(0.01))
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]),
RegularizedDense(300),
RegularizedDense(100),
RegularizedDense(10,
activation='softmax',
kernel_initializer='glorot_uniform')
])
dropout
在每个训练步骤中,每个神经元(包括输入神经元,但始终不包括输出神经元)都有暂时“删除”的概率p,这意味着在这个训练步骤中它被完全忽略,但在下一步中可能处于活动状态。超参数p成为dropout率,通常设置为10%到50%:在循环神经网络中接近20-30%,在卷积神经网络中接近40-50%。训练后,神经元不再被删除。
经过dropout训练过的神经元不能与其相邻的神经元相互适应,它必须发挥自己最大的作用。它们也不能过于依赖少数输入神经元,它们必须注意每个输入神经元。它们对输入的微小变化不太敏感。最后,可以获得一个更有鲁棒性的网络,该网络具有更好的泛化性能
技术细节:假设p=50%,在这种情况下,在测试过程中,一个神经元被连接到输入神经元的数量是训练期间(平均)的两倍。为了弥补这一事实,需要在训练后将每个神经元的输入连接权重乘以0.5.如果不这么做,每个神经元得到的总输入信号大概是网络训练时的两倍,表现可能不会很好。更一般而言,训练后需要将每个输入连接权重乘以保留概率(1-p)。或者,可以在训练过程中将每个神经元的输出除以保留概率(这些替代方法不是完全等效的,但效果一样好
要使用Keras实现dropout,可以使用keras.layers.Dropout层。在训练期间,它会随机丢弃一些输入(将它们设置为0),然后将其余输入除以保留概率。训练之后,它什么都不做,只是将输入传递到下一层。下一代码使用0.2的dropout率在每个Dense层之前应用dropout正则化:
model=keras.models.Sequential([
keras.layers.Flatten(input_shape=[28,28]),
keras.layers.Dropout(rate=0.2),
keras.layers.Dense(300,activation='elu',kernel_initializer='he_normal'),
keras.layers.Dropput(rate=0.2),
keras.layers.Dense(100,activation='elu',kernel_initializer='he_normal'),
keras.layers.Dropout(rate=0.2),
keras.layers.Dense(10,activation='sofrmax')
])
蒙特卡罗(MC)Dropout
MC Dropout的实现,可提升之前训练的dropout模型,而无需重新训练:
y_probas=np.stack([model(X_test_scaled,training=True)for sample in range(100)])
y_proba=y_probas.mean(axis=0
对测试集进行100个预测,设置training=True来确保Dropout层处于激活状态,然后把预测堆叠起来。由于Dropout处于激活状态,因此所有预测都将有所不同。想象一下,predict()返回一个矩阵,每个实例为1行,每个类为1列。因为测试集中有10000个实例和10个类,所以这是一个形状为[10000,10]的矩阵。然后堆叠了100个这样的矩阵,因为y_probas是一个形状为[100,10000,10]的数组,对第一个维度进行平均(axis=0),得到了y_proba,它是形状为[10000,10]的矩阵,就像通过单个预测得到的一样。对于具有dropout功能的多个预测进行平均,这使蒙特卡罗估计通常比关闭dropout的单个预测结果更可靠。
最大范数正则化
对于神经网络而言,另一种流行的正则化技术称为最大范数正则化,对于每个神经元,它会限制传入连接的权重\(w\),使得\(||w||_2\le r\),其中r是最大范数超参数,\(||\bullet||_2\)是\(\ell_2\)范数
最大范数正则化不会把正则化损失添加到总体损失函数中。取而代之的是,通常在每个训练步骤后通过计算\(||w||_2\)来实现,如果有需要,重新缩放\(w(w\gets\frac{||w||_2}{r})\)
减小r会增加正则化的数量,并有助于减少过拟合。最大范数正则化还可以帮助环节不稳定的梯度问题(如果未使用“批量梯度归一化”)
要在Keras中使用最大范数正则化,需要将每个隐藏层的kernel_constraint参数设置为具有适当最大值的max_norm()约束,如下所示:
keras.layers.Dense(100,activation='elu',kernel_initializer='he_normal',
kernel_constraint=keras.constraints.max_norm(1.))
每次训练迭代后,fit()方法会调用由max_norm()返回的对象,将层的权重传递给该对象,并获得返回的缩放权重,然后替换该层的权重。还可以自定义约束函数,并将其用作kernel_constraint。还可以设置bias_constraint参数来约束偏置项。
max_norm()函数的参数axis默认为0。Dense层通常具有形状为[输入数量,神经元数量]的权重,因此使用axis=0意味着最大范数约束将独立作用与每个神经元的权重向量。如果最大范数与卷积层一起使用,要确保正确设置max_norm()约束的axis参数
总结
默认的DNN配置
超参数 | 默认值 |
---|---|
内核初始化 | He 初始化 |
激活函数 | ELU |
归一化 | 浅层网络:不需要;深度网络:批量归一化 |
正则化 | 提前停止(如果需要,可加\(\ell_2\) |
优化器 | 动量优化(或RMSProp或Nadam) |
学习率调度 | 1周期 |
用于自归一化网络的DNN配置
超参数 | 默认值 |
---|---|
内核初始化 | LeCun 初始化 |
激活函数 | SELU |
归一化 | 不需要(自归一化) |
正则化 | 如果需要:Alpha dropout |
优化器 | 动量优化(或RMSProp或Nadam) |
学习率调度 | 1周期 |