Pytorch深度学习【九】

权重衰退—处理过拟合的一种方法—L2正则化

  • L1正则化
    • L1正则化的作用是使得大部分模型参数的值等于0,这样一来,当模型训练好后,这些权值等于0的特征可以省去,从而达到稀疏化的目的,也节省了存储的空间,因为在计算时,值为0的特征都可以不用存储了。
  • L2正则化
    • L2正则化对于绝对值较大的权重予以很重的惩罚,对于绝对值很小的权重予以非常非常小的惩罚,当权重绝对值趋近于0时,基本不惩罚。这个性质与L2的平方项有关系,即越大的数,其平方越大,越小的数,比如小于1的数,其平方反而越小。
    • 公式
      m i n ℓ ( w , b ) + λ 2 ∣ ∣ w ∣ ∣ 2 min \ell(w, b) + \frac{\lambda}{2} ||w||^2 min(w,b)+2λ∣∣w2
      λ 越大可以简化模型的复杂度 \lambda 越大可以简化模型的复杂度 λ越大可以简化模型的复杂度
    • 可以这样理解我们的寻找最优解的目标函数发生了变化
      • 之前:
        只求 m i n ℓ ( w , b ) 只求min \ell(w,b) 只求min(w,b)
      • 引入正则化后:
        求 m i n ℓ ( w , b ) 和 λ 2 ∣ ∣ w ∣ ∣ 2 的交点处 求min \ell(w,b)和\frac{\lambda}{2} ||w||^2的交点处 min(w,b)2λ∣∣w2的交点处
    • 本质上引入正则化后导致所求解的最优解向原点走,这样使得最优解的值变小就等于缩小了超参数范围,从而降低了模型复杂度
  • L2正则化和L1正则化的区别—存在权重衰减
  • 正则化其实都是为了优化损失函数,寻求最优解
  • 如何理解L2正则化可以解决过拟合?
    • 正则化其实通过限制权重范围从而实现模型超参数取值范围的缩小从而解决过拟合问题
  • 为什么叫做权重衰退呢?—我们从公式的角度进行分析
  • 计算梯度
    ∂ ∂ w ( ℓ ( w , b ) + λ 2 ∣ ∣ w ∣ ∣ 2 ) = ∂ ℓ ( w , b ) ∂ w + λ w \frac{\partial}{\partial w}(\ell(w,b)+\frac{\lambda}{2}||w||^2)=\frac{\partial{\ell(w,b)}}{\partial w}+\lambda w w((w,b)+2λ∣∣w2)=w(w,b)+λw
  • 带入权重更新式
    w t + 1 = w t − η ∂ ∂ w t w_{t+1}=w_t-\eta\frac{\partial}{\partial{w_t}} wt+1=wtηwt
  • 权重更新公式
    w t + 1 = ( 1 − η λ ) w t − η ∂ ℓ ( w t , b t ) ∂ w t w_{t+1}=(1-\eta\lambda)w_t-\eta\frac{\partial{\ell(w_t,b_t)}}{\partial{w_t}} wt+1=(1ηλ)wtηwt(wt,bt)
    • 通常 η λ < 1 \eta\lambda < 1 ηλ<1,在深度学习中通常叫做权重衰退
    • 每次权重更新会先减小原来的w在进行梯度
  • 总结
    • 权重衰退通过L2正则项使得模型参数不会过大,从而控制模型复杂度
    • 正则项权重是控制模型复杂度的超参数
  • 代码实现
def l2_penslty(w):
  return torch.sum(w.pow(2))/2
lambd*l2_penslty(w)
  • 本质上就是给损失函数加入正则项,达到缩减参数取值范围的目的
  • lambd越大对过拟合的抑制更强
  • 简洁实现
trainer = torch.optim.SGD(net.parameters(), lr=0.1)
# 使用学习率为0.1对小批量随机梯度下降作为优化算法
# 将上面改为
trainer = torch.optim.SGD(model.parameters(), lr=0.1, weight_decay=0.001)
# 这里直接设置lambd

丢弃法—比权重衰退更好—只在训练中使用

  • 动机
    • 一个好的模型需要对输入数据的扰动具有鲁棒性
    • dropout相当于在层之间加入噪音
  • 无偏差的加入噪音
    • x x x加入噪声得到 x ′ x^{'} x,我们希望 E [ x ′ ] = x E[x^{'}]= x E[x]=x
    • 丢弃法对于每个元素进行如下扰动
      x i ′ = { 0 with probablity p x i 1 − p otherise x_i^{'}=\begin{cases} 0& \text{with probablity p}\\ {\frac{x_i}{1-p}}& \text{otherise} \end{cases} xi={01pxiwith probablity potherise
    • 为什么要 1 − p 1-p 1p?—我们希望期望不能发生变化
      E [ x ′ ] = p ∗ 0 + ( 1 − p ) ∗ x i 1 − p E[x^{'}]= p*0 + (1-p)*\frac{x_i}{1-p} E[x]=p0+(1p)1pxi
  • 使用丢弃法
    • 通常将丢弃法作用在隐藏全连接层的输出上
    • 我们以一个一层隐藏层的模型来进行计算说明
      h = σ ( W 1 x + b 1 ) h = \sigma(W_1x+b_1) h=σ(W1x+b1)
      h ′ = d r o p o u t ( h ) h^{'} = dropout(h) h=dropout(h)
      o = W 2 h ′ + b 2 o = W_2h^{'}+b_2 o=W2h+b2
      y = s o f t m a x ( o ) y = softmax(o) y=softmax(o)
  • 正则项只在训练中使用
  • 在推理过程中,丢弃法直接返回输入
  • 总结
    • 丢弃法将一些输出项随机置0来控制模型复杂度
    • 常作用在多层感知机的隐藏层输出上
    • 丢弃概率是控制模型复杂度的超参数
  • 从零完全代码实现
!pip install d2l
!pip install matplotlib_inline
%matplotlib
import torch
from torch import nn
from d2l import torch as d2l
def dropout_layer(X, dropout):
  assert 0 <= dropout <= 1
  if dropout == 1 :
    return torch.zeros_like(X)
  if dropout == 0:
    return X
  mask = (torch.randn(X.shape) > dropout).float()
  # randn 生成0-1之间的均匀随机分布---比较后生成01矩阵
  return (mask * X)/(1.0 - dropout)
# 定义一个有两个隐藏层的多层感知机,每个隐藏层包含256个单元
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
dropout1 ,dropout2 = 0.2, 0.5
class Net(nn.Module):
  def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training=True):
    # is_training=True会调用
    super(Net, self).__init__()
    self.inputs = num_inputs
    self.training = is_training
    self.lin1 = nn.Linear(num_inputs, num_hiddens1)
    self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
    self.lin3 = nn.Linear(num_hiddens2, num_outputs)
    self.relu = nn.ReLU()
  def forward(self, X):
    # 当我们使用model(input)的形式来调用模型时,PyTorch会自动调用模型的forward方法,并将输入张量传递给它。
    H1 = self.relu(self.lin1(X.reshape(-1, self.inputs)))
    if self.training == True:
      H1 = dropout_layer(H1, dropout1)
    H2 = self.relu(self.lin2(H1))
    if self.training == True:
      H2 = dropout_layer(H2, dropout2)
    out = self.lin3(H2)
    return out
net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training=True)
!pip install matplotlib==3.0
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss()
trainer = torch.optim.SGD(net.parameters(), lr=lr)
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
  • 简洁实现
import torch
from torch import nn
dropout1, dropout2 = 0.2, 0.5
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(), 
                    nn.Dropout(dropout1), nn.Linear(256, 256), nn.ReLU(), 
                    nn.Dropout(dropout2), nn.Linear(256, 10))
def init_weights(m):
  if type(m) == nn.Linear:
    nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss()
trainer = torch.optim.SGD(net.parameters(), lr=lr)
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

你可能感兴趣的:(深度学习,pytorch)