參數正則化方法 - Dropout
受人類繁衍后代時男女各一半基因進行組合產生下一代的啟發,論文(Dropout: A Simple Way to Prevent Neural Networks from Overfitting)提出了Dropout。
Dropout是一種在深度學習環境中應用的正規化手段。它是這樣運作的:在一次循環中我們先隨機選擇神經層中的一些單元並將其臨時隱藏,然后再進行該次循環中神經網絡的訓練和優化過程。在下一次循環中,我們又將隱藏另外一些神經元,如此直至訓練結束。
在訓練時,每個神經單元以概率p被保留(dropout丟棄率為1-p);在測試階段,每個神經單元都是存在的,權重參數w要乘以p,成為:pw。測試時需要乘上p的原因:考慮第一隱藏層的一個神經元在dropout之前的輸出是x,那么dropout之后的期望值是\(E=px + (1-p)0\) ,在測試時該神經元總是激活,為了保持同樣的輸出期望值並使下一層也得到同樣的結果,需要調整\(x \rightarrow px\). 其中p是Bernoulli分布(0-1分布)中值為1的概率。示意圖如下:
inverted dropout
在訓練時由於舍棄了一些神經元,因此在測試時需要在激勵的結果中乘上因子p進行縮放.但是這樣需要需要對測試的代碼進行更改並增加了測試時的計算量,非常影響測試性能。通常為了提高測試的性能(減少測試時的運算時間),可以將縮放的工作轉移到訓練階段,而測試階段與不使用dropout時相同,稱為 **inverted dropout **:將前向傳播dropout時保留下來的神經元的權重乘上1/p(看做懲罰項,使權重擴大為原來的1/p倍,這樣測試時不用再縮小權重),代碼參考這里。
在架構中添加inverted Dropout這一改動僅會影響訓練過程,而並不影響測試過程。
drop的比例常用值是p=0.5 .
Dropout率和正規化有什么關系?我們定義Dropout率為保留一個神經元為激活狀態的概率.Dropout率越高,意味着更多神經元是激活的,正規化程度越低.
Dropout可以與Max-norm regularization,較大的初始學習率和較高的動量(momentum)等結合獲得比單獨使用Dropout更好的效果。由於Max-norm regularization的應用,設置較大的學習率不至於發生梯度爆炸。
Dropout對於循環層效果並不理想,你可能需要稍微修改一下dropout技術來得到良好的結果。
在dropout的過程中,神經元被失活,在dropconnect的過程中,失活的是神經元之間的連接。所以dropout會使輸入和輸出權重都變為無效,而在dropconnect中,只有其中一種會被失活。
Dropout可以看作是Bagging的極限形式,每個模型都在當一種情況訓練,同時模型的每個參數都經過與其他模型共享參數,從而高度正則化。
AlphaDropout
Alpha Dropout是一種保持輸入均值和方差不變的Dropout,該層的作用是通過縮放和平移使得在dropout時也保持數據的自規范性。Alpha Dropout與SELU激活函數配合較好。更多細節參考論文Self-Normalizing Neural Networks
.
代碼實現
caffe dropout_layer 代碼如下:
// LayerSetUp
DCHECK(threshold_ > 0.);
DCHECK(threshold_ < 1.);
scale_ = 1. / (1. - threshold_);
// forward
void DropoutLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
const Dtype* bottom_data = bottom[0]->cpu_data();
Dtype* top_data = top[0]->mutable_cpu_data();
unsigned int* mask = rand_vec_.mutable_cpu_data();
const int count = bottom[0]->count();
if (this->phase_ == TRAIN) {
// 產生01掩碼,伯努利隨機數
caffe_rng_bernoulli(count, 1. - threshold_, mask);
for (int i = 0; i < count; ++i) {
// 丟棄部分置0,保留部分按inverted dropout需要放大scale_倍
top_data[i] = bottom_data[i] * mask[i] * scale_;
}
} else { // 測試階段原樣輸出
caffe_copy(bottom[0]->count(), bottom_data, top_data);
}
}
//backward
void DropoutLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) {
if (propagate_down[0]) {
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
if (this->phase_ == TRAIN) {
const unsigned int* mask = rand_vec_.cpu_data();
const int count = bottom[0]->count();
for (int i = 0; i < count; ++i) {
bottom_diff[i] = top_diff[i] * mask[i] * scale_;
}
} else {
caffe_copy(top[0]->count(), top_diff, bottom_diff);
}
}
}
可以進一步閱讀的論文有:
- Dropout paper by Srivastava et al. 2014.
- Dropout Training as Adaptive Regularization: "we show that the dropout regularizer is first-order equivalent to an L2 regularizer applied after scaling the features by an estimate of the inverse diagonal Fisher information matrix".