1 前言

在上一节中,我们使用人工数据集直观展示了模型过拟合造成的影响【DeepLearning】2-3多层感知机——模型选择、过拟合和欠拟合。正则化是处理过拟合的常用方法,利用正则化模型的技术可以规避过拟合的风险。本节将详细介绍正则化和权重衰减,并通过人工数据集,直观展示权重衰减对模型过拟合的改善效果,以及权重衰减在深度学习框架中的使用。

2 正则化泛数

当模型出现过拟合时,我们应当控制模型复杂度,正则化意味着通过将权重空间不断缩小来限制模型避免过拟合。从技术上讲,正则化通过向模型的损失函数添加惩罚项来限制权重空间的大小,使其在合理的范围内。
一般来说,作为损失函数都需要一个明确的下界,损失值越接近下界可以保证模型达到了最优解。正则化项作为目标函数的一部分,也具有同样的要求,而泛数刚好满足了这个条件。下面来回顾一下泛数的定义,给定一个具有i个分量的x,它的p-泛数为:p-泛数
在权重衰退中,我们运用的是L2泛数,因此我们着重介绍L2正则化。
L2正则化在原损失函数中添加一项后,变为:
L2正则化
为什么添加一个L2泛数项就可以限制权重空间呢?我们发现上式可以等价于一个硬性限制,即:在 min L ( w , b ) \text{min} L(w, b) minL(w,b)时加入一个限制,使得 ∥ w ∥ 2 ≤ θ \|\mathbf{w}\|^2 \leq \theta w2θ,当所有权重w的平方和 ≤ θ \leq \theta θ时,每一个权重w ≤ θ \leq \sqrt{\theta} θ 。这个等价可以通过拉格朗日乘子来证明。证明
由此可见,L2正则化可以通过限制参数的选择范围来限制模型容量。 λ \lambda λ是控制正则项的超参数, λ \lambda λ越大,对参数的约束越强,容易发生欠拟合; λ \lambda λ越小,对参数的约束越弱,不容易解决过拟合问题。

3 权重衰减

理解了正则项的加入后,权重衰减也就迎刃而解了。损失函数加入正则项后,计算梯度时会发生如下变化:权重衰退
通常情况下, η λ < 1 \eta\lambda < 1 ηλ<1,因此 w t w_t wt随着时间的更新,不仅会朝着损失最小的方向前进,自身值的范围也会衰减,权重衰减因此得名。
为什么限制权重的范围能够避免过拟合呢?下图中绿色线代表权重衰减后的模型,而蓝色线则是过拟合的模型,我们发现没有权重衰减的模型会表现出更大的起伏,这实际上是权重过大所导致的。通过限制权重的范围,可以使得模型变得更缓和,由此来避免模型受到太多噪音的影响。
权重衰减与过拟合
通常,偏置 b b b不会影响函数的形状,因此偏置项通常不会被正则化。

4 权重衰减的实现

我们利用一个简单的高维线性回归来直观理解权重衰减在避免过拟合上的应用。

4.1 导入所需模块

%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l

4.2 生成人工数据集

我们建立一个线性函数,样本含有均值为0,标准差为0.01的噪音,为了表现过拟合,我们将模型的维数增大到200,但样本个数只有20。
y = 0.05 + ∑ i = 1 d 0.01 x i + ϵ  where  ε   N ( 0 , 0.0 1 2 ) y = 0.05 + \sum_{i=1}^d 0.01x_i + \epsilon \text{ where } ε ~ N(0, 0.01^2) y=0.05+i=1d0.01xi+ϵ where ε N(0,0.012)

n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
train_data = d2l.synthetic_data(true_w, true_b, n_train)
train_iter = d2l.load_array(train_data, batch_size)
test_data = d2l.synthetic_data(true_w, true_b, n_test)
test_iter = d2l.load_array(test_data, batch_size, is_train=False)

4.3 初始化模型参数

初始化模型参数的定义与之前相同。

def init_params():
    w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)
    return [w, b]

4.4 定义 L 2 L_2 L2泛数惩罚

L 2 L_2 L2泛数惩罚是权重衰减的关键,但实际非常简单,只需要将所有的权重平方后加和即可。因为 L 2 L_2 L2泛数存在平方项,因此我们实现乘 1 2 \frac{1}{2} 21,简化求偏导后的计算。

def l2_penalty(w):
    return torch.sum(w ** 2) / 2

4.5 定义训练函数

训练函数的定义和线性回归模型基本相同,只是增加了一个超参数lambd,用于控制正则项的强弱。最后我们以动画形式输出训练过程和 w w w L 2 L_2 L2泛数用于比较。

def train(lambd):
    w, b = init_params()
    net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss
    num_epochs, lr = 100, 0.003
    animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
                            xlim=[5, num_epochs], legend=['train', 'test'])
    for epoch in range(num_epochs):
        for X, y in train_iter:
            l = loss(net(X), y) + lambd * l2_penalty(w)
            l.sum().backward()
            d2l.sgd([w, b], lr, batch_size)
        if (epoch + 1) % 5 == 0:
            animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
                                     d2l.evaluate_loss(net, test_iter, loss)))
    print('w的L2范数是:', torch.norm(w).item())

4.5.1 忽略正则化直接训练

λ = 0 \lambda = 0 λ=0时,即没有正则项。

train(lambd=0)

在这里插入图片描述
如图我们可以发现,忽略正则化直接训练会导致训练损失迅速下降,而测试损失依旧保持一条直线,发生了严重的过拟合。而且 w w w L 2 L_2 L2泛数很大,事实上我们给定人工数据集的 w w w只有0.01。

4.5.2 使用权重衰减

接下来我们把 λ \lambda λ设置为3。

train(lambd=3)

在这里插入图片描述
尽管前40个循环还是发生了一定程度的过拟合,但由于正则项的存在,参数的范围被控制下来,基本保持不变,而测试集的损失始终下降,说明一定程度上改善了过拟合的问题。

4.6 权重衰减的简洁实现

利用现有的深度学习框架,可以对权重衰减进行简洁实现。简洁实现的效果与上述效果完全相同。

def train_concise(wd):
    net = nn.Sequential(nn.Linear(num_inputs, 1))
    for param in net.parameters():
        param.data.normal_()
    loss = nn.MSELoss(reduction='none')
    num_epochs, lr = 100, 0.003
    # 偏置参数没有衰减
    trainer = torch.optim.SGD([
        {"params":net[0].weight,'weight_decay': wd},
        {"params":net[0].bias}], lr=lr)
    animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
                            xlim=[5, num_epochs], legend=['train', 'test'])
    for epoch in range(num_epochs):
        for X, y in train_iter:
            trainer.zero_grad()
            l = loss(net(X), y)
            l.mean().backward()
            trainer.step()
        if (epoch + 1) % 5 == 0:
            animator.add(epoch + 1,
                         (d2l.evaluate_loss(net, train_iter, loss),
                          d2l.evaluate_loss(net, test_iter, loss)))
    print('w的L2范数:', net[0].weight.norm().item())

5 小结

在本节内容中,我们介绍了正则化泛数在改善过拟合问题中是如何发挥作用的,并由此解释了权重衰减的由来。权重衰减通过 L 2 L_2 L2正则项使得模型参数不会过大,从而控制模型复杂度。正则项权重是控制模型复杂度的超参数, λ \lambda λ通常取值为 e − 2 、 e − 3 、 e − 4 e^{-2}、e^{-3}、e^{-4} e2e3e4,对于较为简单的模型可能有比较显著的效果,但对于更为复杂的模型效果可能是微乎其微的,未来我们还会学习更多优化算法使得模型更为准确。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐