深度学习中的Dropout简介及实现
在訓練神經網絡模型時候,如果模型相對復雜即參數較多而訓練樣本相對較少,這時候訓練出的模型可能對訓練集中的數據擬合的比較好,但在測試集上的表現較差,即出現了過擬合的情況。這種情況下可以使用Dropout來降低過擬合的可能性進而提高模型的泛化能力。過擬合指的是模型在訓練數據上損失函數比較小,預測準確率較高,但是在測試數據上損失函數比較大,預測準確率較低。Dropout可以隨機地臨時選擇一些中間層中的神經元,使這些神經元不起作用,即在本次迭代中輸出為零,同時保持輸入層和輸出層的神經元數目不變。在反向傳播并更新參數的過程中,與這些節點相連的權值也不需要更新。但是這些節點并不從網絡中刪除,并且其權值也保留下來,以使這些節點在下一次迭代時重新被選中作為起作用點而參與權值的更新。Dropout由Hinton等人于2012年提出,論文名字為《Improving neural networks by preventing co-adaptation of feature detetors》,關于Dropout更詳細的介紹可參考另一篇論文,論文名字為《Dropout: A Simple Way to Prevent Neural Networks from Overfitting》,下面的一些截圖均來自此論文,論文下載地址:http://jmlr.org/papers/volume15/srivastava14a/srivastava14a.pdf
由于每次使用輸入網絡的樣本進行權值更新時,隱含層的節點都是以一定的概率隨機出現,因此不能保證每2個隱含節點每次都能同時出現,這樣權值更新將不再依賴于具有固定關系隱含節點的共同作用,阻止了某些特征僅僅在其它特定特征下才有效果的情況。消除或減弱了神經元節點間的聯合適應性,增強了泛化能力。也可以將Dropout看做是模型平均的一種。所謂模型平均,就是把來自不同模型的估計或者預測通過一定的權重平均起來,在一些文獻中也稱為模型組合。因為對于每次輸入到網絡的樣本,由于隱藏層節點的隨機性,其對應的網絡結構都是不同的,但所有的這些不同的網絡結構又同時共享了隱藏層之間的權值。
Dropout神經網絡結構如下圖所示:
應用Dropout的多層神經網絡中,在訓練階段的前向計算過程如下所示:
標準網絡與Dropout網絡的基本操作比較如下圖所示:
Dropout在訓練階段和測試階段描述如下圖所示:
Dropout適合用于數據量大的大型網絡中。Dropout應用在訓練階段,用于減少過擬合。Dropout可以與神經網絡的大多數層一起使用,如全連接層、卷積層、循環層。Dropout能被實現在任何隱含層或可見層或輸入層,Dropout不能被應用在輸出層。
Dropout一般執行過程:
(1). 首先隨機(臨時)刪掉網絡中一些隱藏神經元即使某些神經元輸出為0,輸入輸出神經元保持不變
(2). 然后把輸入通過修改后的網絡前向傳播,然后把得到的損失結果通過修改的網絡反向傳播。一小批訓練樣本執行完這個過程后,在沒有被刪除的神經元上按照隨機梯度下降法更新對應的參數(w, b)。
(3). 然后繼續重復這一過程:恢復被刪掉的神經元(此時被刪除的神經元參數保持不變,而沒有被刪除的神經元已經有所更新);從隱藏層神經元中再次隨機選擇一些神經元臨時刪除掉(備份被刪除神經元的參數);對一小批訓練樣本,先前向傳播然后反向傳播損失并根據隨機梯度下降法更新參數(w,b)(沒有被刪除的那一部分參數得到更新,刪除的神經元參數保持被刪除前的結果)。
不斷重復這一過程。
以下是測試代碼:
#include <time.h>
#include <cmath>
#include <vector>
#include <limits>
#include <string>
#include <tuple>
#include <random>
#include <memory>
#include <random>
#include <opencv2/opencv.hpp>#define EXP 1.0e-5namespace fbc {// ============================ Dropout ================================
template<class T>
int dropout(const T* bottom, int width, int height, T* top, float dropout_ratio = 0.5f)
{if (dropout_ratio <= 0.f || dropout_ratio >= 1.f) {fprintf(stderr, "Error: dropout_ratio's value should be: (0., 1.): %f\n", dropout_ratio);return -1;}std::random_device rd; std::mt19937 gen(rd());std::bernoulli_distribution d(1. - dropout_ratio);int size = height * width;std::unique_ptr<int[]> mask(new int[size]);for (int i = 0; i < size; ++i) {mask[i] = (int)d(gen);}float scale = 1. / (1. - dropout_ratio);for (int i = 0; i < size; ++i) {top[i] = bottom[i] * mask[i] * scale;}return 0;
}} // namespace fbcint test_dropout()
{std::random_device rd; std::mt19937 gen(rd());int height = 4, width = 8, size = height * width;std::unique_ptr<float[]> bottom(new float[size]), top(new float[size]); std::uniform_real_distribution<float> distribution(-10.f, 10.f);for (int i = 0; i < size; ++i) {bottom[i] = distribution(gen);}float dropout_ratio = 0.8f;if (fbc::dropout(bottom.get(), width, height, top.get(), dropout_ratio) != 0) {fprintf(stderr, "Error: fail to dropout\n");return -1;}fprintf(stdout, "bottom data:\n");for (int h = 0; h < height; ++h) {for (int w = 0; w < width; ++w) {fprintf(stdout, " %f ", bottom[h * width + w]);}fprintf(stdout, "\n");}fprintf(stdout, "top data:\n");for (int h = 0; h < height; ++h) {for (int w = 0; w < width; ++w) {fprintf(stdout, " %f ", top[h * width + w]);}fprintf(stdout, "\n");}return 0;
}
執行結果如下圖所示:
GitHub:?https://github.com/fengbingchun/NN_Test?
總結
以上是生活随笔為你收集整理的深度学习中的Dropout简介及实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python3中PyMongo使用举例
- 下一篇: 程序员的自我修养--链接、装载与库笔记: