前言 訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型時,,如果訓(xùn)練樣本較少,為了防止模型過擬合,,Dropout可以作為一種trikc供選擇,。Dropout是hintion最近2年提出的,源于其文章Improving neural networks by preventing co-adaptation of feature detectors.中文大意為:通過阻止特征檢測器的共同作用來提高神經(jīng)網(wǎng)絡(luò)的性能,。本篇博文就是按照這篇論文簡單介紹下Dropout的思想,,以及從用一個簡單的例子來說明該如何使用dropout。
基礎(chǔ)知識: Dropout是指在模型訓(xùn)練時隨機讓網(wǎng)絡(luò)某些隱含層節(jié)點的權(quán)重不工作,,不工作的那些節(jié)點可以暫時認(rèn)為不是網(wǎng)絡(luò)結(jié)構(gòu)的一部分,,但是它的權(quán)重得保留下來(只是暫時不更新而已),因為下次樣本輸入時它可能又得工作了(有點抽象,,具體實現(xiàn)看后面的實驗部分),。 按照hinton的文章,,他使用Dropout時訓(xùn)練階段和測試階段做了如下操作: 在樣本的訓(xùn)練階段,在沒有采用pre-training的網(wǎng)絡(luò)時(Dropout當(dāng)然可以結(jié)合pre-training一起使用),,hintion并不是像通常那樣對權(quán)值采用L2范數(shù)懲罰,,而是對每個隱含節(jié)點的權(quán)值L2范數(shù)設(shè)置一個上限bound,當(dāng)訓(xùn)練過程中如果該節(jié)點不滿足bound約束,,則用該bound值對權(quán)值進行一個規(guī)范化操作(即同時除以該L2范數(shù)值),,說是這樣可以讓權(quán)值更新初始的時候有個大的學(xué)習(xí)率供衰減,并且可以搜索更多的權(quán)值空間(沒理解),。 在模型的測試階段,,使用”mean network(均值網(wǎng)絡(luò))”來得到隱含層的輸出,其實就是在網(wǎng)絡(luò)前向傳播到輸出層前時隱含層節(jié)點的輸出值都要減半(如果dropout的比例為50%),,其理由文章說了一些,,可以去查看(沒理解)。 關(guān)于Dropout,,文章中沒有給出任何數(shù)學(xué)解釋,,Hintion的直觀解釋和理由如下: 1. 由于每次用輸入網(wǎng)絡(luò)的樣本進行權(quán)值更新時,隱含節(jié)點都是以一定概率隨機出現(xiàn),,因此不能保證每2個隱含節(jié)點每次都同時出現(xiàn),,這樣權(quán)值的更新不再依賴于有固定關(guān)系隱含節(jié)點的共同作用,阻止了某些特征僅僅在其它特定特征下才有效果的情況,。 2. 可以將dropout看作是模型平均的一種,。對于每次輸入到網(wǎng)絡(luò)中的樣本(可能是一個樣本,也可能是一個batch的樣本),,其對應(yīng)的網(wǎng)絡(luò)結(jié)構(gòu)都是不同的,,但所有的這些不同的網(wǎng)絡(luò)結(jié)構(gòu)又同時share隱含節(jié)點的權(quán)值。這樣不同的樣本就對應(yīng)不同的模型,,是bagging的一種極端情況,。個人感覺這個解釋稍微靠譜些,和bagging,,boosting理論有點像,,但又不完全相同。 3. native bayes是dropout的一個特例,。Native bayes有個錯誤的前提,,即假設(shè)各個特征之間相互獨立,這樣在訓(xùn)練樣本比較少的情況下,,單獨對每個特征進行學(xué)習(xí),測試時將所有的特征都相乘,,且在實際應(yīng)用時效果還不錯,。而Droput每次不是訓(xùn)練一個特征,,而是一部分隱含層特征。 4. 還有一個比較有意思的解釋是,,Dropout類似于性別在生物進化中的角色,,物種為了使適應(yīng)不斷變化的環(huán)境,性別的出現(xiàn)有效的阻止了過擬合,,即避免環(huán)境改變時物種可能面臨的滅亡,。 文章最后當(dāng)然是show了一大把的實驗來說明dropout可以阻止過擬合。這些實驗都是些常見的benchmark,,比如Mnist, Timit, Reuters, CIFAR-10, ImageNet.
實驗過程: 本文實驗時用mnist庫進行手寫數(shù)字識別,,訓(xùn)練樣本2000個,測試樣本1000個,,用的是matlab的https://github.com/rasmusbergpalm/DeepLearnToolbox,,代碼在test_example_NN.m上修改得到。關(guān)于該toolbox的介紹可以參考網(wǎng)友的博文【面向代碼】學(xué)習(xí) Deep Learning(一)Neural Network,。這里我只用了個簡單的單個隱含層神經(jīng)網(wǎng)絡(luò),,隱含層節(jié)點的個數(shù)為100,所以輸入層-隱含層-輸出層節(jié)點依次為784-100-10. 為了使本例子簡單話,,沒用對權(quán)值w進行規(guī)則化,,采用mini-batch訓(xùn)練,每個mini-batch樣本大小為100,,迭代20次,。權(quán)值采用隨機初始化。
實驗結(jié)果: 沒用Dropout時: 訓(xùn)練樣本錯誤率(均方誤差):0.032355 測試樣本錯誤率:15.500% 使用Dropout時: 訓(xùn)練樣本錯誤率(均方誤差):0.075819 測試樣本錯誤率:13.000% 可以看出使用Dropout后,,雖然訓(xùn)練樣本的錯誤率較高,,但是訓(xùn)練樣本的錯誤率降低了,說明Dropout的泛化能力不錯,,可以防止過擬合,。
實驗主要代碼及注釋: test_dropout.m: %% //導(dǎo)入minst數(shù)據(jù)并歸一化 load mnist_uint8; train_x = double(train_x(1:2000,:)) / 255; test_x = double(test_x(1:1000,:)) / 255; train_y = double(train_y(1:2000,:)); test_y = double(test_y(1:1000,:)); % //normalize [train_x, mu, sigma] = zscore(train_x);% //歸一化train_x,其中mu是個行向量,mu是個列向量 test_x = normalize(test_x, mu, sigma);% //在線測試時,歸一化用的是訓(xùn)練樣本的均值和方差,,需要特別注意 %% //without dropout rng(0); nn = nnsetup([784 100 10]);% //初步構(gòu)造了一個輸入-隱含-輸出層網(wǎng)絡(luò),,其中包括了 % //權(quán)值的初始化,學(xué)習(xí)率,,momentum,,激發(fā)函數(shù)類型, % //懲罰系數(shù),,dropout等 opts.numepochs = 20; % //Number of full sweeps through data opts.batchsize = 100; % //Take a mean gradient step over this many samples [nn, L] = nntrain(nn, train_x, train_y, opts); [er, bad] = nntest(nn, test_x, test_y); str = sprintf('testing error rate is: %f',er); disp(str) %% //with dropout rng(0); nn = nnsetup([784 100 10]); nn.dropoutFraction = 0.5; % //Dropout fraction,,每一次mini-batch樣本輸入訓(xùn)練時,隨機扔掉50%的隱含層節(jié)點 opts.numepochs = 20; % //Number of full sweeps through data opts.batchsize = 100; % //Take a mean gradient step over this many samples nn = nntrain(nn, train_x, train_y, opts); [er, bad] = nntest(nn, test_x, test_y); str = sprintf('testing error rate is: %f',er); disp(str) 下面來分析與dropout相關(guān)的代碼,,集中在上面test.m代碼的后面with drop部分,。首先在訓(xùn)練過程中需要將神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)nn的dropoutFraction設(shè)置為一定比例,,這里設(shè)置為50%:nn.dropoutFraction = 0.5; 然后進入test_dropout.m中的nntrain()函數(shù),沒有發(fā)現(xiàn)與dropoutFraction相關(guān)的代碼,,繼續(xù)進入網(wǎng)絡(luò)前向傳播函數(shù)nnff()函數(shù)中,,在網(wǎng)絡(luò)的隱含層節(jié)點激發(fā)函數(shù)值被計算出來后,有下面的代碼: if(nn.dropoutFraction > 0) if(nn.testing) nn.a{i} = nn.a{i}.*(1 - nn.dropoutFraction); else nn.dropOutMask{i} = (rand(size(nn.a{i}))>nn.dropoutFraction); nn.a{i} = nn.a{i}.*nn.dropOutMask{i}; end end 由上面的代碼可知,,隱含層節(jié)點的輸出值以dropoutFraction百分比的幾率被隨機清0(注意此時是在訓(xùn)練階段,,所以是else那部分的代碼),既然前向傳播時有些隱含節(jié)點值被清0了,,那么在誤差方向傳播時也應(yīng)該有相應(yīng)的處理,,果然,在反向傳播函數(shù)nnbp()中,,有下面的代碼: if(nn.dropoutFraction>0) d{i} = d{i} .* [ones(size(d{i},1),1) nn.dropOutMask{i}]; end 也就是說計算節(jié)點誤差那一項時,,其誤差項也應(yīng)該清0。從上面可以看出,,使用dropout時,,其訓(xùn)練部分的代碼更改很少。 (有網(wǎng)友發(fā)私信說,,反向傳播計算誤差項時可以不用乘以dropOutMask{i}矩陣,,后面我仔細看了下bp的公式,一開始也感覺不用乘有道理,。因為源碼中有為: for i = 1 : (n - 1) if i+1==n nn.dW{i} = (d{i + 1}' * nn.a{i}) / size(d{i + 1}, 1); else nn.dW{i} = (d{i + 1}(:,2:end)' * nn.a{i}) / size(d{i + 1}, 1); end end 代碼進行權(quán)重更新時,,由于需要乘以nn.a{i},而nn.a{i}在前向過程中如果被mask清掉的話(使用了dropout前提下),則已經(jīng)為0了,。但其實這時錯誤的,,因為對誤差 敏感值作用的是與它相連接的前一層權(quán)值,并不是本層的權(quán)值,,而本層的輸出a只對它的下一層權(quán)值更新有效,。) 再來看看測試部分,測試部分如hintion論文所說的,,采用mean network,也就是說前向傳播時隱含層所有節(jié)點的輸出同時減小dropoutFraction百分比,,即保留(1- dropoutFraction)百分比,代碼依舊是上面貼出的nnff()函數(shù)里滿足if(nn.testing)的部分: if(nn.dropoutFraction > 0) if(nn.testing) nn.a{i} = nn.a{i}.*(1 - nn.dropoutFraction); else nn.dropOutMask{i} = (rand(size(nn.a{i}))>nn.dropoutFraction); nn.a{i} = nn.a{i}.*nn.dropOutMask{i}; end end 上面只是個簡單的droput實驗,,可以用來幫助大家理解dropout的思想和使用步驟,。其中網(wǎng)絡(luò)的參數(shù)都是采用toolbox默認(rèn)的,并沒有去調(diào)整它,,如果該實驗將訓(xùn)練樣本增大,,比如6w張,則參數(shù)不變的情況下使用了dropout的識別率還有可能會降低(當(dāng)然這很有可能是其它參數(shù)沒調(diào)到最優(yōu),另一方面也說明在樣本比較少的情況下,,droput確實可以防止過擬合),,為了體現(xiàn)droput的優(yōu)勢,這里我只用了2000張訓(xùn)練樣本,。
參考資料: Hinton, G. E., et al. (2012). "Improving neural networks by preventing co-adaptation of feature detectors." arXiv preprint arXiv:1207.0580. https://github.com/rasmusbergpalm/DeepLearnToolbox 【面向代碼】學(xué)習(xí) Deep Learning(一)Neural Network
|
|