NTU李宏毅老師的《深度學(xué)習(xí)》課程講dropout的本質(zhì)是模型融合ensemble(bagging性質(zhì))。
-
Train階段
在train的時(shí)候,每一次update參數(shù)之前,對network里面的每個(gè)neural(包括input),做sampling(抽樣)。 每個(gè)neural會(huì)有p%會(huì)被丟掉,跟著的weight也會(huì)被丟掉。
image.png
接著使用新的改變了的網(wǎng)絡(luò)結(jié)構(gòu)進(jìn)行訓(xùn)練。那么顯然由于某些neural不見了,你在training 時(shí),performance會(huì)變的有一點(diǎn)差,加上dropout,你會(huì)看到在testing set會(huì)變得有點(diǎn)差,但是dropout真正做的事就是讓你testing 越做越好
-
test階段
image.png
注意兩點(diǎn)
- test階段是不做dropout處理的
- 假設(shè)training時(shí)dropout rate是p%,在testing rate時(shí)weights都要乘以(1-p)%
fully-connected neural layer 用drop-out
為什么dropout會(huì)有效?為什么在訓(xùn)練的時(shí)候要dropout,但是測試的時(shí)候不dropout?
-
直觀的理解
image.png -
本質(zhì)
模型融合的操作如下:將多個(gè)模型的預(yù)測結(jié)果取平均。如果model很復(fù)雜時(shí),這一招是往往有用的,能夠有效的降低模型的variance。
image.png
而dropout就相當(dāng)于每個(gè)mini batch 訓(xùn)練一個(gè)模型,雖然每次更新只更新一個(gè)網(wǎng)絡(luò)的參數(shù),由于每個(gè)子網(wǎng)絡(luò)之間參數(shù)共享,對每個(gè)子網(wǎng)絡(luò)的訓(xùn)練相當(dāng)于對整個(gè)網(wǎng)絡(luò)的訓(xùn)練,所以最終得到了針對整個(gè)數(shù)據(jù)集的多個(gè)模型
image.pngimage.png
那么在testing的時(shí)候,按照ensemble方法,我們需要把之前的每個(gè)不同dropout的network拿出來,然后把train data丟到network里面去,每一個(gè)network都會(huì)給你一個(gè)結(jié)果,這些結(jié)果的平均值就是最終的結(jié)果。但是實(shí)際上沒有辦法這樣做,因?yàn)閚etwork太多了。(每個(gè)神經(jīng)元有2種可能,一共N個(gè)神經(jīng)元,則有個(gè)網(wǎng)絡(luò))。dropout最神奇的是:當(dāng)你把一個(gè)完整的network不進(jìn)行dropout,但是將它的weights乘以(1-p)%,然后將train data輸入,得到的output y:之前做average的結(jié)果跟output y是approximated。
為什么會(huì)近似?

通過以上例子可以發(fā)現(xiàn),針對只有2個(gè)神經(jīng)元的全連接網(wǎng)絡(luò),dropout后一個(gè)產(chǎn)生四種可能的網(wǎng)絡(luò)結(jié)構(gòu),對他們的輸出做average,等效于不做dropout時(shí)對每個(gè)w*(1-p)%,所以dropout的本質(zhì)就是模型融合。同時(shí)只有是linear network,ensemble才會(huì)等于weights multiply一個(gè)值。所以一般都是在全連接網(wǎng)絡(luò)后面加入dropout。
實(shí)踐中比較常用的不是直接dropout,而是inveted dropout。原理是在訓(xùn)練的時(shí)候dropout之后做一個(gè)比例縮放,將所有w乘1/(1-p),則測試的時(shí)候不需要做縮放。無論做不做dropout,可保持inference代碼不變。
""" 普通版隨機(jī)失活: 不推薦實(shí)現(xiàn) (看下面筆記) """
p = 0.5 # 激活神經(jīng)元的概率. p值更高 = 隨機(jī)失活更弱
def train_step(X):
""" X中是輸入數(shù)據(jù) """
# 3層neural network的前向傳播
H1 = np.maximum(0, np.dot(W1, X) + b1)
U1 = np.random.rand(*H1.shape) < p # 第一個(gè)隨機(jī)失活遮罩,rand() [0,1)的隨機(jī)數(shù)
H1 *= U1 # drop!
H2 = np.maximum(0, np.dot(W2, H1) + b2)
U2 = np.random.rand(*H2.shape) < p # 第二個(gè)隨機(jī)失活遮罩
H2 *= U2 # drop!
out = np.dot(W3, H2) + b3
# 反向傳播:計(jì)算梯度... (略)
# 進(jìn)行參數(shù)更新... (略)
def predict(X):
# 前向傳播時(shí)模型集成
H1 = np.maximum(0, np.dot(W1, X) + b1) * p # 注意:激活數(shù)據(jù)要乘以p
H2 = np.maximum(0, np.dot(W2, H1) + b2) * p # 注意:激活數(shù)據(jù)要乘以p
out = np.dot(W3, H2) + b3
"""
反向隨機(jī)失活: 推薦實(shí)現(xiàn)方式.
在訓(xùn)練的時(shí)候drop和調(diào)整數(shù)值范圍,測試時(shí)不做任何事.
"""
p = 0.5 # 激活神經(jīng)元的概率. p值更高 = 隨機(jī)失活更弱
def train_step(X):
# 3層neural network的前向傳播
H1 = np.maximum(0, np.dot(W1, X) + b1)
U1 = (np.random.rand(*H1.shape) < p) / p # 第一個(gè)隨機(jī)失活遮罩. 注意/p!
H1 *= U1 # drop!
H2 = np.maximum(0, np.dot(W2, H1) + b2)
U2 = (np.random.rand(*H2.shape) < p) / p # 第二個(gè)隨機(jī)失活遮罩. 注意/p!
H2 *= U2 # drop!
out = np.dot(W3, H2) + b3
# 反向傳播:計(jì)算梯度... (略)
# 進(jìn)行參數(shù)更新... (略)
def predict(X):
# 前向傳播時(shí)模型集成
H1 = np.maximum(0, np.dot(W1, X) + b1) # 不用數(shù)值范圍調(diào)整了
H2 = np.maximum(0, np.dot(W2, H1) + b2)
out = np.dot(W3, H2) + b3





