方法
权重衰减等价于 L2 范数正则化(regularization)。正则化通过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常用手段。
L2 范数正则化(regularization)
L2 范数正则化在模型原损失函数基础上添加 L2 范数惩罚项,从而得到训练所需要最小化的函数。 L2 范数惩罚项指的是模型权重参数每个元素的平方和与一个正的常数的乘积。以线性回归中的线性回归损失函数为例
ℓ(w1,w2,b)=1n∑i=1n12(x(i)1w1+x(i)2w2+b−y(i))2
其中 w1,w2 是权重参数, b 是偏差参数,样本 i 的输入为 x(i)1,x(i)2 ,标签为 y(i) ,样本数为 n 。将权重参数用向量 w=[w1,w2] 表示,带有 L2 范数惩罚项的新损失函数为
ℓ(w1,w2,b)+λ2n|w|2,
其中超参数 λ>0 。当权重参数均为0时,惩罚项最小。当 λ 较大时,惩罚项在损失函数中的比重较大,这通常会使学到的权重参数的元素较接近0。当 λ 设为0时,惩罚项完全不起作用。上式中 L2 范数平方 |w|2 展开后得到 w21+w22 。 有了 L2 范数惩罚项后,在小批量随机梯度下降中,我们将线性回归一节中权重 w1 和 w2 的迭代方式更改为
w1w2←(1−ηλ|B|)w1−η|B|∑i∈Bx(i)1(x(i)1w1+x(i)2w2+b−y(i)),←(1−ηλ|B|)w2−η|B|∑i∈Bx(i)2(x(i)1w1+x(i)2w2+b−y(i)).
可见, L2 范数正则化令权重 w1 和 w2 先自乘小于1的数,再减去不含惩罚项的梯度。因此, L2 范数正则化又叫权重衰减。权重衰减通过惩罚绝对值较大的模型参数为需要学习的模型增加了限制,这可能对过拟合有效。
def fit_and_plot_pytorch(wd):
# 对权重参数衰减。权重名称一般是以weight结尾
net = nn.Linear(num_inputs, 1)
nn.init.normal_(net.weight, mean=0, std=1)
nn.init.normal_(net.bias, mean=0, std=1)
optimizer_w = torch.optim.SGD(params=[net.weight], lr=lr, weight_decay=wd) # 对权重参数衰减
optimizer_b = torch.optim.SGD(params=[net.bias], lr=lr) # 不对偏差参数衰减
train_ls, test_ls = [], []
for _ in range(num_epochs):
for X, y in train_iter:
l = loss(net(X), y).mean()
optimizer_w.zero_grad()
optimizer_b.zero_grad()
l.backward()
# 对两个optimizer实例分别调用step函数,从而分别更新权重和偏差
optimizer_w.step()
optimizer_b.step()
train_ls.append(loss(net(train_features), train_labels).mean().item())
test_ls.append(loss(net(test_features), test_labels).mean().item())
d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
range(1, num_epochs + 1), test_ls, ['train', 'test'])
丢弃法
多层感知机中神经网络图描述了一个单隐藏层的多层感知机。其中输入个数为4,隐藏单元个数为5,且隐藏单元 hi ( i=1,…,5 )的计算表达式为
hi=ϕ(x1w1i+x2w2i+x3w3i+x4w4i+bi)
这里 ϕ 是激活函数, x1,…,x4 是输入,隐藏单元 i 的权重参数为 w1i,…,w4i ,偏差参数为 bi 。当对该隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉。设丢弃概率为 p ,那么有 p 的概率 hi 会被清零,有 1−p 的概率 hi 会除以 1−p 做拉伸。丢弃概率是丢弃法的超参数。具体来说,设随机变量 ξi 为0和1的概率分别为 p 和 1−p 。使用丢弃法时我们计算新的隐藏单元 h′i
h′i=ξi1−phi
由于 E(ξi)=1−p ,因此
E(h′i)=E(ξi)1−phi=hi
即丢弃法不改变其输入的期望值。让我们对之前多层感知机的神经网络中的隐藏层使用丢弃法,一种可能的结果如图所示,其中 h2 和 h5 被清零。这时输出值的计算不再依赖 h2 和 h5 ,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即 h1,…,h5 都有可能被清零,输出层的计算无法过度依赖 h1,…,h5 中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在测试模型时,我们为了拿到更加确定性的结果,一般不使用丢弃法
%matplotlib inline
import torch
import torch.nn as nn
import numpy as np
import sys
sys.path.append("/home/kesci/input")
import d2lzh1981 as d2l
def dropout(X, drop_prob):
X = X.float()
assert 0 <= drop_prob <= 1
keep_prob = 1 - drop_prob
# 这种情况下把全部元素都丢弃
if keep_prob == 0:
return torch.zeros_like(X)
mask = (torch.rand(X.shape) < keep_prob).float()
return mask * X / keep_prob