本文是吳恩達老師的深度學習課程[1]筆記部分。
作者:黃海廣[2]
主要編寫人員:黃海廣、林興木(第四所有底稿,第五課第一二週,第三週前三節)、祝彥森:(第三課所有底稿)、賀志堯(第五課第三週底稿)、王翔、胡瀚文、 餘笑、 鄭浩、李懷鬆、 朱越鵬、陳偉賀、 曹越、 路皓翔、邱牧宸、 唐天澤、 張浩、 陳志豪、 遊忍、 澤霖、沈偉臣、 賈紅順、 時超、 陳哲、趙一帆、 胡瀟楊、段希、於衝、張鑫倩
參與編輯人員:黃海廣、陳康凱、石晴路、鍾博彥、向偉、嚴鳳龍、劉成 、賀志堯、段希、陳瑤、林家泳、王翔、 謝士晨、蔣鵬
備註:筆記和作業(含數據、原始作業文件)、視頻都在 github[3]中下載。
我將陸續將課程筆記發佈在公衆號「機器學習初學者」,敬請關注。
大家可能已經瞭解了,那麼本週,我們將繼續學習如何有效運作神經網絡,內容涉及超參數調優,如何構建數據,以及如何確保優化算法快速運行,從而使學習算法在合理時間內完成自我學習。
第一週,我們首先說說神經網絡機器學習中的問題,然後是隨機神經網絡,還會學習一些確保神經網絡正確運行的技巧,帶着這些問題,我們開始今天的課程。
在配置訓練、驗證和測試數據集的過程中做出正確決策會在很大程度上幫助大家創建高效的神經網絡。訓練神經網絡時,我們需要做出很多決策,例如:
神經網絡分多少層
每層含有多少個隱藏單元
學習速率是多少
各層採用哪些激活函數
創建新應用的過程中,我們不可能從一開始就準確預測出這些信息和其他超級參數。實際上,應用型機器學習是一個高度迭代的過程,通常在項目啓動時,我們會先有一個初步想法,比如構建一個含有特定層數,隱藏單元數量或數據集個數等等的神經網絡,然後編碼,並嘗試運行這些代碼,通過運行和測試得到該神經網絡或這些配置信息的運行結果,你可能會根據輸出結果重新完善自己的想法,改變策略,或者爲了找到更好的神經網絡不斷迭代更新自己的方案。
現如今,深度學習已經在自然語言處理,計算機視覺,語音識別以及結構化數據應用等衆多領域取得巨大成功。結構化數據無所不包,從廣告到網絡搜索。其中網絡搜索不僅包括網絡搜索引擎,還包括購物網站,從所有根據搜索欄詞條傳輸結果的網站。再到計算機安全,物流,比如判斷司機去哪接送貨,範圍之廣,不勝枚舉。
我發現,可能有自然語言處理方面的人才想踏足計算機視覺領域,或者經驗豐富的語音識別專家想投身廣告行業,又或者,有的人想從電腦安全領域跳到物流行業,在我看來,從一個領域或者應用領域得來的直覺經驗,通常無法轉移到其他應用領域,最佳決策取決於你所擁有的數據量,計算機配置中輸入特徵的數量,用GPU訓練還是CPU,GPU和CPU的具體配置以及其他諸多因素。
目前爲止,我覺得,對於很多應用系統,即使是經驗豐富的深度學習行家也不太可能一開始就預設出最匹配的超級參數,所以說,應用深度學習是一個典型的迭代過程,需要多次循環往復,才能爲應用程序找到一個稱心的神經網絡,因此循環該過程的效率是決定項目進展速度的一個關鍵因素,而創建高質量的訓練數據集,驗證集和測試集也有助於提高循環效率。
假設這是訓練數據,我用一個長方形表示,我們通常會將這些數據劃分成幾部分,一部分作爲訓練集,一部分作爲簡單交叉驗證集,有時也稱之爲驗證集,方便起見,我就叫它驗證集(dev set),其實都是同一個概念,最後一部分則作爲測試集。
接下來,我們開始對訓練集執行算法,通過驗證集或簡單交叉驗證集選擇最好的模型,經過充分驗證,我們選定了最終模型,然後就可以在測試集上進行評估了,爲了無偏評估算法的運行狀況。
在機器學習發展的小數據量時代,常見做法是將所有數據三七分,就是人們常說的70%訓練集,30%測試集。如果明確設置了驗證集,也可以按照60%訓練集,20%驗證集和20%測試集來劃分。這是前幾年機器學習領域普遍認可的最好的實踐方法。
如果只有100條,1000條或者1萬條數據,那麼上述比例劃分是非常合理的。
但是在大數據時代,我們現在的數據量可能是百萬級別,那麼驗證集和測試集佔數據總量的比例會趨向於變得更小。因爲驗證集的目的就是驗證不同的算法,檢驗哪種算法更有效,因此,驗證集只要足夠大到能評估不同的算法,比如2個甚至10個不同算法,並迅速判斷出哪種算法更有效。我們可能不需要拿出20%的數據作爲驗證集。
比如我們有100萬條數據,那麼取1萬條數據便足以進行評估,找出其中表現最好的1-2種算法。同樣地,根據最終選擇的分類器,測試集的主要目的是正確評估分類器的性能,所以,如果擁有百萬數據,我們只需要1000條數據,便足以評估單個分類器,並且準確評估該分類器的性能。假設我們有100萬條數據,其中1萬條作爲驗證集,1萬條作爲測試集,100萬里取1萬,比例是1%,即:訓練集佔98%,驗證集和測試集各佔1%。對於數據量過百萬的應用,訓練集可以佔到99.5%,驗證和測試集各佔0.25%,或者驗證集佔0.4%,測試集佔0.1%。
總結一下,在機器學習中,我們通常將樣本分成訓練集,驗證集和測試集三部分,數據集規模相對較小,適用傳統的劃分比例,數據集規模較大的,驗證集和測試集要小於數據總量的20%或10%。後面我會給出如何劃分驗證集和測試集的具體指導。
現代深度學習的另一個趨勢是越來越多的人在訓練和測試集分佈不匹配的情況下進行訓練,假設你要構建一個用戶可以上傳大量圖片的應用程序,目的是找出並呈現所有貓咪圖片,可能你的用戶都是愛貓人士,訓練集可能是從網上下載的貓咪圖片,而驗證集和測試集是用戶在這個應用上上傳的貓的圖片,就是說,訓練集可能是從網絡上抓下來的圖片。而驗證集和測試集是用戶上傳的圖片。結果許多網頁上的貓咪圖片分辨率很高,很專業,後期製作精良,而用戶上傳的照片可能是用手機隨意拍攝的,像素低,比較模糊,這兩類數據有所不同,針對這種情況,根據經驗,我建議大家要確保驗證集和測試集的數據來自同一分佈,關於這個問題我也會多講一些。因爲你們要用驗證集來評估不同的模型,儘可能地優化性能。如果驗證集和測試集來自同一個分佈就會很好。
但由於深度學習算法需要大量的訓練數據,爲了獲取更大規模的訓練數據集,我們可以採用當前流行的各種創意策略,例如,網頁抓取,代價就是訓練集數據與驗證集和測試集數據有可能不是來自同一分佈。但只要遵循這個經驗法則,你就會發現機器學習算法會變得更快。我會在後面的課程中更加詳細地解釋這條經驗法則。
最後一點,就算沒有測試集也不要緊,測試集的目的是對最終所選定的神經網絡系統做出無偏估計,如果不需要無偏估計,也可以不設置測試集。所以如果只有驗證集,沒有測試集,我們要做的就是,在訓練集上訓練,嘗試不同的模型框架,在驗證集上評估這些模型,然後迭代並選出適用的模型。因爲驗證集中已經涵蓋測試集數據,其不再提供無偏性能評估。當然,如果你不需要無偏估計,那就再好不過了。
在機器學習中,如果只有一個訓練集和一個驗證集,而沒有獨立的測試集,遇到這種情況,訓練集還被人們稱爲訓練集,而驗證集則被稱爲測試集,不過在實際應用中,人們只是把測試集當成簡單交叉驗證集使用,並沒有完全實現該術語的功能,因爲他們把驗證集數據過度擬合到了測試集中。如果某團隊跟你說他們只設置了一個訓練集和一個測試集,我會很謹慎,心想他們是不是真的有訓練驗證集,因爲他們把驗證集數據過度擬合到了測試集中,讓這些團隊改變叫法,改稱其爲「訓練驗證集」,而不是「訓練測試集」,可能不太容易。即便我認爲「訓練驗證集「在專業用詞上更準確。實際上,如果你不需要無偏評估算法性能,那麼這樣是可以的。
所以說,搭建訓練驗證集和測試集能夠加速神經網絡的集成,也可以更有效地衡量算法地偏差和方差,從而幫助我們更高效地選擇合適方法來優化算法。
我注意到,幾乎所有機器學習從業人員都期望深刻理解偏差和方差,這兩個概念易學難精,即使你自己認爲已經理解了偏差和方差的基本概念,卻總有一些意想不到的新東西出現。關於深度學習的誤差問題,另一個趨勢是對偏差和方差的權衡研究甚淺,你可能聽說過這兩個概念,但深度學習的誤差很少權衡二者,我們總是分別考慮偏差和方差,卻很少談及偏差和方差的權衡問題,下面我們來一探究竟。
假設這就是數據集,如果給這個數據集擬合一條直線,可能得到一個邏輯迴歸擬合,但它並不能很好地擬合該數據,這是高偏差(high bias)的情況,我們稱爲「欠擬合」(underfitting)。
相反的如果我們擬合一個非常複雜的分類器,比如深度神經網絡或含有隱藏單元的神經網絡,可能就非常適用於這個數據集,但是這看起來也不是一種很好的擬合方式分類器方差較高(high variance),數據過度擬合(overfitting)。
在兩者之間,可能還有一些像圖中這樣的,複雜程度適中,數據擬合適度的分類器,這個數據擬合看起來更加合理,我們稱之爲「適度擬合」(just right)是介於過度擬合和欠擬閤中間的一類。
在這樣一個只有 和 兩個特徵的二維數據集中,我們可以繪製數據,將偏差和方差可視化。在多維空間數據中,繪製數據和可視化分割邊界無法實現,但我們可以通過幾個指標,來研究偏差和方差。
我們沿用貓咪圖片分類這個例子,左邊一張是貓咪圖片,右邊一張不是。理解偏差和方差的兩個關鍵數據是訓練集誤差(Train set error)和驗證集誤差(Dev set error),爲了方便論證,假設我們可以辨別圖片中的小貓,我們用肉眼識別幾乎是不會出錯的。
假定訓練集誤差是1%,爲了方便論證,假定驗證集誤差是11%,可以看出訓練集設置得非常好,而驗證集設置相對較差,我們可能過度擬合了訓練集,在某種程度上,驗證集並沒有充分利用交叉驗證集的作用,像這種情況,我們稱之爲「高方差」。
通過查看訓練集誤差和驗證集誤差,我們便可以診斷算法是否具有高方差。也就是說衡量訓練集和驗證集誤差就可以得出不同結論。
假設訓練集誤差是15%,我們把訓練集誤差寫在首行,驗證集誤差是16%,假設該案例中人的錯誤率幾乎爲0%,人們瀏覽這些圖片,分辨出是不是貓。算法並沒有在訓練集中得到很好訓練,如果訓練數據的擬合度不高,就是數據欠擬合,就可以說這種算法偏差比較高。相反,它對於驗證集產生的結果卻是合理的,驗證集中的錯誤率只比訓練集的多了1%,所以這種算法偏差高,因爲它甚至不能擬合訓練集,這與上一張幻燈片最左邊的圖片相似。
再舉一個例子,訓練集誤差是15%,偏差相當高,但是,驗證集的評估結果更糟糕,錯誤率達到30%,在這種情況下,我會認爲這種算法偏差高,因爲它在訓練集上結果不理想,而且方差也很高,這是方差偏差都很糟糕的情況。
再看最後一個例子,訓練集誤差是0.5%,驗證集誤差是1%,用戶看到這樣的結果會很開心,貓咪分類器只有1%的錯誤率,偏差和方差都很低。
有一點我先在這個簡單提一下,具體的留在後面課程裏講,這些分析都是基於假設預測的,假設人眼辨別的錯誤率接近0%,一般來說,最優誤差也被稱爲貝葉斯誤差,所以,最優誤差接近0%,我就不在這裏細講了,如果最優誤差或貝葉斯誤差非常高,比如15%。我們再看看這個分類器(訓練誤差15%,驗證誤差16%),15%的錯誤率對訓練集來說也是非常合理的,偏差不高,方差也非常低。
當所有分類器都不適用時,如何分析偏差和方差呢?比如,圖片很模糊,即使是人眼,或者沒有系統可以準確無誤地識別圖片,在這種情況下,最優誤差會更高,那麼分析過程就要做些改變了,我們暫時先不討論這些細微差別,重點是通過查看訓練集誤差,我們可以判斷數據擬合情況,至少對於訓練數據是這樣,可以判斷是否有偏差問題,然後查看錯誤率有多高。當完成訓練集訓練,開始使用驗證集驗證時,我們可以判斷方差是否過高,從訓練集到驗證集的這個過程中,我們可以判斷方差是否過高。
以上分析的前提都是假設基本誤差很小,訓練集和驗證集數據來自相同分佈,如果沒有這些假設作爲前提,分析過程更加複雜,我們將會在稍後課程裏討論。
上一張幻燈片,我們講了高偏差和高方差的情況,大家應該對優質分類器有了一定的認識,偏差和方差都高是什麼樣子呢?這種情況對於兩個衡量標準來說都是非常糟糕的。
我們之前講過,這樣的分類器,會產生高偏差,因爲它的數據擬合度低,像這種接近線性的分類器,數據擬合度低。
但是如果我們稍微改變一下分類器,我用紫色筆畫出,它會過度擬合部分數據,用紫色線畫出的分類器具有高偏差和高方差,偏差高是因爲它幾乎是一條線性分類器,並未擬合數據。
這種二次曲線能夠很好地擬合數據。
這條曲線中間部分靈活性非常高,卻過度擬合了這兩個樣本,這類分類器偏差很高,因爲它幾乎是線性的。
而採用曲線函數或二次元函數會產生高方差,因爲它曲線靈活性太高以致擬合了這兩個錯誤樣本和中間這些活躍數據。
這看起來有些不自然,從兩個維度上看都不太自然,但對於高維數據,有些數據區域偏差高,有些數據區域方差高,所以在高維數據中採用這種分類器看起來就不會那麼牽強了。
總結一下,我們講了如何通過分析在訓練集上訓練算法產生的誤差和驗證集上驗證算法產生的誤差來診斷算法是否存在高偏差和高方差,是否兩個值都高,或者兩個值都不高,根據算法偏差和方差的具體情況決定接下來你要做的工作,下節課,我會根據算法偏差和方差的高低情況講解一些機器學習的基本方法,幫助大家更系統地優化算法,我們下節課見。
上節課我們講的是如何通過訓練誤差和驗證集誤差判斷算法偏差或方差是否偏高,幫助我們更加系統地在機器學習中運用這些方法來優化算法性能。
下圖就是我在訓練神經網絡用到的基本方法:(嘗試這些方法,可能有用,可能沒用)
這是我在訓練神經網絡時用到的基本方法,初始模型訓練完成後,我首先要知道算法的偏差高不高,如果偏差較高,試着評估訓練集或訓練數據的性能。如果偏差的確很高,甚至無法擬合訓練集,那麼你要做的就是選擇一個新的網絡,比如含有更多隱藏層或者隱藏單元的網絡,或者花費更多時間來訓練網絡,或者嘗試更先進的優化算法,後面我們會講到這部分內容。你也可以嘗試其他方法,可能有用,也可能沒用。
一會兒我們會看到許多不同的神經網絡架構,或許你能找到一個更合適解決此問題的新的網絡架構,加上括號,因爲其中一條就是你必須去嘗試,可能有用,也可能沒用,不過採用規模更大的網絡通常都會有所幫助,延長訓練時間不一定有用,但也沒什麼壞處。訓練學習算法時,我會不斷嘗試這些方法,直到解決掉偏差問題,這是最低標準,反覆嘗試,直到可以擬合數據爲止,至少能夠擬合訓練集。
如果網絡足夠大,通常可以很好的擬合訓練集,只要你能擴大網絡規模,如果圖片很模糊,算法可能無法擬合該圖片,但如果有人可以分辨出圖片,如果你覺得基本誤差不是很高,那麼訓練一個更大的網絡,你就應該可以……至少可以很好地擬合訓練集,至少可以擬合或者過擬合訓練集。一旦偏差降低到可以接受的數值,檢查一下方差有沒有問題,爲了評估方差,我們要查看驗證集性能,我們能從一個性能理想的訓練集推斷出驗證集的性能是否也理想,如果方差高,最好的解決辦法就是採用更多數據,如果你能做到,會有一定的幫助,但有時候,我們無法獲得更多數據,我們也可以嘗試通過正則化來減少過擬合,這個我們下節課會講。有時候我們不得不反覆嘗試,但是,如果能找到更合適的神經網絡框架,有時它可能會一箭雙鵰,同時減少方差和偏差。如何實現呢?想系統地說出做法很難,總之就是不斷重複嘗試,直到找到一個低偏差,低方差的框架,這時你就成功了。
有兩點需要大家注意:
第一點,高偏差和高方差是兩種不同的情況,我們後續要嘗試的方法也可能完全不同,我通常會用訓練驗證集來診斷算法是否存在偏差或方差問題,然後根據結果選擇嘗試部分方法。舉個例子,如果算法存在高偏差問題,準備更多訓練數據其實也沒什麼用處,至少這不是更有效的方法,所以大家要清楚存在的問題是偏差還是方差,還是兩者都有問題,明確這一點有助於我們選擇出最有效的方法。
第二點,在機器學習的初期階段,關於所謂的偏差方差權衡的討論屢見不鮮,原因是我們能嘗試的方法有很多。可以增加偏差,減少方差,也可以減少偏差,增加方差,但是在深度學習的早期階段,我們沒有太多工具可以做到只減少偏差或方差卻不影響到另一方。但在當前的深度學習和大數據時代,只要持續訓練一個更大的網絡,只要準備了更多數據,那麼也並非只有這兩種情況,我們假定是這樣,那麼,只要正則適度,通常構建一個更大的網絡便可以,在不影響方差的同時減少偏差,而採用更多數據通常可以在不過多影響偏差的同時減少方差。這兩步實際要做的工作是:訓練網絡,選擇網絡或者準備更多數據,現在我們有工具可以做到在減少偏差或方差的同時,不對另一方產生過多不良影響。我覺得這就是深度學習對監督式學習大有裨益的一個重要原因,也是我們不用太過關注如何平衡偏差和方差的一個重要原因,但有時我們有很多選擇,減少偏差或方差而不增加另一方。最終,我們會得到一個非常規範化的網絡。從下節課開始,我們將講解正則化,訓練一個更大的網絡幾乎沒有任何負面影響,而訓練一個大型神經網絡的主要代價也只是計算時間,前提是網絡是比較規範化的。
今天我們講了如何通過組織機器學習來診斷偏差和方差的基本方法,然後選擇解決問題的正確操作,希望大家有所瞭解和認識。我在課上不止一次提到了正則化,它是一種非常實用的減少方差的方法,正則化時會出現偏差方差權衡問題,偏差可能略有增加,如果網絡足夠大,增幅通常不會太高,我們下節課再細講,以便大家更好理解如何實現神經網絡的正則化。
深度學習可能存在過擬合問題——高方差,有兩個解決方法,一個是正則化,另一個是準備更多的數據,這是非常可靠的方法,但你可能無法時時刻刻準備足夠多的訓練數據或者獲取更多數據的成本很高,但正則化通常有助於避免過擬合或減少你的網絡誤差。
如果你懷疑神經網絡過度擬合了數據,即存在高方差問題,那麼最先想到的方法可能是正則化,另一個解決高方差的方法就是準備更多數據,這也是非常可靠的辦法,但你可能無法時時準備足夠多的訓練數據,或者,獲取更多數據的成本很高,但正則化有助於避免過度擬合,或者減少網絡誤差,下面我們就來講講正則化的作用原理。
我們用邏輯迴歸來實現這些設想,求成本函數 的最小值,它是我們定義的成本函數,參數包含一些訓練數據和不同數據中個體預測的損失, 和 是邏輯迴歸的兩個參數, 是一個多維度參數矢量, 是一個實數。在邏輯迴歸函數中加入正則化,只需添加參數λ,也就是正則化參數,一會兒再詳細講。
乘以 範數的平方,其中 是 的歐幾里德範數的平方,等於 ( 值從1到 )平方的和,也可表示爲 ,也就是向量參數 的歐幾里德範數(2範數)的平方,此方法稱爲 正則化,因爲這裏用了歐幾里德範數,被稱爲向量參數 的 範數。
爲什麼只正則化參數 ?爲什麼不再加上參數 呢?你可以這麼做,只是我習慣省略不寫,因爲 通常是一個高維參數矢量,已經可以表達高偏差問題, 可能包含有很多參數,我們不可能擬合所有參數,而 只是單個數字,所以 幾乎涵蓋所有參數,而不是 ,如果加了參數 ,其實也沒太大影響,因爲 只是衆多參數中的一個,所以我通常省略不計,如果你想加上這個參數,完全沒問題。
正則化是最常見的正則化類型,你們可能聽說過 正則化, 正則化,加的不是 範數,而是正則項 乘以 , 也被稱爲參數 向量的 範數,無論分母是 還是 ,它都是一個比例常量。
如果用的是 正則化, 最終會是稀疏的,也就是說 向量中有很多0,有人說這樣有利於壓縮模型,因爲集合中參數均爲0,存儲模型所佔用的內存更少。實際上,雖然 正則化使模型變得稀疏,卻沒有降低太多存儲內存,所以我認爲這並不是 正則化的目的,至少不是爲了壓縮模型,人們在訓練網絡時,越來越傾向於使用 正則化。
我們來看最後一個細節, 是正則化參數,我們通常使用驗證集或交叉驗證集來配置這個參數,嘗試各種各樣的數據,尋找最好的參數,我們要考慮訓練集之間的權衡,把參數設置爲較小值,這樣可以避免過擬合,所以λ是另外一個需要調整的超級參數,順便說一下,爲了方便寫代碼,在Python編程語言中, 是一個保留字段,編寫代碼時,我們刪掉 ,寫成 ,以免與Python中的保留字段衝突,這就是在邏輯迴歸函數中實現 正則化的過程,如何在神經網絡中實現 正則化呢?
神經網絡含有一個成本函數,該函數包含 , 到 , 所有參數,字母 是神經網絡所含的層數,因此成本函數等於 個訓練樣本損失函數的總和乘以 ,正則項爲 ,我們稱 爲範數平方,這個矩陣範數 (即平方範數),被定義爲矩陣中所有元素的平方求和,
我們看下求和公式的具體參數,第一個求和符號其值 從1到 ,第二個其 值從1到 ,因爲 是一個 的多維矩陣, 表示 層單元的數量, 表示第 層隱藏單元的數量。
該矩陣範數被稱作「弗羅貝尼烏斯範數」,用下標 標註」,鑑於線性代數中一些神祕晦澀的原因,我們不稱之爲「矩陣 範數」,而稱它爲「弗羅貝尼烏斯範數」,矩陣 範數聽起來更自然,但鑑於一些大家無須知道的特殊原因,按照慣例,我們稱之爲「弗羅貝尼烏斯範數」,它表示一個矩陣中所有元素的平方和。
該如何使用該範數實現梯度下降呢?
用backprop計算出 的值,backprop會給出 對 的偏導數,實際上是 ,把 替換爲 減去學習率乘以 。
這就是之前我們額外增加的正則化項,既然已經增加了這個正則項,現在我們要做的就是給 加上這一項 ,然後計算這個更新項,使用新定義的 ,它的定義含有相關參數代價函數導數和,以及最後添加的額外正則項,這也是 正則化有時被稱爲「權重衰減」的原因。
我們用 的定義替換此處的 ,可以看到, 的定義被更新爲 減去學習率 乘以backprop 再加上 。
該正則項說明,不論 是什麼,我們都試圖讓它變得更小,實際上,相當於我們給矩陣W乘以 倍的權重,矩陣 減去 倍的它,也就是用這個係數 乘以矩陣 ,該係數小於1,因此 範數正則化也被稱爲「權重衰減」,因爲它就像一般的梯度下降, 被更新爲少了 乘以backprop輸出的最初梯度值,同時 也乘以了這個係數,這個係數小於1,因此 正則化也被稱爲「權重衰減」。
我不打算這麼叫它,之所以叫它「權重衰減」是因爲這兩項相等,權重指標乘以了一個小於1的係數。
以上就是在神經網絡中應用 正則化的過程,有人會問我,爲什麼正則化可以預防過擬合,我們放在下節課講,同時直觀感受一下正則化是如何預防過擬合的。
爲什麼正則化有利於預防過擬合呢?爲什麼它可以減少方差問題?我們通過兩個例子來直觀體會一下。
左圖是高偏差,右圖是高方差,中間是Just Right,這幾張圖我們在前面課程中看到過。
現在我們來看下這個龐大的深度擬合神經網絡。我知道這張圖不夠大,深度也不夠,但你可以想象這是一個過擬合的神經網絡。這是我們的代價函數 ,含有參數 , 。我們添加正則項,它可以避免數據權值矩陣過大,這就是弗羅貝尼烏斯範數,爲什麼壓縮 範數,或者弗羅貝尼烏斯範數或者參數可以減少過擬合?
直觀上理解就是如果正則化 設置得足夠大,權重矩陣 被設置爲接近於0的值,直觀理解就是把多隱藏單元的權重設爲0,於是基本上消除了這些隱藏單元的許多影響。如果是這種情況,這個被大大簡化了的神經網絡會變成一個很小的網絡,小到如同一個邏輯迴歸單元,可是深度卻很大,它會使這個網絡從過度擬合的狀態更接近左圖的高偏差狀態。
但是 會存在一箇中間值,於是會有一個接近「Just Right」的中間狀態。
直觀理解就是 增加到足夠大, 會接近於0,實際上是不會發生這種情況的,我們嘗試消除或至少減少許多隱藏單元的影響,最終這個網絡會變得更簡單,這個神經網絡越來越接近邏輯迴歸,我們直覺上認爲大量隱藏單元被完全消除了,其實不然,實際上是該神經網絡的所有隱藏單元依然存在,但是它們的影響變得更小了。神經網絡變得更簡單了,貌似這樣更不容易發生過擬合,因此我不確定這個直覺經驗是否有用,不過在編程中執行正則化時,你實際看到一些方差減少的結果。
我們再來直觀感受一下,正則化爲什麼可以預防過擬合,假設我們用的是這樣的雙曲線激活函數。
用 表示 ,我們發現如果 z 非常小,比如 z 只涉及很小範圍的參數(圖中原點附近的紅色區域),這裏我們利用了雙曲正切函數的線性狀態,只要 可以擴展爲這樣的更大值或者更小值,激活函數開始變得非線性。
現在你應該摒棄這個直覺,如果正則化參數λ很大,激活函數的參數會相對較小,因爲代價函數中的參數變大了,如果 很小,
如果 很小,相對來說, 也會很小。
特別是,如果 的值最終在這個範圍內,都是相對較小的值, 大致呈線性,每層幾乎都是線性的,和線性迴歸函數一樣。
第一節課我們講過,如果每層都是線性的,那麼整個網絡就是一個線性網絡,即使是一個非常深的深層網絡,因具有線性激活函數的特徵,最終我們只能計算線性函數,因此,它不適用於非常複雜的決策,以及過度擬合數據集的非線性決策邊界,如同我們在幻燈片中看到的過度擬合高方差的情況。
總結一下,如果正則化參數變得很大,參數 很小, 也會相對變小,此時忽略 的影響, 會相對變小,實際上, 的取值範圍很小,這個激活函數,也就是曲線函數 會相對呈線性,整個神經網絡會計算離線性函數近的值,這個線性函數非常簡單,並不是一個極複雜的高度非線性函數,不會發生過擬合。
大家在編程作業裏實現正則化的時候,會親眼看到這些結果,總結正則化之前,我給大家一個執行方面的小建議,在增加正則化項時,應用之前定義的代價函數 ,我們做過修改,增加了一項,目的是預防權重過大。
如果你使用的是梯度下降函數,在調試梯度下降時,其中一步就是把代價函數 設計成這樣一個函數,在調試梯度下降時,它代表梯度下降的調幅數量。可以看到,代價函數對於梯度下降的每個調幅都單調遞減。如果你實施的是正則化函數,請牢記, 已經有一個全新的定義。如果你用的是原函數 ,也就是這第一個項正則化項,你可能看不到單調遞減現象,爲了調試梯度下降,請務必使用新定義的 函數,它包含第二個正則化項,否則函數 可能不會在所有調幅範圍內都單調遞減。
這就是 正則化,它是我在訓練深度學習模型時最常用的一種方法。在深度學習中,還有一種方法也用到了正則化,就是dropout正則化,我們下節課再講。
除了 正則化,還有一個非常實用的正則化方法——「Dropout(隨機失活)」,我們來看看它的工作原理。
假設你在訓練上圖這樣的神經網絡,它存在過擬合,這就是dropout所要處理的,我們複製這個神經網絡,dropout會遍歷網絡的每一層,並設置消除神經網絡中節點的概率。假設網絡中的每一層,每個節點都以拋硬幣的方式設置概率,每個節點得以保留和消除的概率都是0.5,設置完節點概率,我們會消除一些節點,然後刪除掉從該節點進出的連線,最後得到一個節點更少,規模更小的網絡,然後用backprop方法進行訓練。
這是網絡節點精簡後的一個樣本,對於其它樣本,我們照舊以拋硬幣的方式設置概率,保留一類節點集合,刪除其它類型的節點集合。對於每個訓練樣本,我們都將採用一個精簡後神經網絡來訓練它,這種方法似乎有點怪,單純遍歷節點,編碼也是隨機的,可它真的有效。不過可想而知,我們針對每個訓練樣本訓練規模小得多的網絡,最後你可能會認識到爲什麼要正則化網絡,因爲我們在訓練規模小得多的網絡。
如何實施dropout呢?方法有幾種,接下來我要講的是最常用的方法,即inverted dropout(反向隨機失活),出於完整性考慮,我們用一個三層( )網絡來舉例說明。編碼中會有很多涉及到3的地方。我只舉例說明如何在某一層中實施dropout。
首先要定義向量 , 表示網絡第三層的dropout向量:
d3 = np.random.rand(a3.shape[0],a3.shape[1])
然後看它是否小於某數,我們稱之爲keep-prob,keep-prob是一個具體數字,上個示例中它是0.5,而本例中它是0.8,它表示保留某個隱藏單元的概率,此處keep-prob等於0.8,它意味着消除任意一個隱藏單元的概率是0.2,它的作用就是生成隨機矩陣,如果對 進行因子分解,效果也是一樣的。 是一個矩陣,每個樣本和每個隱藏單元,其中 中的對應值爲1的概率都是0.8,對應爲0的概率是0.2,隨機數字小於0.8。它等於1的概率是0.8,等於0的概率是0.2。
接下來要做的就是從第三層中獲取激活函數,這裏我們叫它
,
含有要計算的激活函數,
等於上面的
乘以
,a3 =np.multiply(a3,d3)
,這裏是元素相乘,也可寫爲
,它的作用就是讓
中所有等於0的元素(輸出),而各個元素等於0的概率只有20%,乘法運算最終把
中相應元素輸出,即讓
中0元素與
中相對元素歸零。
如果用python實現該算法的話, 則是一個布爾型數組,值爲true和false,而不是1和0,乘法運算依然有效,python會把true和false翻譯爲1和0,大家可以用python嘗試一下。
最後,我們向外擴展 ,用它除以0.8,或者除以keep-prob參數。
下面我解釋一下爲什麼要這麼做,爲方便起見,我們假設第三隱藏層上有50個單元或50個神經元,在一維上 是50,我們通過因子分解將它拆分成 維的,保留和刪除它們的概率分別爲80%和20%,這意味着最後被刪除或歸零的單元平均有10(50×20%=10)個,現在我們看下 , ,我們的預期是, 減少20%,也就是說 中有20%的元素被歸零,爲了不影響 的期望值,我們需要用 ,它將會修正或彌補我們所需的那20%, 的期望值不會變,劃線部分就是所謂的dropout方法。
它的功能是,不論keep-prop的值是多少0.8,0.9甚至是1,如果keep-prop設置爲1,那麼就不存在dropout,因爲它會保留所有節點。反向隨機失活(inverted dropout)方法通過除以keep-prob,確保 的期望值不變。
事實證明,在測試階段,當我們評估一個神經網絡時,也就是用綠線框標註的反向隨機失活方法,使測試階段變得更容易,因爲它的數據擴展問題變少,我們將在下節課討論。
據我瞭解,目前實施dropout最常用的方法就是Inverted dropout,建議大家動手實踐一下。Dropout早期的迭代版本都沒有除以keep-prob,所以在測試階段,平均值會變得越來越複雜,不過那些版本已經不再使用了。
現在你使用的是 向量,你會發現,不同的訓練樣本,清除不同的隱藏單元也不同。實際上,如果你通過相同訓練集多次傳遞數據,每次訓練數據的梯度不同,則隨機對不同隱藏單元歸零,有時卻並非如此。比如,需要將相同隱藏單元歸零,第一次迭代梯度下降時,把一些隱藏單元歸零,第二次迭代梯度下降時,也就是第二次遍歷訓練集時,對不同類型的隱藏層單元歸零。向量 或 用來決定第三層中哪些單元歸零,無論用foreprop還是backprop,這裏我們只介紹了foreprob。
如何在測試階段訓練算法,在測試階段,我們已經給出了 ,或是想預測的變量,用的是標準計數法。我用 ,第0層的激活函數標註爲測試樣本 ,我們在測試階段不使用dropout函數,尤其是像下列情況:
以此類推直到最後一層,預測值爲 。
顯然在測試階段,我們並未使用dropout,自然也就不用拋硬幣來決定失活概率,以及要消除哪些隱藏單元了,因爲在測試階段進行預測時,我們不期望輸出結果是隨機的,如果測試階段應用dropout函數,預測會受到干擾。理論上,你只需要多次運行預測處理過程,每一次,不同的隱藏單元會被隨機歸零,預測處理遍歷它們,但計算效率低,得出的結果也幾乎相同,與這個不同程序產生的結果極爲相似。
Inverted dropout函數在除以keep-prob時可以記住上一步的操作,目的是確保即使在測試階段不執行dropout來調整數值範圍,激活函數的預期結果也不會發生變化,所以沒必要在測試階段額外添加尺度參數,這與訓練階段不同。
這就是dropout,大家可以通過本週的編程練習來執行這個函數,親身實踐一下。
爲什麼dropout會起作用呢?下節課我們將更加直觀地瞭解dropout的具體功能。
Dropout可以隨機刪除網絡中的神經單元,他爲什麼可以通過正則化發揮如此大的作用呢?
直觀上理解:不要依賴於任何一個特徵,因爲該單元的輸入可能隨時被清除,因此該單元通過這種方式傳播下去,併爲單元的四個輸入增加一點權重,通過傳播所有權重,dropout將產生收縮權重的平方範數的效果,和之前講的 正則化類似;實施dropout的結果實它會壓縮權重,並完成一些預防過擬合的外層正則化; 對不同權重的衰減是不同的,它取決於激活函數倍增的大小。
總結一下,dropout的功能類似於 正則化,與 正則化不同的是應用方式不同會帶來一點點小變化,甚至更適用於不同的輸入範圍。
第二個直觀認識是,我們從單個神經元入手,如圖,這個單元的工作就是輸入並生成一些有意義的輸出。通過dropout,該單元的輸入幾乎被消除,有時這兩個單元會被刪除,有時會刪除其它單元,就是說,我用紫色圈起來的這個單元,它不能依靠任何特徵,因爲特徵都有可能被隨機清除,或者說該單元的輸入也都可能被隨機清除。我不願意把所有賭注都放在一個節點上,不願意給任何一個輸入加上太多權重,因爲它可能會被刪除,因此該單元將通過這種方式積極地傳播開,併爲單元的四個輸入增加一點權重,通過傳播所有權重,dropout將產生收縮權重的平方範數的效果,和我們之前講過的 正則化類似,實施dropout的結果是它會壓縮權重,並完成一些預防過擬合的外層正則化。
事實證明,dropout被正式地作爲一種正則化的替代形式, 對不同權重的衰減是不同的,它取決於倍增的激活函數的大小。
總結一下,dropout的功能類似於 正則化,與 正則化不同的是,被應用的方式不同,dropout也會有所不同,甚至更適用於不同的輸入範圍。
實施dropout的另一個細節是,這是一個擁有三個輸入特徵的網絡,其中一個要選擇的參數是keep-prob,它代表每一層上保留單元的概率。所以不同層的keep-prob也可以變化。第一層,矩陣 是7×3,第二個權重矩陣 是7×7,第三個權重矩陣 是3×7,以此類推, 是最大的權重矩陣,因爲 擁有最大參數集,即7×7,爲了預防矩陣的過擬合,對於這一層,我認爲這是第二層,它的keep-prob值應該相對較低,假設是0.5。對於其它層,過擬合的程度可能沒那麼嚴重,它們的keep-prob值可能高一些,可能是0.7,這裏是0.7。如果在某一層,我們不必擔心其過擬合的問題,那麼keep-prob可以爲1,爲了表達清除,我用紫色線筆把它們圈出來,每層keep-prob的值可能不同。
注意keep-prob的值是1,意味着保留所有單元,並且不在這一層使用dropout,對於有可能出現過擬合,且含有諸多參數的層,我們可以把keep-prob設置成比較小的值,以便應用更強大的dropout,有點像在處理 正則化的正則化參數 ,我們嘗試對某些層施行更多正則化,從技術上講,我們也可以對輸入層應用dropout,我們有機會刪除一個或多個輸入特徵,雖然現實中我們通常不這麼做,keep-prob的值爲1,是非常常用的輸入值,也可以用更大的值,或許是0.9。但是消除一半的輸入特徵是不太可能的,如果我們遵守這個準則,keep-prob會接近於1,即使你對輸入層應用dropout。
總結一下,如果你擔心某些層比其它層更容易發生過擬合,可以把某些層的keep-prob值設置得比其它層更低,缺點是爲了使用交叉驗證,你要搜索更多的超級參數,另一種方案是在一些層上應用dropout,而有些層不用dropout,應用dropout的層只含有一個超級參數,就是keep-prob。
結束前分享兩個實施過程中的技巧,實施dropout,在計算機視覺領域有很多成功的第一次。計算視覺中的輸入量非常大,輸入太多像素,以至於沒有足夠的數據,所以dropout在計算機視覺中應用得比較頻繁,有些計算機視覺研究人員非常喜歡用它,幾乎成了默認的選擇,但要牢記一點,dropout是一種正則化方法,它有助於預防過擬合,因此除非算法過擬合,不然我是不會使用dropout的,所以它在其它領域應用得比較少,主要存在於計算機視覺領域,因爲我們通常沒有足夠的數據,所以一直存在過擬合,這就是有些計算機視覺研究人員如此鍾情於dropout函數的原因。直觀上我認爲不能概括其它學科。
dropout一大缺點就是代價函數 不再被明確定義,每次迭代,都會隨機移除一些節點,如果再三檢查梯度下降的性能,實際上是很難進行復查的。定義明確的代價函數 每次迭代後都會下降,因爲我們所優化的代價函數 實際上並沒有明確定義,或者說在某種程度上很難計算,所以我們失去了調試工具來繪製這樣的圖片。我通常會關閉dropout函數,將keep-prob的值設爲1,運行代碼,確保J函數單調遞減。然後打開dropout函數,希望在dropout過程中,代碼並未引入bug。我覺得你也可以嘗試其它方法,雖然我們並沒有關於這些方法性能的數據統計,但你可以把它們與dropout方法一起使用。
除了 正則化和隨機失活(dropout)正則化,還有幾種方法可以減少神經網絡中的過擬合:
一.數據擴增(數據增強)
假設你正在擬合貓咪圖片分類器,如果你想通過擴增訓練數據來解決過擬合,但擴增數據代價高,而且有時候我們無法擴增數據,但我們可以通過添加這類圖片來增加訓練集。例如,水平翻轉圖片,並把它添加到訓練集。所以現在訓練集中有原圖,還有翻轉後的這張圖片,所以通過水平翻轉圖片,訓練集則可以增大一倍,因爲訓練集有冗餘,這雖然不如我們額外收集一組新圖片那麼好,但這樣做節省了獲取更多貓咪圖片的花費。
除了水平翻轉圖片,你也可以隨意裁剪圖片,這張圖是把原圖旋轉並隨意放大後裁剪的,仍能辨別出圖片中的貓咪。
通過隨意翻轉和裁剪圖片,我們可以增大數據集,額外生成假訓練數據。和全新的,獨立的貓咪圖片數據相比,這些額外的假的數據無法包含像全新數據那麼多的信息,但我們這麼做基本沒有花費,代價幾乎爲零,除了一些對抗性代價。以這種方式擴增算法數據,進而正則化數據集,減少過擬合比較廉價。
像這樣人工合成數據的話,我們要通過算法驗證,圖片中的貓經過水平翻轉之後依然是貓。大家注意,我並沒有垂直翻轉,因爲我們不想上下顛倒圖片,也可以隨機選取放大後的部分圖片,貓可能還在上面。
對於光學字符識別,我們還可以通過添加數字,隨意旋轉或扭曲數字來擴增數據,把這些數字添加到訓練集,它們仍然是數字。爲了方便說明,我對字符做了強變形處理,所以數字4看起來是波形的,其實不用對數字4做這麼誇張的扭曲,只要輕微的變形就好,我做成這樣是爲了讓大家看的更清楚。實際操作的時候,我們通常對字符做更輕微的變形處理。因爲這幾個4看起來有點扭曲。所以,數據擴增可作爲正則化方法使用,實際功能上也與正則化相似。
二.early stopping
還有另外一種常用的方法叫作early stopping,運行梯度下降時,我們可以繪製訓練誤差,或只繪製代價函數 的優化過程,在訓練集上用0-1記錄分類誤差次數。呈單調下降趨勢,如圖。
因爲在訓練過程中,我們希望訓練誤差,代價函數 都在下降,通過early stopping,我們不但可以繪製上面這些內容,還可以繪製驗證集誤差,它可以是驗證集上的分類誤差,或驗證集上的代價函數,邏輯損失和對數損失等,你會發現,驗證集誤差通常會先呈下降趨勢,然後在某個節點處開始上升,early stopping的作用是,你會說,神經網絡已經在這個迭代過程中表現得很好了,我們在此停止訓練吧,得到驗證集誤差,它是怎麼發揮作用的?
當你還未在神經網絡上運行太多迭代過程的時候,參數 接近0,因爲隨機初始化 值時,它的值可能都是較小的隨機值,所以在你長期訓練神經網絡之前 依然很小,在迭代過程和訓練過程中 的值會變得越來越大,比如在這兒,神經網絡中參數 的值已經非常大了,所以early stopping要做就是在中間點停止迭代過程,我們得到一個 值中等大小的弗羅貝尼烏斯範數,與 正則化相似,選擇參數w範數較小的神經網絡,但願你的神經網絡過度擬合不嚴重。
術語early stopping代表提早停止訓練神經網絡,訓練神經網絡時,我有時會用到early stopping,但是它也有一個缺點,我們來了解一下。
我認爲機器學習過程包括幾個步驟,其中一步是選擇一個算法來優化代價函數 ,我們有很多種工具來解決這個問題,如梯度下降,後面我會介紹其它算法,例如Momentum,RMSprop和Adam等等,但是優化代價函數 之後,我也不想發生過擬合,也有一些工具可以解決該問題,比如正則化,擴增數據等等。
在機器學習中,超級參數激增,選出可行的算法也變得越來越複雜。我發現,如果我們用一組工具優化代價函數 ,機器學習就會變得更簡單,在重點優化代價函數 時,你只需要留意 和 , 的值越小越好,你只需要想辦法減小這個值,其它的不用關注。然後,預防過擬合還有其他任務,換句話說就是減少方差,這一步我們用另外一套工具來實現,這個原理有時被稱爲「正交化」。思路就是在一個時間做一個任務,後面課上我會具體介紹正交化,如果你還不瞭解這個概念,不用擔心。
但對我來說early stopping的主要缺點就是你不能獨立地處理這兩個問題,因爲提早停止梯度下降,也就是停止了優化代價函數 ,因爲現在你不再嘗試降低代價函數 ,所以代價函數 的值可能不夠小,同時你又希望不出現過擬合,你沒有采取不同的方式來解決這兩個問題,而是用一種方法同時解決兩個問題,這樣做的結果是我要考慮的東西變得更復雜。
如果不用early stopping,另一種方法就是 正則化,訓練神經網絡的時間就可能很長。我發現,這導致超級參數搜索空間更容易分解,也更容易搜索,但是缺點在於,你必須嘗試很多正則化參數 的值,這也導致搜索大量 值的計算代價太高。
Early stopping的優點是,只運行一次梯度下降,你可以找出 的較小值,中間值和較大值,而無需嘗試 正則化超級參數 的很多值。
如果你還不能完全理解這個概念,沒關係,下節課我們會詳細講解正交化,這樣會更好理解。
雖然 正則化有缺點,可還是有很多人願意用它。吳恩達老師個人更傾向於使用 正則化,嘗試許多不同的 正則化超級參數 的很多值。
如果你還不能完全理解這個概念,沒關係,下節課我們會詳細講解正交化,這樣會更好理解。
雖然 正則化有缺點,可還是有很多人願意用它。吳恩達老師個人更傾向於使用 正則化,嘗試許多不同的 值,假設你可以負擔大量計算的代價。而使用early stopping也能得到相似結果,還不用嘗試這麼多 值。
這節課我們講了如何使用數據擴增,以及如何使用early stopping降低神經網絡中的方差或預防過擬合。
訓練神經網絡,其中一個加速訓練的方法就是歸一化輸入。假設一個訓練集有兩個特徵,輸入特徵爲2維,歸一化需要兩個步驟:
零均值
歸一化方差;
我們希望無論是訓練集和測試集都是通過相同的 和 定義的數據轉換,這兩個是由訓練集得出來的。
第一步是零均值化,