文章目录

  • 1. 方法
  • 2. 从零开始实现
    • 2.1 定义模型参数
    • 2.2 定义模型
    • 2.3 训练和测试模型
  • 3. 简洁实现
  • 小结

除了前一节介绍的权重衰减以外,深度学习模型常常使用丢弃法(dropout)来应对过拟合问题。

1. 方法

这里有一个单隐藏层的多层感知机。其中输入个数为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​

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

2. 从零开始实现

根据丢弃法的定义,我们可以很容易地实现它。下面的dropout函数将以drop_prob的概率丢弃X中的元素。

%matplotlib inline
import torch
import torch.nn as nn
import numpy as np
import sys
sys.path.append("..")
import d2lzh_pytorch as d2ldef 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_prob

我们运行几个例子来测试一下dropout函数。其中丢弃概率分别为0、0.5和1。

X = torch.arange(16).view(2, 8)
dropout(X, 0)
dropout(X, 0.5)
dropout(X, 1.0)

2.1 定义模型参数

实验中,我们依然使用Fashion-MNIST数据集。我们将定义一个包含两个隐藏层的多层感知机,其中两个隐藏层的输出个数都是256。

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]

2.2 定义模型

下面定义的模型将全连接层和激活函数ReLU串起来,并对每个激活函数的输出使用丢弃法。我们可以分别设置各个层的丢弃概率。通常的建议是把靠近输入层的丢弃概率设得小一点。在这个实验中,我们把第一个隐藏层的丢弃概率设为0.2,把第二个隐藏层的丢弃概率设为0.5。我们可以通过参数is_training来判断运行模式为训练还是测试,并只需在训练模式下使用丢弃法。

drop_prob1, drop_prob2 = 0.2, 0.5def 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) + b3

我们在对模型评估的时候不应该进行丢弃:

def 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 / n

2.3 训练和测试模型

def sgd(params, lr, batch_size):for param in params:param.data -= lr * param.grad / batch_size # 注意这里更改param时用的param.data

定义训练模型:

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, m = 0.0, 0.0, 0, 0for X, y in train_iter:y_hat = net(X)l = loss(y_hat, y)# 梯度清零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]m += 1test_acc = evaluate_accuraacy(test_iter, net)print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'% (epoch + 1, train_l_sum / m, train_acc_sum / n, test_acc))
num_epochs, lr, batch_size = 5, 100.0, 256
loss = torch.nn.CrossEntropyLoss()
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)

输出:

epoch 1, loss 0.0044, train acc 0.574, test acc 0.648
epoch 2, loss 0.0023, train acc 0.786, test acc 0.786
epoch 3, loss 0.0019, train acc 0.826, test acc 0.825
epoch 4, loss 0.0017, train acc 0.839, test acc 0.831
epoch 5, loss 0.0016, train acc 0.849, test acc 0.850

3. 简洁实现

在PyTorch中,我们只需要在全连接层后添加Dropout层并指定丢弃概率。在训练模型时,Dropout层将以指定的丢弃概率随机丢弃上一层的输出元素;在测试模型时(即model.eval()后),Dropout层并不发挥作用。

net = nn.Sequential(d2l.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, 10))for param in net.parameters():nn.init.normal_(param, mean=0, std=0.01)

下面训练并测试模型。

optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)

输出:

epoch 1, loss 0.0045, train acc 0.553, test acc 0.715
epoch 2, loss 0.0023, train acc 0.784, test acc 0.793
epoch 3, loss 0.0019, train acc 0.822, test acc 0.817
epoch 4, loss 0.0018, train acc 0.837, test acc 0.830
epoch 5, loss 0.0016, train acc 0.848, test acc 0.839

小结

  • 我们可以通过使用丢弃法应对过拟合。
  • 丢弃法只在训练模型时使用。

pytorch学习笔记(十三):Dropout相关推荐

  1. 深度学习入门之PyTorch学习笔记:卷积神经网络

    深度学习入门之PyTorch学习笔记 绪论 1 深度学习介绍 2 深度学习框架 3 多层全连接网络 4 卷积神经网络 4.1 主要任务及起源 4.2 卷积神经网络的原理和结构 4.2.1 卷积层 1. ...

  2. 深度学习入门之PyTorch学习笔记:多层全连接网络

    深度学习入门之PyTorch学习笔记 绪论 1 深度学习介绍 2 深度学习框架 3 多层全连接网络 3.1 PyTorch基础 3.2 线性模型 3.2.1 问题介绍 3.2.2 一维线性回归 3.2 ...

  3. PyTorch学习笔记(五):模型定义、修改、保存

    往期学习资料推荐: 1.Pytorch实战笔记_GoAI的博客-CSDN博客 2.Pytorch入门教程_GoAI的博客-CSDN博客 本系列目录: PyTorch学习笔记(一):PyTorch环境安 ...

  4. PyTorch学习笔记(四):PyTorch基础实战

    PyTorch实战:以FashionMNIST时装分类为例: 往期学习资料推荐: 1.Pytorch实战笔记_GoAI的博客-CSDN博客 2.Pytorch入门教程_GoAI的博客-CSDN博客 本 ...

  5. PyTorch学习笔记(三):PyTorch主要组成模块

    往期学习资料推荐: 1.Pytorch实战笔记_GoAI的博客-CSDN博客 2.Pytorch入门教程_GoAI的博客-CSDN博客 本系列目录: PyTorch学习笔记(一):PyTorch环境安 ...

  6. PyTorch学习笔记2:nn.Module、优化器、模型的保存和加载、TensorBoard

    文章目录 一.nn.Module 1.1 nn.Module的调用 1.2 线性回归的实现 二.损失函数 三.优化器 3.1.1 SGD优化器 3.1.2 Adagrad优化器 3.2 分层学习率 3 ...

  7. PyTorch学习笔记(13)--现有网络模型的使用及修改

    PyTorch学习笔记(13)–现有网络模型的使用及修改     本博文是PyTorch的学习笔记,第13次内容记录,主要介绍如何使用现有的神经网络模型,如何修改现有的网络模型. 目录 PyTorch ...

  8. PyTorch学习笔记(六)——Sequential类、参数管理与GPU

    系列文章\text{\bf 系列文章}系列文章 PyTorch学习笔记(一)--Tensor的基础语法 PyTorch学习笔记(二)--自动微分 PyTorch学习笔记(三)--Dataset和Dat ...

  9. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

  10. pytorch学习笔记(二):gradien

    pytorch学习笔记(二):gradient 2017年01月21日 11:15:45 阅读数:17030

最新文章

  1. 暑期项目经验(十)--struts + poi
  2. 一位资深Java的阿里系公司实战面试经验,套路还是面试官的多
  3. C++智能指针使用指南 part1:基本使用
  4. Python 中的range,以及numpy包中的arange函数
  5. 【Java线程池】Java线程池汇总,看这一篇文章就够了
  6. CTF-Bugku逆向题Android方法归纳
  7. js给百度地图上的圆点加自定义动画_three.js实现建筑物纹理流动
  8. 不是男人也要上100层:Unity专为AI开发了游戏,还启动了10万美元挑战赛
  9. linux mysql5.6数据目录,Linux下Mysql5.6 二进制安装过程
  10. 三菱伺服电机选型技巧
  11. open ai gpt_GPT-3:第一个人工智能?
  12. 模拟DVD 实现录入 查看 借出 归还 删除 新增 等功能分层
  13. 在三星smart TV上开发widget-入门篇 1
  14. python脚本:txt文件转为excel
  15. 用grads读取txt中经纬度画站点图
  16. 润科通用 Java开发工程师 面试
  17. matlab中的rand ,randn,和randi函数
  18. 七步成诗-快速创建有效SLO
  19. 爬虫-菜谱信息爬取(保存至数据库)
  20. 如何设计伟大产品:要学会讲故事

热门文章

  1. javascript判断非空
  2. 编程调节Win7/Win8系统音量的一种方法
  3. 【Android】LMK 工作机制
  4. mediamind SyncAds
  5. 如何实现插入数据时自动更新另外一个表的内容
  6. WEB API Filter的使用以及执行顺序
  7. 深度学习-CNN tensorflow 可视化
  8. PAT——乙级1036:跟奥巴马一起编程 乙级1027:打印沙漏 (有坑)
  9. Roundcube Webmail跨站脚本漏洞(CVE-2015-5381 )
  10. CSS定位属性(position)