正则化是一类通过限制模型复杂度,从而避免过拟合,提高泛化能力的方法,比如引入约束、增加先验、提前停止等。在传统的机器学习中,提高泛化能力的方法主要是限制模型复杂度,比如采用 L 1 L1 L1 和 L 2 L2 L2 正则化等方式.而在训练深度神经网络时,特别是在过度参数化(过度参数化是指模型参数的数量远远大于训练数据的数量)时, L 1 L1 L1 和 L 2 L2 L2 正则化的效果往往不如浅层机器学习模型中显著.
因此训练深度学习模型时,往往还会使用其他的正则化方法,比如数据增强、提前停止、Dropout、集成法等.
通过加入 L 1 L1 L1 和 L 2 L2 L2 正则化,优化问题可以写为
θ ∗ = a r g m i n θ 1 N ∑ n = 1 N L ( y ( n ) , f ( x ( n ) ; θ ) ) + λ L p ( θ ) \theta^*=\mathop{argmin}\limits_{\theta}\frac{1}{N}\sum_{n=1}^NL(y^{(n)},f(x^{(n)};\theta))+\lambda L_p(\theta) θ∗=θargminN1n=1∑NL(y(n),f(x(n);θ))+λLp(θ)其中 L ( ⋅ ) L(\cdot) L(⋅) 为损失函数, N N N 为训练样本数, f ( ⋅ ) f(\cdot) f(⋅) 为待学习的神经网络, θ \theta θ 为其参数, L p L_p Lp 为范数函数, p p p 的取值一般是 { 1 , 2 } \{1,2\} {1,2} 代表 L 1 , L 2 L_1,L_2 L1,L2 范数, λ \lambda λ 为正则化系数。
一种折中的正则化方法是同时加入 L 1 , L 2 L_1,L_2 L1,L2 正则化,称为弹性网络正则化,公式如下:
θ ∗ = a r g m i n θ 1 N ∑ n = 1 N L ( y ( n ) , f ( x ( n ) ; θ ) ) + λ 1 L 1 ( θ ) + λ 2 L 2 ( θ ) \theta^*=\mathop{argmin}\limits_{\theta}\frac{1}{N}\sum_{n=1}^NL(y^{(n)},f(x^{(n)};\theta))+\lambda_1 L_1(\theta)+\lambda_2 L_2(\theta) θ∗=θargminN1n=1∑NL(y(n),f(x(n);θ))+λ1L1(θ)+λ2L2(θ)
权重衰减是一种有效的正则化方法[Hanson et al., 1989],在每次参数更新时,引入一个衰减系数,式子如下所示:
θ t = ( 1 − β ) θ t − 1 − α g t \theta_t=(1-\beta) \theta_{t-1}-\alpha g_t θt=(1−β)θt−1−αgt其中, g t g_t gt 为第 t t t 步更新时的梯度, α \alpha α 为学习率, β \beta β 为权重衰减系数,一般取值比较小,比如 0.0005 0.0005 0.0005。我们可以发现,这个参数更新的式子与 L 2 L2 L2 正则化基本一致,该式子的推导如下:
设加了 L 2 L2 L2 正则的函数 C C C 如下:
C = C 0 + λ 2 n ∑ w w 2 C = C_0+ \frac{\lambda}{2n}\sum_{w}w^2 C=C0+2nλw∑w2其中 C 0 C_0 C0 是原始的损失函数, w w w 为神经网络各层权重。
参数更新时,首先对参数 w , b w,b w,b 分别进行偏导得到:
∂ C ∂ w = ∂ C 0 ∂ w + λ n w ∂ C ∂ b = ∂ C 0 ∂ b \begin{aligned} \frac{\partial C}{ \partial w}&=\frac{\partial C_0}{ \partial w}+\frac{\lambda}{n}w \\ \\ \frac{\partial C}{ \partial b}&=\frac{\partial C_0}{ \partial b} \end{aligned} ∂w∂C∂b∂C=∂w∂C0+nλw=∂b∂C0进行参数更新时,更新如下:
b = b − η ∂ C ∂ b w = w − η ∂ C ∂ w = w − η ( ∂ C 0 ∂ w + λ n w ) = w − η λ n w − η ∂ C 0 ∂ w = ( 1 − η λ n ) w − η ∂ C 0 ∂ w \begin{aligned} b &= b - \eta \frac{\partial C}{ \partial b} \\ w &= w - \eta \frac{\partial C}{ \partial w} \\ &= w-\eta (\frac{\partial C_0}{ \partial w}+\frac{\lambda}{n}w) \\ &=w-\eta \frac{\lambda}{n}w-\eta \frac{\partial C_0}{ \partial w} \\ &= (1-\eta\frac{\lambda}{n})w-\eta \frac{\partial C_0}{ \partial w} \end{aligned} bw=b−η∂b∂C=w−η∂w∂C=w−η(∂w∂C0+nλw)=w−ηnλw−η∂w∂C0=(1−ηnλ)w−η∂w∂C0通过上面的式子,可以看到参数 b b b 的更新实际上并没有变化,但是参数 w w w
的更新产生了一些变化,这种调整就是权值衰减,实际上,pytorch中的各种优化算法都会存在一个 weight_decay
参数,该参数可以与上述式子的 λ n \frac{\lambda}{n} nλ 等价。
实际上,在标准的随机梯度下降中,权重衰减正则化和 L 2 L2 L2 正则化的效果相同。不过,在较为复杂的优化方法(比如Adam)中,权重衰减正则化和 L 2 L2 L2 正则化并不等价。
提前停止对于深度神经网络来说是一种简单有效的正则化方法。提前停止也可以参见由于深度神经网络的拟合能力非常强,因此比较容易在训练集上过拟合。使用梯度下降法进行优化时,我们可以使用一个和训练集独立的样本集合,称为验证集,并用验证集上的错误来代替期望错误.当验证集上的错误率不再下降,就停止迭代.然而在实际操作中,验证集上的错误率变化曲线并不一定是平衡曲线,很可能是先升高再降低。因此,提前停止的具体停止标准需要根据实际任务进行优化。
当训练一个深度神经网络时, 我们可以随机丢弃一部分神经元(同时丢弃其对应的连接边)来避免过拟合,这种方法称为 Dropout 。每次选择丢弃的神经元是随机的.最简单的方法是设置一个固定的概率 p p p。对每一个神经元都以概率 p p p 来判定要不要保留。对于一个神经层 y = f ( W x + b ) y = f(Wx + b) y=f(Wx+b),我们可以引入一个掩蔽函数 m a s k ( ⋅ ) mask(⋅) mask(⋅) 使得 y = f ( W ⋅ m a s k ( x ) + b ) y =f(W\cdot mask(x) + b) y=f(W⋅mask(x)+b)。掩蔽函数 m a s k ( ⋅ ) mask(⋅) mask(⋅) 的定义为
m a s k ( x ) = { m x , 训练阶段 p x , 测试阶段 mask(x)=\left\{ \begin{aligned} mx,&训练阶段\\ px,&测试阶段 \end{aligned} \right. mask(x)={mx,px,训练阶段测试阶段其中 m ∈ { 0 , 1 } D m \in \{0,1\}^D m∈{0,1}D ( D D D为输入 x x x的维度)是 Dropout掩码,通过以概率为 p p p 的分布随机生成。在训练时,激活神经元的平均数量为原来的 p p p 倍。而在测试时,所有的神经元都是可以激活的,这会造成训练和测试时网络的输出不一致。为了缓解这个问题,在测试时需要将神经层的输入 x x x 乘以 p p p,也相当于把不同的神经网络做了平均。保留率 p p p 可以通过验证集来选取一个最优的值。一般来讲,对于隐藏层的神经元,其保留率 p = 0.5 p = 0.5 p=0.5 时效果最好,这对大部分的网络和任务都比较有效。当 p = 0.5 p = 0.5 p=0.5 时,在训练时有一半的神经元被丢弃,只剩余一半的神经元是可以激活的,随机生成的网络结构最具多样性。对于输入层的神经元,其保留率通常设为更接近 1 1 1 的数,使得输入变化不会太大。对输入层神经元进行丢弃时,相当于给数据增加噪声,以此来提高网络的鲁棒性。
在下面的网络中,随机删除了一些元素,并且他们在执行反向传播时也会消失吗,这可以理解为在训练时告诉他们不能太过依赖与神经网络的某一个结点,以此提高了网络的泛化型以及拟合能力。
深度神经网络一般都需要大量的训练数据才能获得比较理想的效果。在数据量有限的情况下,可以通过数据增强来增加数据量,提高模型鲁棒性,避免过拟合。目前,数据增强还主要应用在图像数据上,在文本等其他类型的数据上还没有太好的方法。图像数据的增强主要是通过算法对图像进行转变,引入噪声等方法来增加数据的多样性。增强的方法主要有几种:
pytorch中的常用数据增强函数一般用 transforms
里面,主要使用以下的数据增强函数:
from torchvision import transforms
transforms.Compose([
# 随机旋转,角度在-45到45度之间
transforms.RandomRotation(45),
# 从中心开始剪裁
transforms.CenterCrop(224),
# 以0.5的概率水平翻转
transforms.RandomHorizontalFlip(p=0.5),
# 以0.5的概率垂直翻转
transforms.RandomVerticalFlip(p=0.5),
# 参数依次为亮度、对比度、饱和度、色相
transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),
# 以0.025的概率变为灰度图像,3通道即R=G=B
transforms.RandomGrayscale(p=0.025),
# 将0-255的像素进行归一化
transforms.ToTensor(),
# 使用均值和标准差标准化三个通道的数据
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
当然,也可以使用其他库的数据增强函数,torchvision中的数据增强应付大部分的数据增强需求应该是够了的,其他比如 imgaug
、albumentations
等第三方库也可以起到数据增强的作用,且功能更加强大。
在数据增强中,我们可以给样本特征加入随机噪声来避免过拟合.同样,我们也可以给样本的标签引入一定的噪声.假设训练数据集中有一些样本的标签是被错误标注的,那么最小化这些样本上的损失函数会导致过拟合。一种改善的正则化方法是标签平滑,即在输出标签中添加噪声来避免模型过拟合。
一个样本 x x x 的标签可以用 one-hot 向量表示,即
y = [ 0 , ⋯ , 0 , 1 , 0 , ⋯ , 0 ] T y=[0,\cdots,0,1,0,\cdots,0]^T y=[0,⋯,0,1,0,⋯,0]T这种标签可以看作硬目标。如果使用 S o f t m a x Softmax Softmax 分类器并使用交叉熵损失函数,最小化损失函数会使得正确类和其他类的权重差异变得很大.根据 S o f t m a x Softmax Softmax 函数的性质可知,如果要使得某一类的输出概率接近于 1 1 1,其未归一化的得分需要远大于其他类的得分,可能会导致其权重越来越大,并导致过拟合.此外,如果样本标签是错误的,会导致更严重的过拟合现象。为了改善这种情况,我们可以引入一个噪声对标签进行平滑,即假设样本以 ϵ \epsilon ϵ 的概率为其他类。平滑后的标签为
y ~ = [ ϵ K − 1 , ⋯ , ϵ K − 1 , 1 − ϵ , ϵ K − 1 , ⋯ , ϵ K − 1 ] \widetilde{y}=[\frac{\epsilon}{K-1},\cdots,\frac{\epsilon}{K-1},1-\epsilon,\frac{\epsilon}{K-1},\cdots,\frac{\epsilon}{K-1}] y =[K−1ϵ,⋯,K−1ϵ,1−ϵ,K−1ϵ,⋯,K−1ϵ]其中 K K K 为标签数量,这种标签可以看作软目标。标签平滑可以避免模型的输出过拟合到硬目标上,并且通常不会损害其分类能力。
上面的标签平滑方法是给其他 K − 1 K − 1 K−1 个标签相同的概率 ϵ K − 1 \frac{\epsilon}{K-1} K−1ϵ 没有考虑标签之间的相关性。一种更好的做法是按照类别相关性来赋予其他标签不同的概率。比如先训练另外一个更复杂(一般为多个网络的集成)的教师网络,并使用大网络的输出作为软目标来训练学生网络。这种方法也称为知识蒸馏,就不再这里介绍了。