赞
踩
深度神经网(DNN)中经常会存在一个常见的问题:模型只学会在训练集上分类(过拟合现象),dropout就是为了减少过拟合而研究出的一种方法。
当训练模型较大,而训练数据很少的话,很容易引起过拟合,一般情况我们会想到用正则化、或者减小网络规模。然而Hinton在2012年文献:《Improving neural networks by preventing co-adaptation of feature detectors》提出了,在每次训练的时候,随机让一定数量的卷积停止工作,这样可以提高网络的泛化能力,Hinton又把它称之为dropout。
dropout是指深度学习训练过程中,对于神经网络训练单元,暂时将按照一定的概率将其从网络中移除,注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
其工作原理如下图:
第一种理解方式是,在每次训练的时候使用dropout,每个神经元有百分之50的概率被移除,这样可以使得一个神经元的训练不依赖于另外一个神经元,同样也就使得特征之间的协同作用被减弱。Hinton认为,过拟合可以通过阻止某些特征的协同作用来缓解。
第二种理解方式是,我们可以把dropout当做一种多模型效果平均的方式。对于减少测试集中的错误,我们可以将多个不同神经网络的预测结果取平均,而因为dropout的随机性,我们每次dropout后,网络模型都可以看成是一个不同结构的神经网络,而此时要训练的参数数目却是不变的,这就解脱了训练多个独立的不同神经网络的时耗问题。在测试输出的时候,将输出权重除以二,从而达到类似平均的效果。
需要注意的是如果采用dropout,训练时间大大延长,但是对测试阶段没影响。
目前来说,Dropout有两种。第一种就是传统的Dropout方案。另一种,就是我们的吴恩达老师的Inverted Dropout。
Inverted Dropout的实现代码,假设,我们的输入是x,p表示随机丢弃的概率, 1−p表示的是神经元保存的概率。则Inverted Dropout的实现过程如下代码所示:
import numpy as np
def dropout(x, p):
if p < 0. or p >1.
# 边界条件,在写代码的时候,一定要仔细!!!p为随机丢弃的概率
raise Exception("The p must be in interval [0, 1]")
retain_prob =1. -p
#我们通过binomial函数,生成与x一样的维数向量。
# binomial函数就像抛硬币一样,每个神经元扔一次,所以n=1
# sample为生成的一个0与1构成的mask,0表示抛弃,1表示保留
sample =np.random.binomial(n=1, p=retain_prob, size=x.shape)
x *= sample # 与0相乘,表示将该神经元Drop掉
x /= retain_prob
return x
这里解释下,为什么在后面还需要进行 x/=retain_prob 的操作?
假设该层是输入,它的期望是a,在不使用Dropout的时候,它的期望依旧是a。如果该层进行了Dropout, 相当于有p的概率被丢弃,1−p的概率被保留,则此层的期望为 ( 1 − p ) ∗ a ∗ 1 + p ∗ a ∗ 0 = ( 1 − p ) ∗ a (1−p)∗a∗1+p∗a∗0=(1−p)∗a (1−p)∗a∗1+p∗a∗0=(1−p)∗a,为了保证输入与输出的期望一致,我们需要进行代码中x/=retain_prob这一步。
对于传统的Dropout,在训练的时候,不需要进行x/=retain_prob的这一步,直接进行神经元Drop操作。此时,假设输入x的期望是a,则此时的输出期望为(1−p)∗a。在测试的时候,整个神经元是保留的,因此输出期望为a。为了让输入与输出的期望一致,则在测试的阶段,需要乘以(1−p),使其期望值保持(1−p)∗a。
传统的dropout和Inverted-dropout虽然在具体实现步骤上有一些不同,但从数学原理上来看,其正则化功能是相同的,那么为什么现在大家都用Inverted-dropout了呢?主要是有两点原因:
1、测试阶段的模型性能很重要,特别是对于上线的产品,模型已经训练好了,只要执行测试阶段的推断过程,那对于用户来说,推断越快用户体验就越好了,而Inverted-dropout把保持期望一致的关键步骤转移到了训练阶段,节省了测试阶段的步骤,提升了速度。
2、dropout方法里的p是一个可能需要调节的超参数,用Inverted-dropout的情况下,当你要改变p 的时候,只需要修改训练阶段的代码,而测试阶段的推断代码没有用到p ,就不需要修改了,降低了写错代码的概率。
DropOut的出发点是直接干掉部分神经元节点,我们能不能不干掉神经元,我们把网络权值干掉部分呢?DropConnect干掉的就是网络权重。具体细节如下:
针对二维卷积核进行DropConnect操作:
import torch import torch.nn as nn import torch.nn.functional as F from torch.nn.modules.conv import _ConvNd,_pair class DropConnectConv2D(_ConvNd): def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', p=0.5): kernel_size = _pair(kernel_size) stride = _pair(stride) padding = _pair(padding) dilation = _pair(dilation) super(DropConnectConv2D, self).__init__( in_channels, out_channels, kernel_size, stride, padding, dilation, False, _pair(0), groups, bias, padding_mode) self.dropout = nn.Dropout(p) self.p = p def _conv_forward(self, input, weight): if self.padding_mode != 'zeros': return F.conv2d(F.pad(input, self._reversed_padding_repeated_twice, mode=self.padding_mode), weight, self.bias, self.stride, _pair(0), self.dilation, self.groups) return F.conv2d(input, weight, self.bias, self.stride, self.padding, self.dilation, self.groups) def forward(self, input): return self._conv_forward(input, self.dropout(self.weight) * self.p) if __name__=='__main__': conv = DropConnectConv2D(1,1,3,1,bias=False).train() conv.weight.data = torch.ones_like(conv.weight) a = torch.ones([1,1,3,3]) print(a) print(conv(a))
StochasticDepth是采取类似于Dropout的思路,在ResNet块上随机进行对模块的删除,进而提高对模型的泛化能力。
如图所示,为Stochastic Depth的具体做法。
目前为主,丢的主要是权重,或者是丢的是神经元。这里开始,我们要丢的是是网络的输入,当然网络输入不仅仅可以丢,也可以添加噪声(Cutmix等),这个是后面要做的内容。当然,还有一些对于输入图像进行Drop的操作(如random erase)。
图像上进行随机位置和一定大小的patch进行0−mask裁剪。一开始使用裁剪上采样等变换出复杂轮廓的patch后来发现简单的固定像素patch就可以达到不错的效果,所以直接采用正方形patch。
通过patch的遮盖可以让网络学习到遮挡的特征。Cutout不仅能够让模型学习到如何辨别他们,同时还能更好地结合上下文从而关注一些局部次要的特征。
如下图:
首先直观的从图片中看下DropBlock的具体做法:
其中(b)表示的是随机Dropout的效果,©为Drop掉相邻的一整片区域,即按Spatial块随机扔。
假设我们的输入tensor的维度是(4,3,2,2),那么我们在做BN的时候,我们在channel维度中“抽”出来一个通道的数据,则其维度为(4,1,2,2)。我们需要对这16个数据求均值μ 跟方差σ,并用求得的均值与方差归一化,再缩放数据,得到BN层的输出。
Dropout在网络测试的时候神经元会产生“variance shift”,即“方差偏移”。试想若有图一中的神经响应X,当网络从训练转为测试时,Dropout 可以通过其随机失活保留率(即p)来缩放响应,并在学习中改变神经元的方差,而BN仍然维持X的统计滑动方差(varrunning_var)。这种方差不匹配可能导致数值不稳定。而随着网络越来越深,最终预测的数值偏差可能会累计,从而降低系统的性能。事实上,如果没有Dropout,那么实际前馈中的神经元方差将与BN 所累计的滑动方差非常接近,这也保证了其较高的测试准确率。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。