-
使用均方范数作为硬性限制
如下所示,其中l是我们要优化的损失函数,w和b是两个参数。w为权重,b为偏移,
- 使用均方范数作为柔性限制
以上可以通过拉格朗日乘子来证明,超参数 λ \lambda λ控制了正则项的重要程度。
其中, w ∗ w^* w∗表示 w w w的最优解。
- λ = 0 : \lambda=0: λ=0:无作用,即不会影响w的取值,等价于之前的 θ − > ∞ \theta->\infty θ−>∞
- λ − > ∞ \lambda->\infty λ−>∞,等价于之前的 θ − > 0 \theta->0 θ−>0,所以 w − > 0 w->0 w−>0,那么最优解 w ∗ − > 0 w^*->0 w∗−>0
- 如果我们想让模型复杂度低一些,那我们将 λ \lambda λ增加些以满足要求。
-
参数更新法则
如下所示,将画黄线部分代入红色表达式并进行化简,即可得到时间t更新参数对应的表达式。
其中 η \eta η表示学习率,在上图中的第二个公式,后面部分(减去学习率*梯度)与我们之前讲的梯度下降是一样的,只是我们现在在每次更新前,在前面那里多减了一个 η λ \eta\lambda ηλ,进行权重的缩小。
-
总结
-
代码实现
# 权重衰减是最广泛使用的正则化的技术之一 %matplotlib inline import math import torch from torch import nn from d2l import torch as d2l # 1. 生成一些数据 n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5 # 随机生成权重,以及将偏差设成为0.05 true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05 # 使用synthetic_data生成人工数据集,以及使用load_array加载内存数据 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) # 2.初始化模型参数 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] # 3. 定义L2范数惩罚(对照公式),也是本次的核心,注意我们在该函数中没有将lambda放在里面 def L2_penalty(w): return torch.sum(w.pow(2)) / 2 # 拓展:我们也可以用L1 penalty(w) def L1_penalty(w): return torch.sum(torch.abs(w)) # 4. 定义训练代码实现 # lambda为超级参数 def train(lambd): w, b = init_params() net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss num_epochs, lr = 100, 0.03 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: # with torch.enable_grad(): # 增加L2范数惩罚项,广播机制使l2_penalty(w)成为一个长度为`batch_size`的向量。 # 以下表达式对应柔性限制的核心 l = loss(net(X), y) + lambd * L1_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) # 出现严重的过拟合 # 尝试改变lambda的值 train(lambd=3)
-
结果如下所示
当我们将 λ \lambda λ设为0时,得到的结果,如第1张图所示,很明显发生了严重的过滤盒,当我们将 λ \lambda λ设为3时,得到的效果还不错,具体哪个参数最优,则需要自己去调参。