无风而起 2019-12-24
为了解决神经网络的过拟合问题,我们需要使用L2正则化,除了L2正则化解决过拟合的问题,还可以使用另外一个正则化方法——Dropout(随机失活),我们下面详细介绍一个这个正则化的原理。
现在我们有一个这样的神经网络:
这个神经网络存在着过拟合的问题,我们要使用dropout来解决这个过拟合问题,dropout会遍历这个神经网络的每一层,并且设置消除神经网络中结点的概率。假设神经网络中的每一层,每个结点都以抛硬币的方式设置概率(每个结点得以保存和消除的概率都是0.5),设置完结点的概率,我们会消除一些结点(50%的概率结点会被消除),然后删除掉神经网络中从该结点进出的连线,最终我们可以得到一个结点更少,规模更小的神经网络,然后我们使用反向传播算法来训练这个神经网络。
如上图所示,我们的神经网络在dropout之后,一些神经元被消除了,然后神经网络变得简化了很多。训练集中一个样本(或者一批样本)对应一个简化的神经网络,对于训练集中的其它样本(或者其它批量的样本),我们照旧使用抛硬币的方式来设置保留结点或者删除结点的概率,所以训练集中的每一个样本(或者其它批量的样本),我们都会有一个精简的神经网络来训练它。
这样说起来有些让人难以理解,我们对每一个样本都用极小的神经网络来训练,训练这样的神经网络的dropout方法也有点奇怪,它就是在遍历结点,然后根据概率随机确定是否保存这个结点,以次来生成极小的神经网络,但是这样的方法对于解决过拟合问题确实很有效。
我们就是是使用droupout正则化方法获得为每一个样本获得一个精简的神经网络,既然dropout正则化方法对于解决神经网络的过拟合问题很有效果,那么我们应该如何实施dropout方法呢?
输入是x输出是y,正常的流程是:我们首先把x通过网络前向传播,然后把误差反向传播以决定如何更新参数让网络进行学习。使用Dropout之后,过程变成如下:
(1)首先随机(临时)删掉网络中一半的隐藏神经元,输入输出神经元保持不变(图3中虚线为部分临时被删除的神经元)
(2) 然后把输入x通过修改后的网络前向传播,然后把得到的损失结果通过修改的网络反向传播。一小批训练样本执行完这个过程后,在没有被删除的神经元上按照随机梯度下降法更新对应的参数(w,b)。(3)然后继续重复这一过程:. 恢复被删掉的神经元(此时被删除的神经元保持原样,而没有被删除的神经元已经有所更新). 从隐藏层神经元中随机选择一个一半大小的子集临时删除掉(备份被删除神经元的参数)。. 对一小批训练样本,先前向传播然后反向传播损失并根据随机梯度下降法更新参数(w,b) (没有被删除的那一部分参数得到更新,删除的神经元参数保持被删除前的结果)。不断重复这一过程。
我们本文讲解最常用的方法就是反向随机失活方法(inverted dropout),我们使用一个三层的神经网络来进行举例说明,下面我们对三层神经网络中的某一层实施dropout,来看看它是怎么进行的。
我们首先定义一个向量d3,d3(d[3])表示一个dropout向量:
d3 = np.random.rand(a3.shape[0],a3.shape[1])<keep-prob
然后我们看d3向量中的每一个元素是否小于某数(keep-prob),keep-prob是一个具体的数字,比如上面我们使用抛硬币的0.5来作为keep-prob,本例中它是0.8,它表示保留某个隐藏单元的概率,此处 keep-prob 等于 0.8,它意味着消除任意一个隐藏单元的概率是 0.2 ,那么想象中的元素若是小于0.8那么对应为0,大于0.8那么对应为1。
我们现在已经有了d3矩阵,然后我们下面就是使用d3矩阵和a3(a[3])进行对位相乘,目的就是使用d3过滤掉a3中对应位置为0的元素,a3 =np.multiply(a3,d3),这里是元素相乘,也可写为3 ∗= 3
我们要是使用python语言来实现这个算法的话,d3应该是一个布尔型数组,值为true和false,而不是1 和 0,乘法运算依然有效,python 会把 true 和 false 翻译为 1 和 0。
相乘完之后我们得到过滤完的a3,之后我们还需要用a3/0.8或者除以 keep-prob 参数
反向随机失活(inverted dropout)方法通过除以 keep-prob,确保[3]的期望值不变。因为我们刚开始a3乘以了d3将会导致a3有20%的数据元素被归0,相当于缩小了,现在我们要保证期望值不变,那么我们再除以0.8,这样就相当于扩大了。这样一下缩小,一下放大,那么a3的期望值不变,但是确实a3中有很多元素被归为0了,这就起到了dropout的作用了。
下面我们再来详细解释一下为什么要除以0.8
为方便起见,我们假设第三隐藏层上有 50 个单元或50 个神经元,所以在一维上[3]是50(神经元数),我们通过因子分解将它拆分成50 × 维的,保留和删除它们的概率分别为 80%和 20%,这意味着最后被删除或归零的单元平均有 10(50×20%=10)个,现在我们看下[4],[4] = [4][3] + [4],我们的预期是,[3]减少20%,也就是说[3]中有 20%的元素被归零,为了不影响[4]的期望值,我们需要用[4][3]/0.8,它将会修正或弥补我们所需的那 20%,[3]的期望值不会变,这就是所谓的 dropout 方法。
如果 keep-prop 设置为 1,那么就不存在 dropout,因为它会保留所有节点。反向随机失活(inverted dropout)方法通过除以 keep-prob,确保[3]的期望值不变。
如果要是不除以keep-prop,那么再测试阶段需要将我们的神经网络的权重参数那么在测试的时候,就需要对权重进行缩放,操作如下。
现在你使用的是向量,你会发现,不同的训练样本,清除不同的隐藏单元也不同。实际上,如果你通过相同训练集多次传递数据,每次训练数据的梯度不同,则随机对不同隐藏单元归零,有时却并非如此。比如,需要将相同隐藏单元归零,第一次迭代梯度下降时,把一些隐藏单元归零,第二次迭代梯度下降时,也就是第二次遍历训练集时,对不同类型的隐藏层单元归零。向量或[3]用来决定第三层中哪些单元归零,无论用 foreprop 还是 backprop,这里我们只介绍了 foreprob。
在测试阶段,我用[0]表示第 0 层的激活函数标注为测试样本,我们在测试阶段不使用dropout 函数,我们在测试的时候就是从第一层开始逐渐进行前向传播:
以此类推直到最后一层,预测值为 ^。