动手学深度学习 3.12 权重衰减

前言

从零开始学习ai文章系列计划是个人在《动手学深度学习》和《磨菇书》两本书的学习中的个人笔记,文章也会以课本中的章节分开,即每个章节一片笔记。我会尽量的把主要内容以及遇到的难点进行记录与解决,如果哪里有错误的欢迎指正。或者不清晰的可以直接查看原文部分。

《动手学深度学习》原文(课本):https://tangshusen.me/Dive-into-DL-PyTorch/#/

《动手学深度学习》代码:https://github.com/ShusenTang/Dive-into-DL-PyTorch

(由于有时候公式太多,可能会直接贴图片)

虽然增大训练数据集可能会减轻过拟合,但是获取额外的训练数据往往代价高昂。

本节介绍应对过拟合问题的常用方法:权重衰减(weight decay)。

1. 方法

权重衰减等价于 L2范数正则化(regularization)

正则化通过为模型损失函数添加惩罚项 使学出的模型参数值较小,是应对过拟合的常用手段。L2范数正则化在模型原损失函数基础上添加L2范数惩罚项,从而得到训练所需要最小化的函数

L2范数惩罚项指的是模型权重参数每个元素的平方和与一个正的常数的乘积。

以3.1节(线性回归)中的线性回归损失函数为例,

其中 \(w_1,w_2\) 是权重参数,b是偏差参数,样本 \(i\) 的输入为 \(x^{(i)}_1、 x^{(i)}_2\),标签为 \(y^{(i)}\),样本数为 \(n\)。将权重参数用向量 \(w=[w_1,w_2]\) 表示,带有L2 范数惩罚项的新损失函数为

image-20250411161809353

其中超参数λ>0.

上式中L2范数平方 \(\left | \left | {w} \right | \right |\) 展开后得到 \(w^2_1+w^2_2\)

感觉下图gpt解释的公式更亲民点

当权重参数均为0时,惩罚项最小。当λ较大时,惩罚项在损失函数中的比重较大,这通常会使学到的权重参数的元素较接近0。

当λ设为0时,惩罚项完全不起作用。

有了L2范数惩罚项后,在小批量随机梯度下降中,我们将线性回归一节中权重 \(w_1\)\(w_2\) 的迭代方式更改为

image-20250411162334337

其求导可以参考下图,对 \(\sum {w^2_i}\) 中某特定 \(w_i\) 的求导(先别管红框)

image-20250411162423404

这意味着当前 \(w_i\) 越大的话,他更新幅度越大,因此 \(w_i\) 更新后越趋近于0

使得所有参数w之间的差距不会过大,每个都有更新的机会。因此很适合训练初期,当初期有对应特征之后,可以减少λ的大小。

有以下优点:

  1. 提高数值稳定性
  2. L2 正则化鼓励权重较小,从而避免梯度过大或梯度爆炸的问题,在一定程度上 提高了训练的数值稳定性。
  3. 它有助于防止过拟合、平滑优化、提高数值稳定性。

2. 高维线性回归实验

下面,我们以高维线性回归为例来引入一个过拟合问题,并使用权重衰减来应对过拟合。设数据样本特征的维度为p。

对于训练数据集和测试数据集中特征为 \(x_1,x_2,…,x_p\) 的任一样本,我们使用如下的线性函数来生成该样本的标签: \[ y = 0.05+ \sum ^{p}_{i=1} {0.01x_i}+ϵ \] 其中噪声项ϵ,ϵ服从均值为0、标准差为0.01的正态分布。为了较容易地观察过拟合,我们考虑高维线性回归问题,如设维度p=200。

同时,我们特意把训练数据集的样本数设低,如20。

3. 从零开始实现

3.1 初始化模型参数

定义随机初始化模型参数的函数。该函数为每个参数都附上梯度。

1
2
3
4
def init_params():
w = torch.randn((num_inputs, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
return [w, b]

3.2 定义L2范数惩罚项

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

3.3 定义训练和测试

其中net和loss的函数如下

1
2
3
4
5
6
def linreg(X, w, b):
return torch.mm(X, w) + b

def squared_loss(y_hat, y):
# 注意这里返回的是向量, 另外, pytorch里的MSELoss并没有除以 2
return ((y_hat - y.view(y_hat.size())) ** 2) / 2

当我们设置 lambd=0,fit_and_plot(lambd=0),即不使用权重衰减,效果如下

当我们设置 lambd=3,fit_and_plot(lambd=3),效果如下

4. 简洁实现

这里我们直接在构造优化器实例时通过weight_decay参数来指定权重衰减超参数。

(每个参数如果使用了参数衰减,那么更新的时候也只是 减去自身权重相关的一个数,不需要像之前那样在loss那里将所有权重加起来。可以像下图中在优化处进行指定参数的权重衰减。)

设置 lambd=0,fit_and_plot_pytorch(0),即不使用权重衰减,效果如下

设置 lambd=3,fit_and_plot_pytorch(3),效果如下