Dropout 正则化

在训深层练神经网络时,由于模型参数较多,在数据量不足的情况下,很容易过拟合。Dropout 就是在神经网络中一种缓解过拟合的方法。

我们知道,缓解过拟合的方式就是降低模型的复杂度,而 Dropout 就是通过减少神经元之间的连接,把稠密的神经网络神经元连接,变成稀疏的神经元连接,从而达到降低网络复杂度的目的。

我们先通过一段代码观察下丢弃层的效果:

import torch
import torch.nn as nn


def test():

    # 初始化丢弃层
    dropout = nn.Dropout(p=0.8)
    # 初始化输入数据
    inputs = torch.randint(0, 10, size=[5, 8]).float()
    print(inputs)
    print('-' * 50)

    outputs = dropout(inputs)
    print(outputs)


if __name__ == '__main__':
    test()

程序输出结果:

tensor([[1., 0., 3., 6., 7., 7., 5., 7.],
        [6., 8., 4., 6., 2., 0., 4., 1.],
        [1., 4., 6., 9., 3., 1., 2., 1.],
        [0., 6., 3., 7., 1., 7., 8., 9.],
        [5., 6., 8., 4., 1., 7., 5., 5.]])
--------------------------------------------------
tensor([[ 0.,  0., 15.,  0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0., 10.,  0.,  0.,  0.],
        [ 0.,  0.,  0., 45.,  0.,  0.,  0.,  0.],
        [ 0.,  0., 15.,  0.,  0.,  0.,  0.,  0.],
        [25.,  0.,  0.,  0.,  0.,  0.,  0., 25.]])

我们将 Dropout 层的概率 p 设置为 0.8,此时经过 Dropout 层计算的张量中就出现了很多 0 , 概率 p 设置值越大,则张量中出现的 0 就越多。上面结果的计算过程如下:

  1. 先按照 p 设置的概率,随机将部分的张量元素设置为 0
  2. 为了校正张量元素被设置为 0 带来的影响,需要对非 0 的元素进行缩放,其缩放因子为: 1/(1-p),上面代码中 p 的值为 0.8, 根据公式缩放因子为:1/(1-0.8) = 5
  3. 比如:第 3 个元素,原来是 5,乘以缩放因子之后变成 25。

我们也发现了,丢弃概率 p 的值越大,则缩放因子的值就越大,相对其他未被设置的元素就要更多的变大。丢弃概率 P 的值越小,则缩放因子的值就越小,相对应其他未被置为 0 的元素就要有较小的变大。

当张量某些元素被设置为 0 时,对网络会带来什么影响?

比如上面这种情况,如果输入该样本,会使得某些参数无法更新,请看下面的代码:

import torch
import torch.nn as nn


# 设置随机数种子
torch.manual_seed(0)


def caculate_gradient(x, w):

    y = x @ w
    y = y.sum()
    y.backward()
    print('Gradient:', w.grad.reshape(1, -1).squeeze().numpy())


def test01():


    # 初始化权重
    w = torch.randn(15, 1, requires_grad=True)
    # 初始化输入数据
    x = torch.randint(0, 10, size=[5, 15]).float()
    # 计算梯度
    caculate_gradient(x, w)


def test02():

    # 初始化权重
    w = torch.randn(15, 1, requires_grad=True)
    # 初始化输入数据
    x = torch.randint(0, 10, size=[5, 15]).float()
    # 初始化丢弃层
    dropout = nn.Dropout(p=0.8)
    x = dropout(x)
    # 计算梯度
    caculate_gradient(x, w)


if __name__ == '__main__':
    test01()
    print('-' * 70)
    test02()

程序输出结果:

Gradient: [19. 15. 16. 13. 34. 23. 20. 22. 23. 26. 21. 29. 28. 22. 29.]
----------------------------------------------------------------------
Gradient: [ 5.  0. 35.  0.  0. 45. 40. 40.  0. 20. 25. 45. 55.  0. 10.]

从程序结果来看,是否经过 Dropout 层对梯度的计算产生了不小的影响,例如:经过 Dropout 层之后有一些梯度为 0,这使得参数无法得到更新,从而达到了降低网络复杂度的目的。

为啥 dropout 能够降低模型过拟合的风险?

我们知道通过 bagging 集成思想能够降低模型的泛化误差,这是由于通过多个模型集体决策,能够在很大程度上弱化少数精度较低模型的影响。dropout 有点类似给神经网络增加了 bagging 思想。

当发生一次 dropout 就会得到一个不同的网络模型,训练完成之后就好像得到了多个网络模型,并将这些网络模型集成到了同一个神经网络中,每次预测时就好像多个模型集体决策,从而降低了模型过拟合的风险。

另外一个角度,dropout 能稀疏网络,我们知道过拟合也有可能是模型的学习能力太强,该学不该学的都学了,稀疏的网络能够降低模型的学习能力,从而起到正则化的作用。

未经允许不得转载:一亩三分地 » Dropout 正则化