dropout作为一种预防CNN过拟合的正则化方法被Hinton等人在2012年的经典论文《ImageNet Classification with Deep Convolutional》中提出。dropout的原理很简单:在一次训练时的迭代中,对每一层中的神经元(总数为N)以概率P随机剔除,用余下的(1-P)×N个神经元所构成的网络来训练本次迭代中的数据(batchsize个样本)。
关于dropout能够较好减轻CNN过拟合的原因,看了一些论文和博客,目前有多种不同的解释,大致整理如下。
在设计网络时,设定的每层神经元代表一个学习到的中间特征(即几个权值的组合),网络所有神经元共同作用来表征输入数据的特定属性(如图像分类中,表征所属类别)。当相对于网络的复杂程度(即网络的表达能力、拟合能力)而言数据量过小时,出现过拟合,显然这时各神经元表示的特征相互之间存在许多重复和冗余。
dropout的直接作用是减少中间特征的数量,从而减少冗余,即增加每层各个特征之间的正交性(数据表征的稀疏性观点也恰好支持此解释)。
解释到这里,可能会问:要减少特征冗余,设计网络时直接减少神经元的数量就可以了,为什么要有dropout?
针对一个任务和拥有的数据集,一开始无法知道多大的网络才能充分地学习到我们需要数据特征,考虑到通常网络越复杂对训练数据的拟合效果越好(不代表泛化性能越好),因此一般都会设计一个较大的通用网络来训练。这样一来,神经元数量就事先确定了,要想在出现过拟合时减少冗余、尽可能地增加特征正交性,当然可以尝试简化网络,但这样可能会明显降低网络拟合能力(而且简化网络并不能直接增加特征间的正交性)。一个折中的办法就是dropout,由于随机性,使每一次迭代训练时,整体来看都在更新不同的一些参数(因此这也可以看做是进行了数据扩增),使得各个特征(权值)不用每一次迭代时都一起更新、互相产生关联和影响,这样也就弱化了各个特征之间由于数据量太小导致产生的过多的相互作用,缓解了过拟合。
dropout带来的缺点是可能减慢收敛速度:由于每次迭代只有一部分参数更新,可能导致梯度下降变慢。
原理简介:
在没有dropout时,正向传播如下:
加入dropout后:
测试时,需要每个权值乘以P:
其中的Bernoulli函数,作用是以概率P随机生成一个由0、1组成的向量。
实现:
官方源码如下:
#dropout函数实现
def dropout(x, level): # level为神经元丢弃的概率值,在0-1之间
if level < 0. or level >= 1:
raise Exception('Dropout level must be in interval [0, 1[.')
retain_prob = 1. - level
# 利用binomial函数,生成与x一样的维数向量。
# 神经元x保留的概率为p,n表示每个神经元参与随机实验的次数,通常为1,。
# size是神经元总数。
sample=np.random.binomial(n=1,p=retain_prob,size=x.shape)
# 生成一个0、1分布的向量,0表示该神经元被丢弃
# print sample
x *=sample
# print x
x /= retain_prob
return x