动手学深度学习11 权重衰退
- 1. 权重衰退
- 2. 代码实现
- 3. QA
视频: https://www.bilibili.com/video/BV1UK4y1o7dy/?spm_id_from=autoNext&vd_source=eb04c9a33e87ceba9c9a2e5f09752ef8
电子书: ttps://zh-v2.d2l.ai/chapter_multilayer-perceptrons/weight-decay.html
课件: https://courses.d2l.ai/zh-v2/assets/pdfs/part-0_16.pdf
1. 权重衰退
为了便于讨论,我们假设训练的模型中只有w1和w2两个参数
但是我们觉得100这个数还是太大了,怎么办?我们在损失函数中添加一项,这一项是w1的平方+w2的平方
罚的项是L2正则项,因为离原点越近,正则项越小
绿线是损失函数的取值, 黄线是惩罚项的取值, 两者都是圈越大取值越大
两个圆锥的交点可能是最优点!!!!!!!
这里的平衡点可以看看kkt条件来理解,但其实增广拉格朗日方程本身和subject to ||w||^2<theta的模型是等价的,在这里用subject to 的模型来理解可能更简单
其实就是新的损失函数由两项组成,此时求导后,梯度有两项了,一项将w向绿线中心拉,一项将w向原点拉进,最后将在w*点达到一个平衡
每次都在权重更新之前对w做了一次放小(ηλ<1), 所以叫做权重衰退。
lambda是控制模型参数的超参数
2. 代码实现
%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l
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)
print(train_data[0], train_data[1])
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]
def l2_penalty(w):
return torch.sum(w.pow(2)) / 2 # w.pow(2) 幂函数 w的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.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:
# 增加了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)
train(lambd=3)
w的L2范数是: 12.036040306091309 # lambda=0
w的L2范数是: 0.03226672485470772 # lambda=3
lambd = 0
lambd = 3
3. QA
-
pytorch是否支持复数神经网络,nn输入输出权重激活函数都是复数,loss则是一个复数到实数的映射。
不支持。复数是把一个数做到二维,加一个第二维实现效果,不一定要用复数。 -
为什么参数不过大模型复杂度就低呢?
限制整个模型在优化的时候,是在很小的范围取参数。只能在在一些比较平滑的模型曲线上取参数,这样就学不出一个很复杂的模型。 -
如果是L1范数的话如何更新权重?
把上面的l2_penalty()函数内容,换成torch.abs(w)尝试
w的L1范数是: 0.7089653015136719return torch.sum(torch.abs(w)) ...... train(lambd=3)
-
实践中权重衰减的值一般设置为多少好?有时感觉权重衰减的效果并不好
一般取1e-2, 1e-3, 1e-4 (0.01, 0.001, 0.0001)。 权重衰退有一点点,但是不要太指望这个方法。如果模型很复杂,权重衰退没有很好的效果。可以试下 1e-3,效果不好换别的方法。 -
损失函数正则项中的2为什么使用上标而不是下标?之前介绍L2范数使用的是下标,是相同的概念?不太理解不同的数学记法。
上标是平方的意思L2的平方项,L2范数是在下标有2的,但是L2是默认的范数,所以一般都是省略的。 -
为什么要把w往小的啦?如果最优解的w就是比较大的数,那权重衰减是不是会有反作用?
数据是有噪音的,可能学到的不是真正的最优解,lambda过大过小都会和最优解离得比较远,所以选择的lambda值要合适。 -
L2 norm理解是让w的值变得更平均,没有突出的值为什么这样调整可以使得拟合更好呢?
不是让w更平均,而是让值更小一点。当没有lambda学到的范数很大的情况下,可以用lambda往回拉。但模型没有overfitting的时候,往回拉这种操作是没用的。 -
weight_decay的值一般怎么选择?有哪些实践经验?
试试1e-3这些值,没效果换方法。 -
实际应用中,lambda作为超参数是一次次在训练后调整优化了吗?调整到什么时候达到满意的效果?有什么方法论或最佳实践吗?
不知道什么时候最优。看看训练集和测试集曲线的差距,调下参数。
10 在解释数据噪音的时候,说如果噪音越大,w就比较大,是经验所得还是可以证明?
可以证明。噪音越大,学的w就越大,可以尝试一下。