pytorch 入门 - L1,L2正则,Dropout

Dropout

dropout 主要用于解决训练过程中模型出现过拟合的问题。在模型训练过程中,当训练集上的正确率很高,但验证集上的正确率很低时,即发生了过拟合。解决过拟合的方法有很多,例如利用集成学习的方法,训练多个模型进行组合;减少网络训练的层数;提前终止训练等。此外,Dropout可以比较有效的缓解过拟合的发生,在一定程度上达到正则化的效果。

dropout 简介

(以下参考深度学习中Dropout原理解析
dropout可解决模型的过拟合问题,其原理是在模型训练的每个批次中,随机的让一半的隐层节点值变为0,这种做法可以让隐层节点之间的相互作用变弱(隐层之间的相互作用是指 某些检测器依赖其他检测器才能发挥作用)。

总而言之,就是在前向传播的过程中,以概率P让某个神经元失活,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征,用图片表示上述过程:

在这里插入图片描述

dropout具体工作流程

首先,定义一个标准的神经网络模型;
使用dropout之后,过程变成如下:
1.随机删掉网络中的一半的隐藏神经元(备份被删除的神经元参数);
2.将输入的x通过修改后的网络做前向传播,得到的损失函数做反向传播;一小批训练样本执行这个过程之后,利用梯度下降法更新没有被删除的神经元参数。
3.恢复被删除的神经元,即被删除的神经元参数保持原样(回复备份的参数);
4.重复上述过程

dropout 数学表达

由于dropout在训练时是随机将隐藏层节点设置为0的,所以在前向计算时需要添加一个概率流程。
在这里插入图片描述
上述为标准网络和dropout网络前向计算的流程,其中 y i ( l ) y_i^{(l)} 为这一隐藏层的输入, w i ( l + 1 ) w_i^{(l+1)} 是权重向量, b i ( l + 1 ) b_i^{(l+1)} 是偏倚项, r j ( l ) r_j{(l)} 服从伯努利分布,以概率p生成1,最终生成0-1向量,表明以概率p选择留下的隐藏层节点。

  • 正常网络计算:
    z i ( l + 1 ) = w i ( l + 1 ) y l + b i ( l + 1 ) z_i^{(l+1)} = w_i^{(l+1)}y^l+b_i^{(l+1)}
    y i ( l + 1 ) = f ( z i ( l + 1 ) ) y_i^{(l+1)} = f(z_i^{(l+1)})
  • dropout计算公式
    y n e w ( l + 1 ) = r ( l ) y ( l ) y_{new}^{(l+1) = r^{(l)}*y^{(l)}} ,
    z i ( l + 1 ) = w i ( l + 1 ) y n e w l + b i ( l + 1 ) z_i^{(l+1)} = w_i^{(l+1)}y_{new}^l+b_i^{(l+1)}
    y i ( l + 1 ) = f ( z i ( l + 1 ) ) y_i^{(l+1)} = f(z_i^{(l+1)})

由于我们在dropout过程中增加了一个概率过程实现随机drop隐藏层节点,所以在训练过程中计算出的参数 w i ( l + 1 ) w_i^{(l+1)} 是基于概率转换后的输入值,所以在训练过程中需要做一个rescale,即 w i ( l + 1 ) / p w_i^{(l+1)}/p ;若在训练阶段未对模型参数做rescale,那么在测试阶段就得对每个神经元参数乘以p,这是因为在训练过程中隐层参数是可以随机丢弃的,但在测试集是无法drop的,那么这里就以期望输出作为最终输出,如一个神经元的输出是x,那么在训练的时候它有p的概率参与训练,(1-p)的概率丢弃,那么它输出的期望是px+(1-p)0=px。因此测试的时候把这个神经元的权重乘以p可以得到同样的期望。

dropout如何解决过拟合

(1)取平均

dropout掉不同的隐藏神经元就类似在训练不同的网络,随机删掉一半隐藏神经元导致网络结构已经不同,整个dropout过程就相当于对很多个不同的神经网络取平均。而不同的网络产生不同的过拟合,一些互为“反向”的拟合相互抵消就可以达到整体上减少过拟合。

(2)减少神经元之间的共线关系

因为dropout程序导致两个神经元不一定每次都在一个dropout网络中出现。这样权值的更新不再依赖于有固定关系的隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况 。迫使网络去学习更加鲁棒的特征 ,这些特征在其它的神经元的随机子集中也存在。换句话说假如我们的神经网络是在做出某种预测,它不应该对一些特定的线索片段太过敏感,即使丢失特定的线索,它也应该可以从众多其它线索中学习一些共同的特征。从这个角度看dropout就有点像L1,L2正则,减少权重使得网络对丢失特定神经元连接的鲁棒性提高。

dropout 使用场景

dropout 常用于全连接网络,一般设置为0.5或03,而在卷积网络中由于卷积自身的稀疏化以及大量使用ReLU函数等原因,dropout在卷积网络中使用较少。

Dropout的numpy实现

import numpy as np
# 此处定义的dropout的参数level表示drop掉参数的比例
def dropout(x, level):  
    if level < 0. or level >= 1:#level是概率值,必须在0~1之间  
        raise Exception('Dropout level must be in interval [0, 1[.')  
    retain_prob = 1. - level  
   # 通过伯努利函数生成0-1向量,p表示生成1的概率,即保留神经元的概率 
    sample=np.random.binomial(n=1,p=retain_prob,size=x.shape) # n表示每个神经元需生成的次数;size表示总共需要调用函数的次数,即0-1向量的长度;
    
    print (sample)  
    x *=sample          # 利用0-1向量与输入的内积决定屏蔽哪些神经元
    print(x) 
    x /= retain_prob   #此处是rescale

    return x  

PyTorch中实现dropout

pytorch包内有封装好的dropout 函数,在torch.nn.functional函数中。

dropout(input, p=0.5, training=True, inplace=False)

  • 其中p是随机置零的概率
import troch
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self):
        super(Model,self).__init__()
        # 定义多层神经网络
        self.fc1 = torch.nn.Linear(8,6)
        self.fc2 = torch.nn.Linear(6,4)
        self.fc3 = torch.nn.Linear(4,1)
        
    def forward(self,x):
        x = F.relu(self.fc1(x))            # 8->6
        x = F.dropout(x,p=0.5)             #dropout 1 此处为dropout
        x = F.relu(self.fc2(x))            #-6->4
        x = F.dropout(x,p=0.5)             # dropout 2  #此处为drouout
        y_pred = torch.sigmoid(self.fc3(x))         # 4->1 ->sigmoid 
        # warnings.warn("nn.functional.sigmoid is deprecated. Use torch.sigmoid instead."
        return y_pred

L1及L2正则化

参考资料

1) https://blog.csdn.net/program_developer/article/details/80737724
2)https://blog.csdn.net/wehung/article/details/89283583

猜你喜欢

转载自blog.csdn.net/qq_39446239/article/details/89299651