丢弃法 讨论区


#42

我想因为两种方式一起使用,使得weight parameters 得不到充分训练,所以会欠拟合。你可以试试把weight decay 的lambda调小,dropout的概率调小,试试,应该就OK了


#43

为什么不把dropout写在激活函数之前呢?这样不是应该会比较省时吗?


#44
  • 以本节中的模型为例,比较使用丢弃法与权重衰减的效果。如果同时使用丢弃法和权重衰减,效果会如何?
    使用如下代码做了尝试,发现同时使用丢弃法和权重衰减,效果很差,分类结果近似于在10个类别中随机猜测一种,测试精度约等于1/10。
    被丢弃的权重对Loss的导数是0,参数更新之后,这一项权重会变成接近0,退回到类似于刚初始化时的权重。

如果非得同时使用丢弃法和权重衰减,那就需要修改权重衰减的范数惩罚项,计算范数惩罚项时只考虑没有被drop的那些权重。


#45

dropout不会节省计算量。
用程序实现dropout时,不会真的“drop”,只是把某些权重设置为0,其它权重乘以(1/(1-p))。
其它的运算照旧进行。

比如,假设某一层有五个权重,分别为w0, w1,w2,w3,w4。
输入为:x0,x1,x2,x3,x4
输出为:O
假设w1和w4被丢弃。
drop层的操作是:(1)把w1和w4设置为0;(2)把w0,w2,w3都乘以5/3.

程序中输出O的计算方法仍然是:
O = w0x0+w1x1+w2x2+w3x3+w4*x4
只不过此时,w1=0,w4=0.

下面的这种实现方法,看似节省了 +w1x1 和 +w4x4 两次乘法,两次加法。
但是程序增加了一些分支,反而会降低程序运行速度。
O = 0
if (w0 没有被drop)
O = O+ w0x0
if (w1 没有被drop)
O = O+ w1
x1
if (w0 没有被drop)
O = O+ w2x2
if (w0 没有被drop)
O = O+ w3
x3
if (w0 没有被drop)
O = O+ w4*x4


#46

同时使用 丢弃法 和权重衰减,把权重衰减参数设置小一点,wd=0.01。
实验结果如下。虽然比wd=1好多了。但是仍然不如单独使用 丢弃法。


#47

我也有这样的疑惑,文中Out[3]的输出并不能保证一定是8个值为0,甚至有可能是14个为0,所以感觉dropout函数的实现不完美


#48

Hi, I found a bug:

import d2lzh as d2l
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import loss as gloss, nn

def dropout(X, drop_prob):
assert 0<=drop_prob<=1
keep_prob = 1 - drop_prob
if keep_prob==0:
return X.zeros_like()
tmp = nd.random.uniform(0, 1, X.shape)
print(tmp)
mask = tmp < 0.5
return mask * X / keep_prob
X = nd.arange(16).reshape((2,8))
X = dropout(X,0.5)
print(X)

[[0.5488135 0.5928446 0.71518934 0.84426576 0.60276335 0.8579456
** 0.5448832 0.8472517 ]**
** [0.4236548 0.6235637 0.6458941 0.3843817 0.4375872 0.2975346**
** 0.891773 0.05671298]]**
<NDArray 2x8 @cpu(0)>

[[ 0. 0. 0. 0. 0. 0. 0. 0.]
** [16. 0. 0. 22. 24. 26. 0. 30.]]**
<NDArray 2x8 @cpu(0)>
跑很多次,第一行一直是0?感觉nd.random.uniform(0, 1, X.shape)这一行代码有问题。
改成下面这样就没问题,不知道为什么。
def dropout(X, drop_prob):
assert 0<=drop_prob<=1
keep_prob = 1 - drop_prob
if keep_prob==0:
return X.zeros_like()
nd.random.uniform(0, 1, X.shape)
tmp = nd.random.uniform(0, 1, X.shape)
print(tmp)
mask = tmp < 0.5
return mask * X / keep_prob


#49

为了reproducibility,默认下随机种子一开始是固定的,再运行一遍就会换一拨随机数


#50

没看明白啊。和你图片完全相同的代码,我这里运行的时候第一行一定是0,不懂为什么。


#51

设置seed,的确起作用,但是不设置也应该没问题啊。


#52

因为默认情况下随机种子不变,
第一次生成的
nd.random.uniform(0, 1, X.shape)
都是相同的大于0.5的几个数

再运行一下
nd.random.uniform(0, 1, X.shape)
就会重新生成几个其他的随机数


#53

可是斑竹你没解释为什么你图片里面的代码在我这里得不到想要的结果啊。我这里跑,第一行总是大于0.5的数。


#54

每次重启python console, 运行如下代码:
from mxnet import nd; nd.random.uniform(0, 1, (2,8))
产生的array第一行肯定都是大于0.5的数,这是不合理的。


#55

是这样,同一个platform下,默认下随机种子是固定的。所以每次重启时,第一次获得的
nd.random.uniform(0, 1, (2,8))
的结果是固定的。这个默认行为的原因是为了reproducibility方便。

如果想要获得一组其他随机数,

方法一:设其他的随机种子,这样重启后第一次获得的随机数会和现在的不一样
方法二:重启后多跑几遍


#56

不理解的是,nd.random.uniform应该是从均匀分布U[0,1]中独立采样2*8个sample, 这16个数的均值应该是0.5,而且大于0.5和小于0.5的数应该随机出现。但是下面的结果就是异常的:
[[0.5488135 0.5928446 0.71518934 0.84426576 0.60276335 0.8579456 0.5448832 0.8472517 ]
[0.4236548 0.6235637 0.6458941 0.3843817 0.4375872 0.2975346 0.891773 0.05671298]]
因为第一行0.5488135…0.8472517都是大于0.5的。这种现象一次出现是可能(概率小,0.5^16),但是当你每次重启python console, 这种情况一定会出现,这就不正常了。感觉你一直没理解我的问题呢?


#57

纠正一下,0.5^16 ----> 0.5^8,如果只关注第一行的8个数。


#58

我理解你的意思是,每次重启python console时,运行nd.random.uniform的前8个数总是相同的

所以我上面回复:


#59

重新试了一下,的确是一样的。所以情况是:虽然第一行都大于0.5的概率很小,但是只发生了一次。不算特别异常。谢谢你的耐心回复。


#60

依概率丢弃而非严格的数目来丢弃的话,泛化性能应该更好吧


#61

同样,不用dropout时效果更好,但增大靠近输入层的丢弃率后模型不容易收敛。