动手学PyTorch(李沐)7 ---- 丢弃法

丢弃法

​ 丢弃法符合正则的实验结果,主流把dropout当作正则项。把输入变成0和把中间结果变成0,都可以认为是正则项。

在训练过程中,他们建议在计算后续层之前向⽹络的每⼀层注⼊噪声。因为当训练⼀个有多层的深层⽹络时,注⼊噪声只会在输⼊-输出映射上增强平滑性。这个想法被称为暂退(dropout)。暂退法在前向传播过程中,计算每⼀内部层的同时注⼊噪声,这已经成为训练神经⽹络的常⽤技术。这种⽅法之所以被称为暂退法,因为我们从表⾯上看是在训练过程中丢弃(dropout)⼀些神经元。在整个训练过程的每⼀次迭代中,标准暂退法包括在计算下⼀层之前将当前层中的⼀些节点置零。

总结

​ 丢弃概率通常为0.5,0.9,0.3

​ 通常,我们在测试时不⽤暂退法。给定⼀个训练好的模型和⼀个新的样本,我们不会丢弃任何节点,因此不需要标准化。然⽽也有⼀些例外:⼀些研究⼈员在测试时使⽤暂退法,⽤于估计神经⽹络预测的“不确定性”:如果通过许多不同的暂退法遮盖后得到的预测结果都是⼀致的,那么我们可以说⽹络发挥更稳定。

​ dropout一般作用在全连接隐藏层的输出上,作用后的结果作为下一层的输入。

​ dropout为模型设计提供了一个新思路,即将模型设计深一点,隐藏层设计大一点,通过调大丢弃率,来控制隐藏层大小和模型复杂度,这可能会有一个不错的效果。

QA

  • dropout置0,梯度也会变成0,没有置0的地方,梯度也会相应乘以一个数(1/(1-p)),dropout为0对应的那一批权重在本轮就不会被更新。也就相当于,每一轮在网络当中随机采一些小网络来对权重进行更新。
  • dropout太大可能欠拟合,太小可能过拟合
  • 可能128+dropout0.5效果比64好

实现

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.rand(X.shape) > dropout).float()
  # print('\n',mask,'\n')
  '''
   torch,randn(x.shape)生成一个输入大小的0到1之间的正态分布向量,
   如果向量单元值大于dropout就选出来等于一。mask就是说哪些东西要等于0,
   哪些东西要等于1.
   X[mask]=0  这种写法对GPU不友好

   调用的是随机数,每一次置为0的位置是不一样的。
  '''
  return mask * X / (1.0 - dropout)
X = torch.arange(16,dtype=torch.float32).reshape((2,8))
print(X)
print(dropout_layer(X,0.))
print(dropout_layer(X,0.5))
print(dropout_layer(X,1.))
# 设置输入输出和两个隐藏层的大小
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
# 设置两个隐藏层的丢弃概率
dropout1, dropout2 = 0.2, 0.5
# Net类继承于nn.Module
class Net(nn.Module):
  def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
               is_training = True):
    super(Net, self).__init__()
    self.num_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):
    # 第一个隐藏层通过relu激活函数的输出
    H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
    # 只有在训练模型时才使⽤dropout
    if self.training == True:
      # 在第⼀个全连接层之后添加⼀个dropout层
      H1 = dropout_layer(H1, dropout1)
    # 把H1放到第二个隐藏层,得到H2
    H2 = self.relu(self.lin2(H1))
    if self.training == True:
      # 在第⼆个全连接层之后添加⼀个dropout层
      H2 = dropout_layer(H2, dropout2)
    out = self.lin3(H2)
    """dropout一般作用在全连接隐藏层的输出上"""
    return out
net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss()
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

在这里插入图片描述

调用

net = nn.Sequential(nn.Flatten(),
  # 先将输入拉平成二维
  # 第一个全连接层,784输入,256第一隐藏层大小
  nn.Linear(784, 256),
  nn.ReLU(),
  # 在第⼀个全连接层之后添加⼀个dropout层
  nn.Dropout(dropout1),
  # 第二个全连接层,256输入,256第二隐藏层大小
  nn.Linear(256, 256),
  nn.ReLU(),
  # 在第⼆个全连接层之后添加⼀个dropout层
  nn.Dropout(dropout2),
  # 第三个全连接层,256输入,10输出
  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);
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值