当前位置: 首页 > news >正文

深度学习------------丢弃法dropout

目录

  • 动机
  • 无偏差的加入噪音
  • 使用丢弃法
  • 推理中的丢弃法
  • 总结
  • 从零开始实现
    • Dropout
    • 定义模型参数
    • 定义模型
    • 训练和测试
    • 代码实现
    • 简洁代码实现
  • 问题

在这里插入图片描述

动机

一个好的模型需要对你输入数据的扰动 鲁棒

    使用有噪音的数据等价于Tikhnov正则
    丢弃法:在层之间加入噪音




无偏差的加入噪音

假设x是一层到下一层的输入的话
对x加入噪音得到 x ′ x^{'} x。我们希望
在这里插入图片描述
(即:虽然我们加入了噪音,但不要改变我们的期望,即这个值还是对的)


丢弃法对每个元素进行如下扰动
在这里插入图片描述
也可以这样表示
在这里插入图片描述

一部分概率变成0,一部分数据变大(其中p∈(0,1))

期望没有变化
在这里插入图片描述


使用丢弃法

通常将丢弃法作用在隐藏全连接层的输出上
在这里插入图片描述

在这里插入图片描述

h 2 h_2 h2 h 5 h_5 h5被换成0了。


推理中的丢弃法

正则项只在训练中使用(这是因为dropout是一个正则项,它只会对权重有影响,当进行预测的时候权重不需要发生变化情况,是不需要正则的):它们影响模型参数的更新。
在推理过程中,丢弃法直接返回输入

在这里插入图片描述
这样也能保证确定性的输出




总结

①丢弃法将一些输出项随机置0来控制模型复杂度
②常作用在多层感知机的隐藏层输出上
③丢弃概率是控制模型复杂度的超参数




从零开始实现

Dropout

    要实现单层的暂退法函数, 我们从均匀分布 𝑈[0,1] 中抽取样本,样本数与这层神经网络的维度一致。 然后我们保留那些对应样本大于 𝑝 的节点,把剩下的丢弃
    在下面的代码中,(我们实现 dropout_layer 函数, 该函数以dropout的概率丢弃张量输入X中的元素), 如上所述重新缩放剩余部分:将剩余部分(h)除以1.0-dropout。

在这里插入图片描述

import torch
from torch import nn
from d2l import torch as d2ldef dropout_layer(X, dropout):# 断言检查assert 0 <= dropout <= 1# 在本情况中,所有元素都被丢弃if dropout == 1:return torch.zeros_like(X)# 在本情况中,所有元素都被保留if dropout == 0: return X# 生成一个与输入张量形状相同的掩码 mask# 对于掩码中的每个元素:都是基于随机数生成的# 随机数> dropout 概率,对应的掩码元素为 1;随机数≤ dropout 概率,对应的掩码元素为 0。mask = (torch.rand(X.shape) > dropout).float()# 将mask与x进行元素级乘法,只保留x中被掩码标记为1的元素,然后除以1-dropout以抵消由于丢弃部分元素而引起的整体缩放效果。# 确保训练过程中神经元的期望输出都保持不变。return mask * X / (1.0 - dropout)

我们可以通过下面几个例子来测试dropout_layer函数。 我们将输入X通过暂退法操作,暂退概率分别为0、0.5和1。

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.))

输出:
在这里插入图片描述




定义模型参数

引入Fashion-MNIST数据集,定义具有两个隐藏层的多层感知机,每个隐藏层包含256个单元。

num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256



定义模型

    可以将暂退法应用于每个隐藏层的输出(在激活函数之后), 并且可以为每一层分别设置暂退概率
    常见的技巧是在靠近输入层的地方设置较低的暂退概率。 下面的模型将第一个和第二个隐藏层的暂退概率分别设置为0.2和0.5, 并且暂退法只在训练期间有效

dropout1, dropout2 = 0.2, 0.5class Net(nn.Module):def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,is_training = True):# super()调用父类的一个方法,确保了nn.Module的初始化方法被执行super(Net, self).__init__()self.num_inputs = num_inputsself.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)# 将负值置为0,保留正值不变self.relu = nn.ReLU()# 前向传播def forward(self, X):# -1表示自动计算,这里指batch_size大小H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))# 只有在训练模型时才使用dropoutif self.training == True:# 在第一个全连接层之后添加一个dropout层H1 = dropout_layer(H1, dropout1)# H2是经过线性变换和非线性激活处理后的特征表示,它被用作后续层的输入。H2 = self.relu(self.lin2(H1))if self.training == True:# 在第二个全连接层之后添加一个dropout层H2 = dropout_layer(H2, dropout2)# 计算神经网络中最后一个线性层的输出out = self.lin3(H2)return outnet = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)



训练和测试

num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss(reduction='none')
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)



代码实现

import torch
from torch import nn
from d2l import torch as d2lclass Net(nn.Module):def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2, is_training=True):# super()调用父类的一个方法,确保了nn.Module的初始化方法被执行super(Net, self).__init__()self.num_inputs = num_inputsself.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)# 将负值置为0,保留正值不变self.relu = nn.ReLU()# 前向传播def forward(self, X):# -1表示自动计算,这里指batch_size大小H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))# 只有在训练模型时才使用dropoutif self.training == True:# 在第一个全连接层之后添加一个dropout层H1 = dropout_layer(H1, dropout1)# H2是经过线性变换和非线性激活处理后的特征表示,它被用作后续层的输入。H2 = self.relu(self.lin2(H1))if self.training == True:# 在第二个全连接层之后添加一个dropout层H2 = dropout_layer(H2, dropout2)# 计算神经网络中最后一个线性层的输出out = self.lin3(H2)return outdef dropout_layer(X, dropout):# 断言检查assert 0 <= dropout <= 1# 在本情况中,所有元素都被丢弃if dropout == 1:return torch.zeros_like(X)# 在本情况中,所有元素都被保留if dropout == 0:return X# 生成一个与输入张量形状相同的掩码 mask# 对于掩码中的每个元素:都是基于随机数生成的# 随机数> dropout 概率,对应的掩码元素为 1;随机数≤ dropout 概率,对应的掩码元素为 0。mask = (torch.rand(X.shape) > dropout).float()# 将mask与x进行元素级乘法,只保留x中被掩码标记为1的元素,然后除以1-dropout以抵消由于丢弃部分元素而引起的整体缩放效果。# 确保训练过程中神经元的期望输出都保持不变。return mask * X / (1.0 - dropout)num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
dropout1, dropout2 = 0.2, 0.5
net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss(reduction='none')
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)
d2l.plt.show()

在这里插入图片描述

这里不使用丢弃法,即将参数置为0.

dropout1, dropout2 = 0.2, 0.5

在这里插入图片描述

dropout是正则用来防止过拟合的,这里不用dropout之后损失更小,说明过拟合程度加深了

简洁代码实现

对于深度学习框架的高级API,我们只需在每个全连接层之后添加一个Dropout层, 将暂退概率作为唯一的参数传递给它的构造函数。 在训练时,Dropout层将根据指定的暂退概率随机丢弃上一层的输出(相当于下一层的输入)。 在测试时,Dropout层仅传递数据。

import torch
from torch import nn
from d2l import torch as d2ldef init_weights(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, std=0.01)num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
dropout1, dropout2 = 0.2, 0.5
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss(reduction='none')
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)net = nn.Sequential(nn.Flatten(),nn.Linear(784, 256),nn.ReLU(),# 在第一个全连接层之后添加一个dropout层nn.Dropout(dropout1),nn.Linear(256, 256),nn.ReLU(),# 在第二个全连接层之后添加一个dropout层nn.Dropout(dropout2),nn.Linear(256, 10))net.apply(init_weights)
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
d2l.plt.show()

在这里插入图片描述




问题

①dropout随机置0对求梯度和反向传播的影响是什么?
梯度也是0

②丢弃法的丢弃依据是什么?如果丢弃不合理对输出的结果影响会很大?
丢弃不合理是指丢弃率没设置好,要么太小了,对模型的正则效果不大,还是过拟合,要么就是过大(欠拟合)

③丢弃法是在训练中把神经元丢弃后训练,在与测试时网络中的神经元没有丢弃是这样吗?
是的

④丢弃法是每次迭代一次,随机丢弃一次吗?
是的,每一层调用前向运算时随机丢一次。

⑤⭐推理中dropout是直接返回输入吗?
是的,在做预测的时候(不对权重进行更新的时候)不用dropout。因为dropout是一个正则项,正则项唯一的作用是更新权重的时候让你的模型复杂度变得低一点点。在做推理的时候,不会更新模型的复杂度,不更新模型,所以不需要dropout。

⑥dropout函数返回值的表达式return X*mask/(1.0-p)没被丢弃的输入部分的值会因为表达式分母(1-p)的存在而改变,而训练数据的标签还是原来的值。

⑦训练时用dropout,推理时不用,那会不会导致推理时输出结果翻倍了?
不假设在训练的时候dropout=0.5,就是把一半的神经元设成0,剩下的要除以0.5(1-p,这里的p为0.5)也就是乘以2.所以在训练的过程中期望是不会发生变化的,

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Python爬虫技术 第29节 实战案例分析
  • 【Golang】清理Markdown未引用图片
  • PHP如何实现登录认证和鉴权
  • 【Rust光年纪】解锁 Rust 库新姿势:抽象语法树、代码生成与宏处理全解析
  • Qt文件读写
  • 实战:ElasticSearch 索引操作命令(补充)
  • day18 Java流程控制——Scanner进阶使用
  • C++20三向比较运算符详解
  • 你的网站访客来自何方?GoAccess地理分析工具告诉你!
  • 图像生成中图像质量评估指标—FID介绍
  • C#的#define #if用法
  • 《C语言程序设计 第4版》笔记和代码 第十三章 文件操作
  • 二百五十四、OceanBase——Linux上安装OceanBase数据库(四):登录ocp-express,配置租户管理等信息
  • Swift-Extension
  • 【简单讲解下Symfony框架】
  • CSS 提示工具(Tooltip)
  • ES6 ...操作符
  • input的行数自动增减
  • mysql常用命令汇总
  • pdf文件如何在线转换为jpg图片
  • php中curl和soap方式请求服务超时问题
  • React 快速上手 - 07 前端路由 react-router
  • Redash本地开发环境搭建
  • 初识 webpack
  • 对象引论
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 如何利用MongoDB打造TOP榜小程序
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 思考 CSS 架构
  • 微服务核心架构梳理
  • 赢得Docker挑战最佳实践
  • 用element的upload组件实现多图片上传和压缩
  • Android开发者必备:推荐一款助力开发的开源APP
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ​数据结构之初始二叉树(3)
  • ###C语言程序设计-----C语言学习(6)#
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • #if 1...#endif
  • #Linux(make工具和makefile文件以及makefile语法)
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • $(this) 和 this 关键字在 jQuery 中有何不同?
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (二十六)Java 数据结构
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (排序详解之 堆排序)
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)Linux+Windows下安装ffmpeg
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET MVC 验证码
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .net 调用海康SDK以及常见的坑解释