返回顶部

请叫我杨先生

导航

Pytorch 4.5 权重衰减

正则化

预备知识

1.范数

距离的定义是一个宽泛的概念。只要是满足①非负②自反③三角不等式就可以称之为距离。范数是一种强化了的距离概念,它在定义上比距离多了一条数乘的运算法则。我们可以将范数当成是一种距离来理解。

(1)L-P范数

\[||L||_p = (\sum_{i=1}^{n}|x_i^p|)^{\frac{1}{p}} \quad x = (x_1,x_2,x_3,\cdots,x_n) \]

(2)据此我们很容易得到 : L-1范数

\[||L||_1 = (\sum_{i=1}^{n}|x_i^1|)^{\frac{1}{1}} \quad x = (x_1,x_2,x_3,\cdots,x_n)\\||L||_1 = \sum_{i=1}^{n}|x_i| \]

(3)L-2范数

\[||L||_2 = (\sum_{i=1}^{n}|x_i^2|)^{\frac{1}{2}} \quad x = (x_1,x_2,x_3,\cdots,x_n)\\||L||_2 = \sqrt[2]{\sum_{i=1}^{n}x_i^2} \]

权重衰减

在训练参数化机器学习模型时, 权重衰减(weight decay)是最广泛使用的正则化的技术之一, 它通常也被称为 \(L2\) 正则化。我们在上一篇文章中有讲到过,参数范围越大,越容易使得模型的函数更加尖锐,容易过拟合,为了使我们的函数更加平滑,具有更好的泛化性能,我们要引入一个正则化。 具体原理如下:

\[L(\mathbf{w}, b) = \frac{1}{n}\sum_{i=1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)^2\\L(\mathbf{w}, b) + \frac{\lambda}{2} \|\mathbf{w}\|^2 \]

其中 \(L(\mathbf{w}, b)\) 是我们的损失函数 \(\frac{\lambda}{2} \|\mathbf{w}\|^2\) 是我们的正则化项,\(\lambda = 0\) 时相当于没有引入,\(\lambda > 0\) 时正则化正则化项求导 \(\lambda\mathbf{w}\) ,恰好是我们的权重张量。我们仅考虑惩罚项,优化算法在训练的每一步衰减权重。 与特征选择相比,权重衰减为我们提供了一种连续的机制来调整函数的复杂度。 较小的 \(λ\) 值对应较少约束的 \(w\) , 而较大的 \(\lambda\) 值对 \(w\) 的约束更大。

\[\begin{aligned} \mathbf{w} & \leftarrow \left(1- \eta\lambda \right) \mathbf{w} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \mathbf{x}^{(i)} \left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right). \end{aligned}\]

提示:我们一般不会对偏置项进行正则化,在于说,求导之后几乎都是一个常数。

简单实现下权重衰减

step1.库函数
%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l
step2.初始化参数

我们选择标签是关于输入的线性函数。 标签同时被均值为\(0\),标准差为\(0.01\)高斯噪声破坏。 为了使过拟合的效果更加明显,我们可以将问题的维数增加到 \(d=200\) , 并使用一个只包含\(20\)个样本的小训练集。

n_train, n_test, num_inputs, batch_size = 20,100,200,5   
true_w, true_b = torch.ones(size=(num_inputs,1))*0.01 ,0.05 
train_data = d2l.synthetic_data(true_w,true_b,n_train) # type(train_data) tuple
train_iter = d2l.load_array(train_data,batch_size)  # torch.utils.data.dataloader.DataLoader 
test_data = d2l.synthetic_data(true_w, true_b, n_test)
test_iter = d2l.load_array(test_data, batch_size, is_train=False) # Q1:为什么测试数据集不用随机化样本 

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]
step3.定义正则项和训练函数
def l2_penalty(w):
    return torch.sum(w.pow(2)) / 2
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:
            # 增加了L2范数惩罚项,
            # 广播机制使l2_penalty(w)成为一个长度为batch_size的向量
            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())
# 忽略正则化
train(lambd=0)

w的L2范数是: 13.449113845825195

#正则化的lambda = 1 
torch(1)

w的L2范数是: 4.180489540100098

  1. 在本节的估计问题中使用 \(λ\) 的值进行实验。绘制训练和测试精度关于 \(λ\) 的函数。你观察到了什么?
  2. 使用验证集来找到最佳值 \(λ\) 。它真的是最优值吗?这有关系吗?
  3. 如果我们使用 \(∑_i|w_i|\) 作为我们选择的惩罚( \(L_1\) 正则化),那么更新方程会是什么样子?
  4. 我们知道 \(∥w∥_2=w⊤w\) 。你能找到类似的矩阵方程吗(见 2.3.10节 中的Frobenius范数)?
  5. 回顾训练误差和泛化误差之间的关系。除了权重衰减、增加训练数据、使用适当复杂度的模型之外,你还能想出其他什么方法来处理过拟合?
  6. 在贝叶斯统计中,我们使用先验和似然的乘积,通过公式 \(P(w∣x)∝P(x∣w)P(w)\) 得到后验。如何得到带正则化的 \(P(w)\)

posted on 2022-01-05 16:22  YangShusen'  阅读(283)  评论(0编辑  收藏  举报