天天看點

深度學習筆記5:正則化與dropout

在筆記 4 中,筆者詳細闡述了機器學習中利用正則化防止過拟合的基本方法,對 L1 和 L2 範數進行了通俗的解釋。為了防止深度神經網絡出現過拟合,除了給損失函數加上 L2 正則化項之外,還有一個很著名的方法——dropout.

廢話少說,咱們單刀直入正題。究竟啥是 dropout ? dropout 是指在神經網絡訓練的過程中,對所有神經元按照一定的機率進行消除的處理方式。在訓練深度神經網絡時,dropout 能夠在很大程度上簡化神經網絡結構,防止神經網絡過拟合。是以,從本質上而言,dropout 也是一種神經網絡的正則化方法。

假設我們要訓練了一個 4 層(3個隐層)的神經網絡,該神經網絡存在着過拟合。于是我們決定使用 dropout 方法來處理,dropout 為該網絡每一層的神經元設定一個失活(drop)機率,在神經網絡訓練過程中,我們會丢棄一些神經元節點,在網絡圖上則表示為該神經元節點的進出連線被删除。最後我們會得到一個神經元更少、模型相對簡單的神經網絡,這樣一來原先的過拟合情況就會大大的得到緩解。這樣說似乎并沒有将 dropout 正則化原了解釋清楚,我們繼續深究一下:為什麼 dropout 可以可以通過正則化發揮防止過拟合的功能?

因為 dropout 可以随時随機的丢棄任何一個神經元,神經網絡的訓練結果不會依賴于任何一個輸入特征,每一個神經元都以這種方式進行傳播,并為神經元的所有輸入增加一點權重,dropout 通過傳播所有權重産生類似于 L2 正則化收縮權重的平方範數的效果,這樣的權重壓縮類似于 L2 正則化的權值衰減,這種外層的正則化起到了防止過拟合的作用。

是以說,總體而言,dropout 的功能類似于 L2 正則化,但又有所差別。另外需要注意的一點是,對于一個多層的神經網絡,我們的 dropout 某層神經元的機率并不是一刀切的。對于不同神經元個數的神經網絡層,我們可以設定不同的失活或者保留機率,對于含有較多權值的層,我們可以選擇設定較大的失活機率(即較小的保留機率)。是以,總結來說就是如果你擔心某些層所含神經元較多或者比其他層更容易發生過拟合,我們可以将該層的失活機率設定的更高一些。

說了這麼多,總算大緻把 dropout 說明白了。那 dropout 這種操作在實際的 python 程式設計中該如何實作呢?以一個三層的神經網絡為例,首先我們需要定義一個 3 層的 dropout 向量,然後将其與保留機率 keep-prob 進行比較生成一個布爾值向量,再将其與該層的神經元激活輸出值進行乘積運算,最後擴充上一步的計算結果,将其除以 keep-prob 即可。但在實際程式設計中就沒說的這麼容易了,我們需要對整個神經網絡的計算過程進行重新定義,包括前向傳播和反向傳播的計算定義。

含 dropout 的前向計算定義如下:

def forward_propagation_with_dropout(X, parameters, keep_prob = 0.5):
 np.random.seed(1) # retrieve parameters
 W1 = parameters["W1"]
 b1 = parameters["b1"]
 W2 = parameters["W2"]
 b2 = parameters["b2"]
 W3 = parameters["W3"]
 b3 = parameters["b3"] # LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID
 Z1 = np.dot(W1, X) + b1
 A1 = relu(Z1)

 D1 = np.random.rand(A1.shape[0], A1.shape[1]) 
 D1 = D1 < keep_prob 
 A1 = np.multiply(D1, A1) 
 A1 = A1 / keep_prob 

 A2 = relu(Z2)
 Z2 = np.dot(W2, A1) + b2

 D2 = np.random.rand(A2.shape[0], A2.shape[1]) 
 D2 = D2 < keep_prob 
 A2 = np.multiply(D2, A2) 
 A2 = A2 / keep_prob 
 A3 = sigmoid(Z3)
 Z3 = np.dot(W3, A2) + b3

 cache = (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3) 
 return A3, cache           

以上代碼基本展現了 dropout 的實作的四步流程。

含 dropout 的反向傳播計算定義如下:

def backward_propagation_with_dropout(X, Y, cache, keep_prob):

 m = X.shape[1]
 (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3) = cache

 dZ3 = A3 - Y
 dW3 = 1./m * np.dot(dZ3, A2.T)
 db3 = 1./m * np.sum(dZ3, axis=1, keepdims = True)
 dA2 = np.dot(W3.T, dZ3)

 dA2 = np.multiply(dA2, D2) 
 dA2 = dA2 / keep_prob 

 dZ2 = np.multiply(dA2, np.int64(A2 > 0))
 dW2 = 1./m * np.dot(dZ2, A1.T)
 db2 = 1./m * np.sum(dZ2, axis=1, keepdims = True)

 dA1 = np.dot(W2.T, dZ2)

 dA1 = np.multiply(dA1, D1) 
 dA1 = dA1 / keep_prob 

 dZ1 = np.multiply(dA1, np.int64(A1 > 0))
 dW1 = 1./m * np.dot(dZ1, X.T)
 db1 = 1./m * np.sum(dZ1, axis=1, keepdims = True)

 gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,"dA2": dA2, "dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1, 
 "dZ1": dZ1, "dW1": dW1, "db1": db1} 
 return gradients           

在定義反向傳播計算函數時,我們必須丢棄和執行前向傳播時一樣的神經元。

最後帶有 dropout 的分類效果如下所示:

深度學習筆記5:正則化與dropout

是以,總結而言,dropout 就是在正常的神經網絡基礎上給每一層的每一個神經元加了一道機率流程來随機丢棄某些神經元以達到防止過拟合的目的。

原文釋出時間為:2018-09-3本文作者:louwill本文來自雲栖社群合作夥伴“

Python愛好者社群

”,了解相關資訊可以關注“

”。