Weight Decay & Dropout

Concept and Principle

  • 权重衰退
    权重衰退可以控制模型复杂度,使其复杂度不会太大,从而一定程度上避免过拟合
    • 使用均方范数作为硬性限制
      通过限制参数的取值范围来控制模型容量,具体有如下例子
      在限制参数向量范数的情况下优化损失函数,一般不会使用这种正则方式
    • 使用均方范数作为柔性限制
      上述硬性限制有一个等价方案,具体如下,这就是一般的正则化方法,其作用同样也是使得参数被限制在一个较小的范围

      下面是正则项对最优解影响的一个演示
      坐标轴分别是w的各个分量,圆线是等高线。
      正则项给了另外一个梯度,把原始的损失函数算出的最优解往原点拉,必然会导致W的取值范围变小从而使模型复杂度降低,也就减小了过拟合。另外一种理解,正则项加入后优化目标就不再全局最优点了,所以肯定会减小训练集拟合程度,也就减小了过拟合
      考虑为什么λ控制了正则项的重要程度,因为求偏导时λ会变成梯度前的常数项
    • 参数更新
      带正则项后参数更新过程如下,这也说明了为什么这种方法叫权重衰退:更新前先把权重减小,然后继续更新梯度
    • 注意
      权重衰减也只在训练过程中使用,用来限制训练过程中的参数,在最终的验证过程中,指标还是原先的损失函数
  • 丢弃法
    • 动机
      一个好的模型需要对输入数据加入扰动鲁棒,使用有噪音的数据等价于Tikhonov正则。丢弃法就是在层之间加入噪音,丢弃法也可以看作一个正则
    • 无偏差地加入噪音
      丢弃法就是加入了无偏噪音
    • 使用丢弃法
      • 对其发作用域隐藏层地输出上,即随机将某些神经元的输出置零且其它输出按上述公式增大
      • 丢弃法只在训练过程中使用,测试和验证过程中不使用,这样保证了确定的输出
      • 丢弃法常用于全连接层

Implementation

  • 权重衰减从零实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import torch
from torch import nn,optim
from d2l import *

# 训练数据设置比较小,容易过拟合
num_train=20
num_test=100
num_inputs=200
batch_size=5

true_w,true_b=torch.ones(num_inputs)*0.01,0.05

train_data=synthetic_data(true_w,true_b,num_train)
train_iter=data_loader(train_data,batch_size)
test_data=synthetic_data(true_w,true_b,num_test)
test_iter=data_loader(test_data,batch_size)

# for X,y in train_iter:
# print(X,y)
w=torch.normal(0,1,size=true_w.shape,requires_grad=True)
b=torch.zeros(1,requires_grad=True)

# L2正则
def L2_penalty(lambada,w):
return torch.sum(w**2)/2*lambada

def liner_reg(w,b,X):
return torch.matmul(X,w)+b

def net(X):
return liner_reg(w,b,X)

def squared_loss_L2(y_hat,y):
loss=(y_hat.view(y.shape)-y)**2/2/len(y)
return (loss+L2_penalty(0.5,w)).sum()

opt=optim.SGD([w,b],lr=0.01)



train(100,squared_loss_L2,opt,net,train_iter,test_iter)
  • 权重衰减简洁实现
1
2
3
4
5
6
7
8
9
10
net=nn.Sequential(nn.Linear(num_inputs,1))
loss_f=nn.MSELoss()
# weight_decay代表了L2范数前面的λ系数
# 权重衰减系数很小时,在当前数据集下过拟合非常明显
# 权重衰减系数很大时,欠拟合则会非常明显
opt=optim.SGD(net.parameters(),lr=0.01,weight_decay=1.2)

train(100,loss_f,opt,net,train_iter,test_iter)
# 其它范数的正则pytorch没有直接的实现
# 手动实现也很简单