1 训练阶段
原理:训练阶段dropout启动。在前向传播过程,dropout模块对于输入的每个数,都会以概率p将该数置0,如果该数被置0则输出0,如果该数未被置0则把该数乘上
1
1
−
p
\frac{1}{1-p}
1−p1作为输出。反向传播阶段,即求导数阶段,如下图所示。
下面通过代码验证一下。
前向过程
首先,我创建一个dropout层,如下所示, p = 0.3 p=0.3 p=0.3。
dp = torch.nn.Dropout(0.3)
创建变量
torch.manual_seed(10)
x = torch.randn(3, requires_grad=True) # 创建3个随机数
x
tensor([-1.2277, 0.9198, -0.3485], requires_grad=True)
y = dp(x)
y
tensor([-1.7538, 1.3140, -0.0000], grad_fn=<MulBackward0>)
可以看出第三个数经过dropout层以概率p被置0
那么以第一个数为例,它未被以概率p置0,那么输出是输入的 1 1 − p \frac{1}{1-p} 1−p1倍吗?
-1.2277*(1/(1-0.3))
-1.753857142857143
符合-1.7538
再次总结:
前向过程要么以概率p被置0,输出0;要么未被以概率p置0,输入乘
1
1
−
p
\frac{1}{1-p}
1−p1作为输出。
反向传播,即求导
因为前向过程分2种情况,那么反向传播也分两种情况:
1 若前向输出以概率p被置为0,那么输出y对输入x求导->导数0
2 否则,输出y对输入x求导->导数
1
1
−
p
\frac{1}{1-p}
1−p1
y.sum().backward() # 求导
x.grad
tensor([1.4286, 1.4286, 0.0000])
第三个数经过dropout层以概率p被置0,其导数0,第一个数未被置0,其导数是
1
1
−
p
=
1
1
−
0.3
=
1.4285714285714286
\frac{1}{1-p}=\frac{1}{1-0.3}=1.4285714285714286
1−p1=1−0.31=1.4285714285714286。
另一种验证方式
y = dp(x) # y三维向量
y.backward(torch.tensor([1.0,1.0,1.0]))
x.grad
tensor([1.4286, 1.4286, 0.0000])
2 测试阶段
原理:dropout相当于被关闭,经过dropout层得到的输出等于输入。
x为tensor([-1.2277, 0.9198, -0.3485], requires_grad=True)
dp.eval() # 测试阶段
y = dp(x)
y
tensor([-1.2277, 0.9198, -0.3485], requires_grad=True)
y==x
tensor([True, True, True])
数值相等,所以全为True
3 训练阶段和测试阶段的切换
一个模块被创建,默认是训练模式。
model.train()->训练模式;model.eval()->测试模式。
dp = torch.nn.Dropout(0.3)
dp.training # 是否是训练模式
True
dp.eval()
dp.training
False
dp.train()
dp.training
True