dropout理解(一)

1.Dropout原理

1.概述
作用:防止过拟合
方法:训练时,随机停止某些神经元的参数训练
2. Dropout工作流程及使用
2.1 Dropout具体工作流程
假设我们要训练这样一个神经网络,如图2所示。
在这里插入图片描述
上图表示标准的神经网络。

输入是x输出是y,正常的流程是:我们首先把x通过网络前向传播,然后把误差反向传播以决定如何更新参数让网络进行学习。使用Dropout之后,过程变成如下:
(1)首先随机(临时)删掉网络中一半的隐藏神经元,输入输出神经元保持不变(图3中虚线为部分临时被删除的神经元)
在这里插入图片描述
(2) 然后把输入x通过修改后的网络前向传播,然后把得到的损失结果通过修改的网络反向传播。一小批训练样本执行完这个过程后,在没有被删除的神经元上按照随机梯度下降法更新对应的参数(w,b)。

(3)然后继续重复这一过程:

. 恢复被删掉的神经元(此时被删除的神经元保持原样,而没有被删除的神经元已经有所更新)

. 从隐藏层神经元中随机选择一个一半大小的子集临时删除掉(备份被删除神经元的参数)。

. 对一小批训练样本,先前向传播然后反向传播损失并根据随机梯度下降法更新参数(w,b) (没有被删除的那一部分参数得到更新,删除的神经元参数保持被删除前的结果)。

Dropout在神经网络中的使用

Dropout的具体工作流程上面已经详细的介绍过了,但是具体怎么让某些神经元以一定的概率停止工作(就是被删除掉)?代码层面如何实现呢?

下面,我们具体讲解一下Dropout代码层面的一些公式推导及代码实现思路。

(1)在训练模型阶段

无可避免的,在训练网络的每个单元都要添加一道概率流程。
在这里插入图片描述
图4:标准网络和带有Dropout网络的比较

对应的公式变化如下:

. 没有Dropout的网络计算公式:
在这里插入图片描述
. 采用Dropout的网络计算公式:

在这里插入图片描述
上面公式中Bernoulli函数是为了生成概率r向量,也就是随机生成一个0、1的向量。

代码层面实现让某个神经元以概率p停止工作,其实就是让它的激活函数值以概率p变为0。比如我们某一层网络神经元的个数为1000个,其激活函数输出值为y1、y2、y3、…、y1000,我们dropout比率选择0.4,那么这一层神经元经过dropout后,1000个神经元中会有大约400个的值被置为0。

注意: 经过上面屏蔽掉某些神经元,使其激活值为0以后,我们还需要对向量y1……y1000进行缩放,也就是乘以1/(1-p)。如果你在训练的时候,经过置0后,没有对y1……y1000进行缩放(rescale),那么在测试的时候,就需要对权重进行缩放,操作如下。

在测试模型阶段

预测模型的时候,每一个神经单元的权重参数要乘以概率p。
在这里插入图片描述
图5:预测模型时Dropout的操作
测试阶段Dropout公式:
在这里插入图片描述

3.通过代码理解

# coding:utf-8
import numpy as np
 
# dropout函数的实现,函数中,x是本层网络的激活值。Level就是dropout就是每个神经元要被丢弃的概率。
def dropout(x, level):
    if level < 0. or level >= 1: #level是概率值,必须在0~1之间
        raise ValueError('Dropout level must be in interval [0, 1[.')
    retain_prob = 1. - level
 
    # 我们通过binomial函数,生成与x一样的维数向量。binomial函数就像抛硬币一样,我们可以把每个神经元当做抛硬币一样
    # 硬币 正面的概率为p,n表示每个神经元试验的次数
    # 因为我们每个神经元只需要抛一次就可以了所以n=1,size参数是我们有多少个硬币。
    random_tensor = np.random.binomial(n=1, p=retain_prob, size=x.shape) #即将生成一个0、1分布的向量,0表示这个神经元被屏蔽,不工作了,也就是dropout了
    print(random_tensor)
 
    x *= random_tensor
    print(x)
    x /= retain_prob
 
    return x
 
#对dropout的测试,大家可以跑一下上面的函数,了解一个输入x向量,经过dropout的结果  
x=np.asarray([1,2,3,4,5,6,7,8,9,10],dtype=np.float32)
print(dropout(x,0.4))

import torch
import torch.nn as nn
import torch.nn.functional as F


class LinearFC(nn.Module):

    def __init__(self):
        super(LinearFC, self).__init__()
        self.fc = nn.Linear(3, 2)

    def forward(self, input):
        out = self.fc(input)
        out = F.dropout(out, p=0.5, training=self.training)
        return out


Net = LinearFC()
x = torch.randint(10, (2, 3)).float()  # 随机生成不大于10的整数,转为float, 因为nn.linear需要float类型数据
Net.train()
output = Net(x)
print(output)

# train the Net
  1. 第一步Net = LinearFC(),生成 W W W b b b:
W=tensor([[-0.5347,  0.3559,  0.0637],
        [-0.5676, -0.0257,  0.1802]], requires_grad=True)
b=tensor([0.4141, 0.4688], requires_grad=True)
  1. 第二步x = torch.randint(10, (2, 3)).float(),随机生成不大于10的整数,转为float, 因为nn.linear需要float类型数据
x=tensor([[3., 2., 0.],
        [2., 6., 8.]])
  1. 第三步 output = Net(x) out = self.fc(input)进入forward o u t = x × W T + b out = x \times W^T + b out=x×WT+b,代码实现:torch.mm(x, Net.fc.weight.t()) + Net.fc.bias
tensor([[-0.4783, -1.2855],
        [ 1.9898,  0.6210]], grad_fn=<AddBackward0>)
  1. 第四步,dropout,公式 o u t = o u t / ( 1 − 0.5 ) 在 以 0.5 概 率 置 为 0 out = out/(1-0.5)在以0.5概率置为0 out=out/(10.5)0.50
(torch.mm(x, Net.fc.weight.t()) + Net.fc.bias)/(1-0.5)=
tensor([[-0.9565, -2.5710],
        [ 3.9796,  1.2420]], grad_fn=<DivBackward0>)
out=
tensor([[-0.0000, -0.0000],
        [0.0000, 1.2420]], grad_fn=<MulBackward0>)

可以看到经过dropout之后,数据变为:tensor([[-0.0000, -0.0000], [0.0000, 1.2420]], grad_fn=<MulBackward0>)

转载:https://blog.csdn.net/powu0193/article/details/99573632

猜你喜欢

转载自blog.csdn.net/vincent_duan/article/details/119936339
今日推荐