文章目录

  • 一、什么是丢弃法,为什么丢弃法可以缓解过拟合?
  • 二、丢弃法的手动实现
  • 三、丢弃法的pytorch实现
  • 参考
  • 关于过拟合、欠拟合的解释可以参考我的博文:【pytorch】过拟合和欠拟合详解,并以三阶多项式函数绘图举例 (附pytorch.cat的用法)
  • 虽然增大训练数据集可能会减轻过拟合,但是获取额外的训练数据往往代价高昂。本篇博客将介绍应对过拟合问题的常用方法:权重衰减(weight decay)和丢弃法(dropout)。
  • 关于权重衰减的讲解参考我的博文:【pytorch】过拟合的应对办法 —— 权重衰减(并以具体实例详细推导、讲解)

一、什么是丢弃法,为什么丢弃法可以缓解过拟合?

由于丢弃法种类有很多,此处以倒置丢弃法(inverted dropout)来讲解。
下式为一个单隐藏层的多层感知机。其中输入个数为4,隐藏单元个数为5,且隐藏单元hih_ihi​(i=1,…,5i=1, \ldots, 5i=1,…,5)的计算表达式为

hi=ϕ(x1w1i+x2w2i+x3w3i+x4w4i+bi)h_i = \phi\left(x_1 w_{1i} + x_2 w_{2i} + x_3 w_{3i} + x_4 w_{4i} + b_i\right) hi​=ϕ(x1​w1i​+x2​w2i​+x3​w3i​+x4​w4i​+bi​)

这里ϕ\phiϕ是激活函数,x1,…,x4x_1, \ldots, x_4x1​,…,x4​是输入,隐藏单元iii的权重参数为w1i,…,w4iw_{1i}, \ldots, w_{4i}w1i​,…,w4i​,偏差参数为bib_ibi​。当对该隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉。设丢弃概率为ppp,那么有ppp的概率hih_ihi​会被清零,有1−p1-p1−p的概率hih_ihi​会除以1−p1-p1−p做拉伸。丢弃概率是丢弃法的超参数。具体来说,设随机变量ξi\xi_iξi​为0和1的概率分别为ppp和1−p1-p1−p。使用丢弃法时我们计算新的隐藏单元hi′h_i'hi′​

hi′=ξi1−phih_i' = \frac{\xi_i}{1-p} h_i hi′​=1−pξi​​hi​

由于E(ξi)=1−pE(\xi_i) = 1-pE(ξi​)=1−p,因此

E(hi′)=E(ξi)1−phi=hiE(h_i') = \frac{E(\xi_i)}{1-p}h_i = h_i E(hi′​)=1−pE(ξi​)​hi​=hi​

丢弃法不改变其输入的期望值。让我们对上图多层感知机中的隐藏层使用丢弃法,一种可能的结果如下图所示,其中h2h_2h2​和h5h_5h5​被清零。这时输出值的计算不再依赖h2h_2h2​和h5h_5h5​,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即h1,…,h5h_1, \ldots, h_5h1​,…,h5​都有可能被清零,输出层的计算无法过度依赖h1,…,h5h_1, \ldots, h_5h1​,…,h5​中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在进行测试模型的步骤时,我们为了拿到更加确定性的结果,一般不使用丢弃法。

  • 总而言之,丢弃法就是通过在进行卷积运算时,丢弃某一些神经原,每次只训练一部分神经元,从而让某一些神经原对其中一些数据不敏感,从而有效地防止了过拟合。
  • dropout函数示例
def dropout(X, drop_prob):X = X.float()assert 0 <= drop_prob <= 1keep_prob = 1 - drop_prob# 这种情况下把全部元素都丢弃if keep_prob == 0:return torch.zeros_like(X)mask = (torch.rand(X.shape) < keep_prob).float()return mask * X / keep_probX = torch.arange(16).view(2, 8)
dropout(X, 0)
dropout(X, 0.5)
dropout(X, 1.0)

二、丢弃法的手动实现

  • 代码
import torch
import torch.nn as nn
import numpy as np
import torchvisiondef evaluate_accuracy(data_iter, net):acc_sum, n = 0.0, 0for X, y in data_iter:if isinstance(net, torch.nn.Module):net.eval()  # 评估模式, 这会关闭dropoutacc_sum += (net(X).argmax(dim=1) == y).float().sum().item()net.train()  # 改回训练模式else:  # 自定义的模型if ('is_training' in net.__code__.co_varnames):  # 如果有is_training这个参数# 将is_training设置成Falseacc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item()else:acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()n += y.shape[0]return acc_sum / ndef load_data_fashion_mnist(batch_size, resize=None, root='./data'):"""Download the fashion mnist dataset and then load into memory."""trans = []if resize:trans.append(torchvision.transforms.Resize(size=resize))trans.append(torchvision.transforms.ToTensor())transform = torchvision.transforms.Compose(trans)mnist_train = torchvision.datasets.FashionMNIST(root=root, train=True, download=True, transform=transform)mnist_test = torchvision.datasets.FashionMNIST(root=root, train=False, download=True, transform=transform)num_workers = 0  # 0表示不用额外的进程来加速读取数据train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)return train_iter, test_iterdef dropout(X, drop_prob):X = X.float()assert 0 <= drop_prob <= 1keep_prob = 1 - drop_prob# 这种情况下把全部元素都丢弃if keep_prob == 0:return torch.zeros_like(X)mask = (torch.rand(X.shape) < keep_prob).float()return mask * X / keep_probdef net(X, is_training=True):X = X.view(-1, num_inputs)H1 = (torch.matmul(X, W1) + b1).relu()if is_training:  # 只在训练模型时使用丢弃法H1 = dropout(H1, drop_prob1)  # 在第一层全连接后添加丢弃层H2 = (torch.matmul(H1, W2) + b2).relu()if is_training:H2 = dropout(H2, drop_prob2)  # 在第二层全连接后添加丢弃层return torch.matmul(H2, W3) + b3def sgd(params, lr, batch_size):# 为了和原书保持一致,这里除以了batch_size,但是应该是不用除的,因为一般用PyTorch计算loss时就默认已经# 沿batch维求了平均了。for param in params:param.data -= lr * param.grad / batch_size  # 注意这里更改param时用的param.datadef train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size,params=None, lr=None, optimizer=None):for epoch in range(num_epochs):train_l_sum, train_acc_sum, n = 0.0, 0.0, 0for X, y in train_iter:y_hat = net(X)l = loss(y_hat, y).sum()# 梯度清零if optimizer is not None:optimizer.zero_grad()elif params is not None and params[0].grad is not None:for param in params:param.grad.data.zero_()l.backward()if optimizer is None:sgd(params, lr, batch_size)else:optimizer.step()  # “softmax回归的简洁实现”一节将用到train_l_sum += l.item()train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()n += y.shape[0]test_acc = evaluate_accuracy(test_iter, net)print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'% (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))if __name__ == '__main__':num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256W1 = torch.tensor(np.random.normal(0, 0.01, size=(num_inputs, num_hiddens1)), dtype=torch.float, requires_grad=True)b1 = torch.zeros(num_hiddens1, requires_grad=True)W2 = torch.tensor(np.random.normal(0, 0.01, size=(num_hiddens1, num_hiddens2)), dtype=torch.float,requires_grad=True)b2 = torch.zeros(num_hiddens2, requires_grad=True)W3 = torch.tensor(np.random.normal(0, 0.01, size=(num_hiddens2, num_outputs)), dtype=torch.float,requires_grad=True)b3 = torch.zeros(num_outputs, requires_grad=True)params = [W1, b1, W2, b2, W3, b3]drop_prob1, drop_prob2 = 0.2, 0.5num_epochs, lr, batch_size = 5, 100.0, 256loss = torch.nn.CrossEntropyLoss()train_iter, test_iter = load_data_fashion_mnist(batch_size)train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)
  • 结果
epoch 1, loss 0.0047, train acc 0.538, test acc 0.723
epoch 2, loss 0.0023, train acc 0.779, test acc 0.779
epoch 3, loss 0.0020, train acc 0.818, test acc 0.807
epoch 4, loss 0.0018, train acc 0.838, test acc 0.832
epoch 5, loss 0.0016, train acc 0.848, test acc 0.843

三、丢弃法的pytorch实现

  • 代码
import torch
import torch.nn as nn
import numpy as np
import torchvisionfrom d2lzh_pytorch import utils as d2ldef evaluate_accuracy(data_iter, net):acc_sum, n = 0.0, 0for X, y in data_iter:# isinstance()函数来判断一个对象是否是一个已知的类型,类似type()。# isinstance()与type()区别:# type()不会认为子类是一种父类类型,不考虑继承关系。# isinstance()会认为子类是一种父类类型,考虑继承关系。如果要判断两个类型是否相同推荐使用isinstance()。if isinstance(net, torch.nn.Module):net.eval()  # 评估模式, 这会关闭dropoutacc_sum += (net(X).argmax(dim=1) == y).float().sum().item()net.train()  # 改回训练模式else:  # 自定义的模型if ('is_training' in net.__code__.co_varnames):  # 如果有is_training这个参数# 将is_training设置成Falseacc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item()else:acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()n += y.shape[0]return acc_sum / ndef load_data_fashion_mnist(batch_size, resize=None, root='./data'):"""Download the fashion mnist dataset and then load into memory."""trans = []if resize:trans.append(torchvision.transforms.Resize(size=resize))trans.append(torchvision.transforms.ToTensor())transform = torchvision.transforms.Compose(trans)mnist_train = torchvision.datasets.FashionMNIST(root=root, train=True, download=True, transform=transform)mnist_test = torchvision.datasets.FashionMNIST(root=root, train=False, download=True, transform=transform)num_workers = 0  # 0表示不用额外的进程来加速读取数据train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)return train_iter, test_iter# Flatten层用来将输入“压平”,即把多维的输入一维化,常用在从卷积层到全连接层的过渡。Flatten不影响batch的大小。
class FlattenLayer(torch.nn.Module):def __init__(self):super(FlattenLayer, self).__init__()def forward(self, x):  # x shape: (batch, *, *, ...)return x.view(x.shape[0], -1)def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size,params=None, lr=None, optimizer=None):for epoch in range(num_epochs):train_l_sum, train_acc_sum, n = 0.0, 0.0, 0for X, y in train_iter:y_hat = net(X)l = loss(y_hat, y).sum()# 梯度清零if optimizer is not None:optimizer.zero_grad()elif params is not None and params[0].grad is not None:for param in params:param.grad.data.zero_()l.backward()# 所有的optimizer都实现了step()方法,这个方法会更新所有的参数。optimizer.step()  # “softmax回归的简洁实现”一节将用到train_l_sum += l.item()train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()n += y.shape[0]test_acc = evaluate_accuracy(test_iter, net)print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'% (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))if __name__ == '__main__':num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256drop_prob1, drop_prob2 = 0.2, 0.5num_epochs, batch_size = 5, 256loss = torch.nn.CrossEntropyLoss()net = nn.Sequential(FlattenLayer(),nn.Linear(num_inputs, num_hiddens1),nn.ReLU(),nn.Dropout(drop_prob1),nn.Linear(num_hiddens1, num_hiddens2),nn.ReLU(),nn.Dropout(drop_prob2),nn.Linear(num_hiddens2, num_outputs))for param in net.parameters():nn.init.normal_(param, mean=0, std=0.01)optimizer = torch.optim.SGD(net.parameters(), lr=0.5)train_iter, test_iter = load_data_fashion_mnist(batch_size)train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)
  • 结果
epoch 1, loss 0.0044, train acc 0.561, test acc 0.771
epoch 2, loss 0.0023, train acc 0.787, test acc 0.757
epoch 3, loss 0.0019, train acc 0.825, test acc 0.829
epoch 4, loss 0.0017, train acc 0.841, test acc 0.788
epoch 5, loss 0.0016, train acc 0.846, test acc 0.814

参考

【pytorch】过拟合和欠拟合详解,并以三阶多项式函数绘图举例 (附pytorch.cat的用法)
【pytorch】过拟合的应对办法 —— 权重衰减(并以具体实例详细推导、讲解)
动手学深度学习

【pytorch】过拟合的应对办法 —— 丢弃法(dropout)相关推荐

  1. 丢弃法——dropout

    <动手学深度学习pytorch>部分学习笔记,仅用作自己复习. 丢弃法--dropout 除了权重衰减以外,深度学习模型常使⽤丢弃法(dropout) 来应对过拟合问题.丢弃法有一些不同的 ...

  2. 丢弃法Dropout

    丢弃法Dropout:一种抑制过拟合的方法. 上图中提到的两种解决方案:1.downgrade_in_infer:训练时随机丢弃一部分神经元:预测时不丢弃神经元,这里提到的不丢弃神经元是指预测时不丢弃 ...

  3. 丢弃法(dropout)

    1 对于丢弃法的一点小思考 (1) 对于模型设计我们可以把隐藏层设计的稍微大一点然后用drop out控制隐藏层大小这样的设计可能比隐藏层设计的小一点的效果更好,防止过拟合,drop out 其实就是 ...

  4. 【深度学习】丢弃法(dropout)

    丢弃法 在小虾的这篇文章中介绍了权重衰减来应对过拟合问题(https://blog.csdn.net/qq_33432841/article/details/107879937),下面在介绍一种应对过 ...

  5. [pytorch、学习] - 3.13 丢弃法

    参考 3.13 丢弃法 过拟合问题的另一种解决办法是丢弃法.当对隐藏层使用丢弃法时,隐藏单元有一定概率被丢弃. 3.12.1 方法 3.13.2 从零开始实现 import torch import ...

  6. Pytorch与drop_out(丢弃法)

    简述 深度学习模型常常使用丢弃法(dropout)[1] 来应对过拟合问题.丢弃法有一些不同的变体.文中提到的丢弃法特指倒置丢弃法(inverted dropout). 对于激活函数而言有: hi=ϕ ...

  7. PyTorch——Dropout(丢弃法)

    参考链接 https://tangshusen.me/Dive-into-DL-PyTorch/#/chapter03_DL-basics/3.13_dropout dropout 深度学习模型常常使 ...

  8. 动手学深度学习V2.0(Pytorch)——13.丢弃法

    文章目录 1. 课件讲解 插一句(正则的分类) 2. Q&A 2.1 dropout是初次生效,还是每次都重新选取概率 2.2 dropout的感性评价 2.3 dropout随机置0对求梯度 ...

  9. 《动手学深度学习》丢弃法(dropout)

    丢弃法(dropout) 丢弃法 方法 从零开始实现 定义模型参数 定义模型 训练和测试模型 简洁实现 小结 参考文献 丢弃法 除了前一节介绍的权重衰减以外,深度学习模型常常使用丢弃法(dropout ...

最新文章

  1. Scala for循环示例
  2. python写数据结构书_有哪些用 Python 语言讲算法和数据结构的书?
  3. 【BLE】TLSR8258开发记录之15--模拟FATFS
  4. 1.1 sql注入分类与详解
  5. java heap space flex_Flash builder 4内存优化之java heap space解决办法
  6. C++课程上 有关“指针” 的小结
  7. 2019年物联网发展趋势与预测分析
  8. 鼠标移至图片后抖动的JS代码
  9. 吴恩达深度学习作业L1W2:ValueError: cannot reshape array of size 12288 into shape (50,1)
  10. div旋转45度_一看就会,一做不废的旋转楼梯建模
  11. 2B or 2c : 做2019的幸存者
  12. EMP电磁脉冲射频发射器制作教程
  13. 一步教你如何开通支付宝手机网站支付,微信h5收款,降低支付宝当面付费率
  14. 【复盘】如何打造自己的研发能力
  15. Adaptive AutoSAR 标准介绍
  16. 魔百盒cm311-1a yst 青龙
  17. 更快、更 Pythonic 的 PyTorch 2.0 | 非常值得期待
  18. 验证随机数案例java_Java实现随机验证码功能实例代码
  19. IP核Map编译报错:Buffers of the same direction cannot beplaced in series.
  20. 网线如何制作和如何使用?

热门文章

  1. VS2017+qt 缺少根元素
  2. python的星号(*)和双星号(**)运算符的使用
  3. 关于青春的某点回忆(钢铁是怎么炼成的)2007-04-24 2
  4. 手机卖了 微信如何关掉订阅服务器,微信订阅号消息怎么关闭?详细方法介绍
  5. pacman常用命令汇总
  6. java 字符串驻留_【Java中的字符串驻留】
  7. 电大java语言程序设计_国家开放大学电大Java语言程序设计形考任务1答案
  8. 美版「蚂蚁花呗」上市记
  9. 私有文件服务器系统,GitHub - xty438307820/NetDisk-Private: 基于Linux的私有文件服务器(网盘)...
  10. I-SOON CTF