这一篇介绍另一种防止过拟合的方法,dropout,即丢弃某些神经元的输出.由于每次训练的过程里,丢弃掉哪些神经元的输出都是随机的,从而可以使得模型不过分依赖于某些神经元的输出,从而达到防止过拟合的目的.
需要注意的一点是:并不是简单地丢弃掉某些神经元的输出,对留下的输出,我们要改变他们的值,以保证丢弃前后的输出的期望不变
比如,对如下神经网络:输入个数为4,隐藏单元个数为5,且隐藏单元hihi(i=1,…,5i=1,…,5)的计算表达式为
hi=ϕ(x1w1i+x2w2i+x3w3i+x4w4i+bi)hi=ϕ(x1w1i+x2w2i+x3w3i+x4w4i+bi)
这里ϕϕ是激活函数,x1,…,x4x1,…,x4是输入,隐藏单元ii的权重参数为w1i,…,w4iw1i,…,w4i,偏差参数为bibi。当对该隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉。设丢弃概率为pp,那么有pp的概率hihi会被清零,有1−p1−p的概率hihi会除以1−p1−p做拉伸。丢弃概率是丢弃法的超参数。具体来说,设随机变量ξiξi为0和1的概率分别为pp和1−p1−p。使用丢弃法时我们计算新的隐藏单元h′ihi′
h′i=ξi1−phihi′=ξi1−phi
由于E(ξi)=1−pE(ξi)=1−p,因此
E(h′i)=E(ξi)1−phi=hiE(hi′)=E(ξi)1−phi=hi
从零开始实现
以一个三层的多层感知机为例.两个隐藏层的输出个数都是256.
导入必要的包
import torch
import torch.nn as nn
import numpy as np
import sys
import utils
utils.py中包含了常用的一些实现,比如数据集加载,sgd实现之类的函数都实现在了这个文件里.
实现dropout
def dropout(X,drop_prob):
X = X.float()
keep_prob = 1 - drop_prob
if keep_prob == 0:
return torch.zeros_like(X)
mask = (torch.rand(X.shape) < keep_prob).float()
#print("mask:\n",mask)
return mask * X/keep_prob
X=torch.arange(16).view(2,8)
drop_prob是丢弃的概率.其中我们用torch.rand(X.shape) < keep_prob
去生成一组bool数,表明要丢弃哪些,保留哪些.
关于torch中几种分布的用法,参考https://zhuanlan.zhihu.com/p/31231210
-
均匀分布
torch.rand(*sizes, out=None) → Tensor
返回一个张量,包含了从区间[0, 1)的均匀分布中抽取的一组随机数。张量的形状由参数sizes定义。 -
标准正态分布
torch.randn(*sizes, out=None) → Tensor
返回一个张量,包含了从标准正态分布(均值为0,方差为1,即高斯白噪声)中抽取的一组随机数。张量的形状由参数sizes定义。 -
离散正态分布
torch.normal(means, std, out=None) → → Tensor
返回一个张量,包含了从指定均值means和标准差std的离散正态分布中抽取的一组