深度学习笔记第二门课 改善深层神经网络 第三周 超参数调试、Batch正则化和程序框架...
本文是吳恩達老師的深度學習課程[1]筆記部分。
作者:黃海廣[2]
主要編寫人員:黃海廣、林興木(第四所有底稿,第五課第一二周,第三周前三節)、祝彥森:(第三課所有底稿)、賀志堯(第五課第三周底稿)、王翔、胡瀚文、 余笑、 鄭浩、李懷松、 朱越鵬、陳偉賀、 曹越、 路皓翔、邱牧宸、 唐天澤、 張浩、 陳志豪、 游忍、 澤霖、沈偉臣、 賈紅順、 時超、 陳哲、趙一帆、 胡瀟楊、段希、于沖、張鑫倩
參與編輯人員:黃海廣、陳康凱、石晴路、鐘博彥、向偉、嚴鳳龍、劉成 、賀志堯、段希、陳瑤、林家泳、王翔、 謝士晨、蔣鵬
備注:筆記和作業(含數據、原始作業文件)、視頻都在?github[3]中下載。
我將陸續將課程筆記發布在公眾號“機器學習初學者”,敬請關注。
第三周 超參數調試、Batch正則化和程序框架(Hyperparameter tuning)
3.1 調試處理(Tuning process)
大家好,歡迎回來,目前為止,你已經了解到,神經網絡的改變會涉及到許多不同超參數的設置。現在,對于超參數而言,你要如何找到一套好的設定呢?在此視頻中,我想和你分享一些指導原則,一些關于如何系統地組織超參調試過程的技巧,希望這些能夠讓你更有效的聚焦到合適的超參設定中。
關于訓練深度最難的事情之一是你要處理的參數的數量,從學習速率到Momentum(動量梯度下降法)的參數。如果使用Momentum或Adam優化算法的參數,,和,也許你還得選擇層數,也許你還得選擇不同層中隱藏單元的數量,也許你還想使用學習率衰減。所以,你使用的不是單一的學習率。接著,當然你可能還需要選擇mini-batch的大小。
結果證實一些超參數比其它的更為重要,我認為,最為廣泛的學習應用是,學習速率是需要調試的最重要的超參數。
除了,還有一些參數需要調試,例如Momentum參數,0.9就是個很好的默認值。我還會調試mini-batch的大小,以確保最優算法運行有效。我還會經常調試隱藏單元,我用橙色圈住的這些,這三個是我覺得其次比較重要的,相對于而言。重要性排第三位的是其他因素,層數有時會產生很大的影響,學習率衰減也是如此。當應用Adam算法時,事實上,我從不調試,和,我總是選定其分別為0.9,0.999和,如果你想的話也可以調試它們。
但希望你粗略了解到哪些超參數較為重要,無疑是最重要的,接下來是我用橙色圈住的那些,然后是我用紫色圈住的那些,但這不是嚴格且快速的標準,我認為,其它深度學習的研究者可能會很不同意我的觀點或有著不同的直覺。
現在,如果你嘗試調整一些超參數,該如何選擇調試值呢?在早一代的機器學習算法中,如果你有兩個超參數,這里我會稱之為超參1,超參2,常見的做法是在網格中取樣點,像這樣,然后系統的研究這些數值。這里我放置的是5×5的網格,實踐證明,網格可以是5×5,也可多可少,但對于這個例子,你可以嘗試這所有的25個點,然后選擇哪個參數效果最好。當參數的數量相對較少時,這個方法很實用。
在深度學習領域,我們常做的,我推薦你采用下面的做法,隨機選擇點,所以你可以選擇同等數量的點,對嗎?25個點,接著,用這些隨機取的點試驗超參數的效果。之所以這么做是因為,對于你要解決的問題而言,你很難提前知道哪個超參數最重要,正如你之前看到的,一些超參數的確要比其它的更重要。
舉個例子,假設超參數1是(學習速率),取一個極端的例子,假設超參數2是Adam算法中,分母中的。在這種情況下,的取值很重要,而取值則無關緊要。如果你在網格中取點,接著,你試驗了的5個取值,那你會發現,無論取何值,結果基本上都是一樣的。所以,你知道共有25種模型,但進行試驗的值只有5個,我認為這是很重要的。
對比而言,如果你隨機取值,你會試驗25個獨立的,似乎你更有可能發現效果做好的那個。
我已經解釋了兩個參數的情況,實踐中,你搜索的超參數可能不止兩個。假如,你有三個超參數,這時你搜索的不是一個方格,而是一個立方體,超參數3代表第三維,接著,在三維立方體中取值,你會試驗大量的更多的值,三個超參數中每個都是。
實踐中,你搜索的可能不止三個超參數有時很難預知,哪個是最重要的超參數,對于你的具體應用而言,隨機取值而不是網格取值表明,你探究了更多重要超參數的潛在值,無論結果是什么。
當你給超參數取值時,另一個慣例是采用由粗糙到精細的策略。
比如在二維的那個例子中,你進行了取值,也許你會發現效果最好的某個點,也許這個點周圍的其他一些點效果也很好,那在接下來要做的是放大這塊小區域(小藍色方框內),然后在其中更密集得取值或隨機取值,聚集更多的資源,在這個藍色的方格中搜索,如果你懷疑這些超參數在這個區域的最優結果,那在整個的方格中進行粗略搜索后,你會知道接下來應該聚焦到更小的方格中。在更小的方格中,你可以更密集得取點。所以這種從粗到細的搜索也經常使用。
通過試驗超參數的不同取值,你可以選擇對訓練集目標而言的最優值,或對于開發集而言的最優值,或在超參搜索過程中你最想優化的東西。
我希望,這能給你提供一種方法去系統地組織超參數搜索過程。另一個關鍵點是隨機取值和精確搜索,考慮使用由粗糙到精細的搜索過程。但超參數的搜索內容還不止這些,在下一個視頻中,我會繼續講解關于如何選擇超參數取值的合理范圍。
3.2 為超參數選擇合適的范圍(Using an appropriate scale to pick hyperparameters)
在上一個視頻中,你已經看到了在超參數范圍中,隨機取值可以提升你的搜索效率。但隨機取值并不是在有效范圍內的隨機均勻取值,而是選擇合適的標尺,用于探究這些超參數,這很重要。在這個視頻中,我會教你怎么做。
假設你要選取隱藏單元的數量,假設,你選取的取值范圍是從50到100中某點,這種情況下,看到這條從50-100的數軸,你可以隨機在其取點,這是一個搜索特定超參數的很直觀的方式。或者,如果你要選取神經網絡的層數,我們稱之為字母,你也許會選擇層數為2到4中的某個值,接著順著2,3,4隨機均勻取樣才比較合理,你還可以應用網格搜索,你會覺得2,3,4,這三個數值是合理的,這是在幾個在你考慮范圍內隨機均勻取值的例子,這些取值還蠻合理的,但對某些超參數而言不適用。
看看這個例子,假設你在搜索超參數(學習速率),假設你懷疑其值最小是0.0001或最大是1。如果你畫一條從0.0001到1的數軸,沿其隨機均勻取值,那90%的數值將會落在0.1到1之間,結果就是,在0.1到1之間,應用了90%的資源,而在0.0001到0.1之間,只有10%的搜索資源,這看上去不太對。
反而,用對數標尺搜索超參數的方式會更合理,因此這里不使用線性軸,分別依次取0.0001,0.001,0.01,0.1,1,在對數軸上均勻隨機取點,這樣,在0.0001到0.001之間,就會有更多的搜索資源可用,還有在0.001到0.01之間等等。
所以在Python中,你可以這樣做,使r=-4*np.random.rand(),然后隨機取值,,所以,第一行可以得出,那么,所以最左邊的數字是,最右邊是。
更常見的情況是,如果你在和之間取值,在此例中,這是(0.0001),你可以通過算出的值,即-4,在右邊的值是,你可以算出的值,即0。你要做的就是在區間隨機均勻地給取值,這個例子中,然后你可以設置的值,基于隨機取樣的超參數。
所以總結一下,在對數坐標下取值,取最小值的對數就得到的值,取最大值的對數就得到值,所以現在你在對數軸上的到區間取值,在,間隨意均勻的選取值,將超參數設置為,這就是在對數軸上取值的過程。
最后,另一個棘手的例子是給?取值,用于計算指數的加權平均值。假設你認為是0.9到0.999之間的某個值,也許這就是你想搜索的范圍。記住這一點,當計算指數的加權平均值時,取0.9就像在10個值中計算平均值,有點類似于計算10天的溫度平均值,而取0.999就是在1000個值中取平均。
所以和上張幻燈片上的內容類似,如果你想在0.9到0.999區間搜索,那就不能用線性軸取值,對吧?不要隨機均勻在此區間取值,所以考慮這個問題最好的方法就是,我們要探究的是,此值在0.1到0.001區間內,所以我們會給取值,大概是從0.1到0.001,應用之前幻燈片中介紹的方法,這是,這是,值得注意的是,在之前的幻燈片里,我們把最小值寫在左邊,最大值寫在右邊,但在這里,我們顛倒了大小。這里,左邊的是最大值,右邊的是最小值。所以你要做的就是在里隨機均勻的給r取值。你設定了,所以,然后這就變成了在特定的選擇范圍內超參數隨機取值。希望用這種方式得到想要的結果,你在0.9到0.99區間探究的資源,和在0.99到0.999區間探究的一樣多。
所以,如果你想研究更多正式的數學證明,關于為什么我們要這樣做,為什么用線性軸取值不是個好辦法,這是因為當?接近1時,所得結果的靈敏度會變化,即使有微小的變化。所以?在0.9到0.9005之間取值,無關緊要,你的結果幾乎不會變化。
但值如果在0.999到0.9995之間,這會對你的算法產生巨大影響,對吧?在這兩種情況下,是根據大概10個值取平均。但這里,它是指數的加權平均值,基于1000個值,現在是2000個值,因為這個公式,當接近1時,就會對細微的變化變得很敏感。所以整個取值過程中,你需要更加密集地取值,在?接近1的區間內,或者說,當?接近于0時,這樣,你就可以更加有效的分布取樣點,更有效率的探究可能的結果。
希望能幫助你選擇合適的標尺,來給超參數取值。如果你沒有在超參數選擇中作出正確的標尺決定,別擔心,即使你在均勻的標尺上取值,如果數值總量較多的話,你也會得到還不錯的結果,尤其是應用從粗到細的搜索方法,在之后的迭代中,你還是會聚焦到有用的超參數取值范圍上。
希望這會對你的超參數搜索有幫助,下一個視頻中,我們將會分享一些關于如何組建搜索過程的思考,希望它能使你的工作更高效。
3.3 超參數調試的實踐:Pandas VS Caviar(Hyperparameters tuning in practice: Pandas vs. Caviar)
到現在為止,你已經聽了許多關于如何搜索最優超參數的內容,在結束我們關于超參數搜索的討論之前,我想最后和你分享一些建議和技巧,關于如何組織你的超參數搜索過程。
如今的深度學習已經應用到許多不同的領域,某個應用領域的超參數設定,有可能通用于另一領域,不同的應用領域出現相互交融。比如,我曾經看到過計算機視覺領域中涌現的巧妙方法,比如說Confonets或ResNets,這我們會在后續課程中講到。它還成功應用于語音識別,我還看到過最初起源于語音識別的想法成功應用于NLP等等。
深度學習領域中,發展很好的一點是,不同應用領域的人們會閱讀越來越多其它研究領域的文章,跨領域去尋找靈感。
就超參數的設定而言,我見到過有些直覺想法變得很缺乏新意,所以,即使你只研究一個問題,比如說邏輯學,你也許已經找到一組很好的參數設置,并繼續發展算法,或許在幾個月的過程中,觀察到你的數據會逐漸改變,或也許只是在你的數據中心更新了服務器,正因為有了這些變化,你原來的超參數的設定不再好用,所以我建議,或許只是重新測試或評估你的超參數,至少每隔幾個月一次,以確保你對數值依然很滿意。
最后,關于如何搜索超參數的問題,我見過大概兩種重要的思想流派或人們通常采用的兩種重要但不同的方式。
一種是你照看一個模型,通常是有龐大的數據組,但沒有許多計算資源或足夠的CPU和GPU的前提下,基本而言,你只可以一次負擔起試驗一個模型或一小批模型,在這種情況下,即使當它在試驗時,你也可以逐漸改良。比如,第0天,你將隨機參數初始化,然后開始試驗,然后你逐漸觀察自己的學習曲線,也許是損失函數J,或者數據設置誤差或其它的東西,在第1天內逐漸減少,那這一天末的時候,你可能會說,看,它學習得真不錯。我試著增加一點學習速率,看看它會怎樣,也許結果證明它做得更好,那是你第二天的表現。兩天后,你會說,它依舊做得不錯,也許我現在可以填充下Momentum或減少變量。然后進入第三天,每天,你都會觀察它,不斷調整你的參數。也許有一天,你會發現你的學習率太大了,所以你可能又回歸之前的模型,像這樣,但你可以說是在每天花時間照看此模型,即使是它在許多天或許多星期的試驗過程中。所以這是一個人們照料一個模型的方法,觀察它的表現,耐心地調試學習率,但那通常是因為你沒有足夠的計算能力,不能在同一時間試驗大量模型時才采取的辦法。
另一種方法則是同時試驗多種模型,你設置了一些超參數,盡管讓它自己運行,或者是一天甚至多天,然后你會獲得像這樣的學習曲線,這可以是損失函數J或實驗誤差或損失或數據誤差的損失,但都是你曲線軌跡的度量。同時你可以開始一個有著不同超參數設定的不同模型,所以,你的第二個模型會生成一個不同的學習曲線,也許是像這樣的一條(紫色曲線),我會說這條看起來更好些。與此同時,你可以試驗第三種模型,其可能產生一條像這樣的學習曲線(紅色曲線),還有另一條(綠色曲線),也許這條有所偏離,像這樣,等等。或者你可以同時平行試驗許多不同的模型,橙色的線就是不同的模型。用這種方式你可以試驗許多不同的參數設定,然后只是最后快速選擇工作效果最好的那個。在這個例子中,也許這條看起來是最好的(下方綠色曲線)。
打個比方,我把左邊的方法稱為熊貓方式。當熊貓有了孩子,他們的孩子非常少,一次通常只有一個,然后他們花費很多精力撫養熊貓寶寶以確保其能成活,所以,這的確是一種照料,一種模型類似于一只熊貓寶寶。對比而言,右邊的方式更像魚類的行為,我稱之為魚子醬方式。在交配季節,有些魚類會產下一億顆卵,但魚類繁殖的方式是,它們會產生很多卵,但不對其中任何一個多加照料,只是希望其中一個,或其中一群,能夠表現出色。我猜,這就是哺乳動物繁衍和魚類,很多爬蟲類動物繁衍的區別。我將稱之為熊貓方式與魚子醬方式,因為這很有趣,更容易記住。
所以這兩種方式的選擇,是由你擁有的計算資源決定的,如果你擁有足夠的計算機去平行試驗許多模型,那絕對采用魚子醬方式,嘗試許多不同的超參數,看效果怎么樣。但在一些應用領域,比如在線廣告設置和計算機視覺應用領域,那里的數據太多了,你需要試驗大量的模型,所以同時試驗大量的模型是很困難的,它的確是依賴于應用的過程。但我看到那些應用熊貓方式多一些的組織,那里,你會像對嬰兒一樣照看一個模型,調試參數,試著讓它工作運轉。盡管,當然,甚至是在熊貓方式中,試驗一個模型,觀察它工作與否,也許第二或第三個星期后,也許我應該建立一個不同的模型(綠色曲線),像熊貓那樣照料它,我猜,這樣一生中可以培育幾個孩子,即使它們一次只有一個孩子或孩子的數量很少。
所以希望你能學會如何進行超參數的搜索過程,現在,還有另一種技巧,能使你的神經網絡變得更加堅實,它并不是對所有的神經網絡都適用,但當適用時,它可以使超參數搜索變得容易許多并加速試驗過程,我們在下個視頻中再講解這個技巧。
3.4 歸一化網絡的激活函數(Normalizing activations in a network)
在深度學習興起后,最重要的一個思想是它的一種算法,叫做Batch歸一化,由Sergey loffe和Christian Szegedy兩位研究者創造。Batch歸一化會使你的參數搜索問題變得很容易,使神經網絡對超參數的選擇更加穩定,超參數的范圍會更加龐大,工作效果也很好,也會是你的訓練更加容易,甚至是深層網絡。讓我們來看看Batch歸一化是怎么起作用的吧。
當訓練一個模型,比如logistic回歸時,你也許會記得,歸一化輸入特征可以加快學習過程。你計算了平均值,從訓練集中減去平均值,計算了方差,接著根據方差歸一化你的數據集,在之前的視頻中我們看到,這是如何把學習問題的輪廓,從很長的東西,變成更圓的東西,更易于算法優化。所以這是有效的,對logistic回歸和神經網絡的歸一化輸入特征值而言。
那么更深的模型呢?你不僅輸入了特征值,而且這層有激活值,這層有激活值等等。如果你想訓練這些參數,比如,,那歸一化的平均值和方差豈不是很好?以便使,的訓練更有效率。在logistic回歸的例子中,我們看到了如何歸一化,,,會幫助你更有效的訓練和。
所以問題來了,對任何一個隱藏層而言,我們能否歸一化值,在此例中,比如說的值,但可以是任何隱藏層的,以更快的速度訓練,,因為是下一層的輸入值,所以就會影響,的訓練。簡單來說,這就是Batch歸一化的作用。盡管嚴格來說,我們真正歸一化的不是,而是,深度學習文獻中有一些爭論,關于在激活函數之前是否應該將值歸一化,或是否應該在應用激活函數后再規范值。實踐中,經常做的是歸一化,所以這就是我介紹的版本,我推薦其為默認選擇,那下面就是Batch歸一化的使用方法。
在神經網絡中,已知一些中間值,假設你有一些隱藏單元值,從到,這些來源于隱藏層,所以這樣寫會更準確,即為隱藏層,從1到,但這樣書寫,我要省略及方括號,以便簡化這一行的符號。所以已知這些值,如下,你要計算平均值,強調一下,所有這些都是針對層,但我省略及方括號,然后用正如你常用的那個公式計算方差,接著,你會取每個值,使其規范化,方法如下,減去均值再除以標準偏差,為了使數值穩定,通常將作為分母,以防σ的情況。
所以現在我們已把這些值標準化,化為含平均值0和標準單位方差,所以的每一個分量都含有平均值0和方差1,但我們不想讓隱藏單元總是含有平均值0和方差1,也許隱藏單元有了不同的分布會有意義,所以我們所要做的就是計算,我們稱之為,,這里和是你模型的學習參數,所以我們使用梯度下降或一些其它類似梯度下降的算法,比如Momentum或者Nesterov,Adam,你會更新和,正如更新神經網絡的權重一樣。
請注意和的作用是,你可以隨意設置的平均值,事實上,如果,如果等于這個分母項(中的分母),等于,這里的這個值是中的,那么的作用在于,它會精確轉化這個方程,如果這些成立(),那么。
通過對和合理設定,規范化過程,即這四個等式,從根本來說,只是計算恒等函數,通過賦予和其它值,可以使你構造含其它平均值和方差的隱藏單元值。
所以,在網絡匹配這個單元的方式,之前可能是用,等等,現在則會用取代,方便神經網絡中的后續計算。如果你想放回,以清楚的表明它位于哪層,你可以把它放這。
所以我希望你學到的是,歸一化輸入特征是怎樣有助于神經網絡中的學習,Batch歸一化的作用是它適用的歸一化過程,不只是輸入層,甚至同樣適用于神經網絡中的深度隱藏層。你應用Batch歸一化了一些隱藏單元值中的平均值和方差,不過訓練輸入和這些隱藏單元值的一個區別是,你也許不想隱藏單元值必須是平均值0和方差1。
比如,如果你有sigmoid激活函數,你不想讓你的值總是全部集中在這里,你想使它們有更大的方差,或不是0的平均值,以便更好的利用非線性的sigmoid函數,而不是使所有的值都集中于這個線性版本中,這就是為什么有了和兩個參數后,你可以確保所有的值可以是你想賦予的任意值,或者它的作用是保證隱藏的單元已使均值和方差標準化。那里,均值和方差由兩參數控制,即和,學習算法可以設置為任何值,所以它真正的作用是,使隱藏單元值的均值和方差標準化,即有固定的均值和方差,均值和方差可以是0和1,也可以是其它值,它是由和兩參數控制的。
我希望你能學會怎樣使用Batch歸一化,至少就神經網絡的單一層而言,在下一個視頻中,我會教你如何將Batch歸一化與神經網絡甚至是深度神經網絡相匹配。對于神經網絡許多不同層而言,又該如何使它適用,之后,我會告訴你,Batch歸一化有助于訓練神經網絡的原因。所以如果覺得Batch歸一化起作用的原因還顯得有點神秘,那跟著我走,在接下來的兩個視頻中,我們會弄清楚。
3.5 將 Batch Norm 擬合進神經網絡(Fitting Batch Norm into a neural network)
你已經看到那些等式,它可以在單一隱藏層進行Batch歸一化,接下來,讓我們看看它是怎樣在深度網絡訓練中擬合的吧。
假設你有一個這樣的神經網絡,我之前說過,你可以認為每個單元負責計算兩件事。第一,它先計算z,然后應用其到激活函數中再計算a,所以我可以認為,每個圓圈代表著兩步的計算過程。同樣的,對于下一層而言,那就是和等。所以如果你沒有應用Batch歸一化,你會把輸入擬合到第一隱藏層,然后首先計算,這是由和兩個參數控制的。接著,通常而言,你會把擬合到激活函數以計算。但Batch歸一化的做法是將值進行Batch歸一化,簡稱BN,此過程將由和兩參數控制,這一操作會給你一個新的規范化的值(),然后將其輸入激活函數中得到,即。
現在,你已在第一層進行了計算,此時Batch歸一化發生在z的計算和之間,接下來,你需要應用值來計算,此過程是由和控制的。與你在第一層所做的類似,你會將進行Batch歸一化,現在我們簡稱BN,這是由下一層的Batch歸一化參數所管制的,即和,現在你得到,再通過激活函數計算出等等。
所以需要強調的是Batch歸一化是發生在計算和之間的。直覺就是,與其應用沒有歸一化的值,不如用歸一過的,這是第一層()。第二層同理,與其應用沒有規范過的值,不如用經過方差和均值歸一后的。所以,你網絡的參數就會是,,和等等,我們將要去掉這些參數。但現在,想象參數,到,,我們將另一些參數加入到此新網絡中,,,等等。對于應用Batch歸一化的每一層而言。需要澄清的是,請注意,這里的這些(,等等)和超參數沒有任何關系,下一張幻燈片中會解釋原因,后者是用于Momentum或計算各個指數的加權平均值。Adam論文的作者,在論文里用代表超參數。Batch歸一化論文的作者,則使用代表此參數(,等等),但這是兩個完全不同的。我在兩種情況下都決定使用,以便你閱讀那些原創的論文,但Batch歸一化學習參數,等等和用于Momentum、Adam、RMSprop算法中的不同。
所以現在,這是你算法的新參數,接下來你可以使用想用的任何一種優化算法,比如使用梯度下降法來執行它。
舉個例子,對于給定層,你會計算,接著更新參數為。你也可以使用Adam或RMSprop或Momentum,以更新參數和,并不是只應用梯度下降法。
即使在之前的視頻中,我已經解釋過Batch歸一化是怎么操作的,計算均值和方差,減去均值,再除以方差,如果它們使用的是深度學習編程框架,通常你不必自己把Batch歸一化步驟應用于Batch歸一化層。因此,探究框架,可寫成一行代碼,比如說,在TensorFlow框架中,你可以用這個函數(tf.nn.batch_normalization)來實現Batch歸一化,我們稍后講解,但實踐中,你不必自己操作所有這些具體的細節,但知道它是如何作用的,你可以更好的理解代碼的作用。但在深度學習框架中,Batch歸一化的過程,經常是類似一行代碼的東西。
所以,到目前為止,我們已經講了Batch歸一化,就像你在整個訓練站點上訓練一樣,或就像你正在使用Batch梯度下降法。
實踐中,Batch歸一化通常和訓練集的mini-batch一起使用。你應用Batch歸一化的方式就是,你用第一個mini-batch(),然后計算,這和上張幻燈片上我們所做的一樣,應用參數和,使用這個mini-batch()。接著,繼續第二個mini-batch(),接著Batch歸一化會減去均值,除以標準差,由和重新縮放,這樣就得到了,而所有的這些都是在第一個mini-batch的基礎上,你再應用激活函數得到。然后用和計算,等等,所以你做的這一切都是為了在第一個mini-batch()上進行一步梯度下降法。
類似的工作,你會在第二個mini-batch()上計算,然后用Batch歸一化來計算,所以Batch歸一化的此步中,你用第二個mini-batch()中的數據使歸一化,這里的Batch歸一化步驟也是如此,讓我們來看看在第二個mini-batch()中的例子,在mini-batch上計算的均值和方差,重新縮放的和得到,等等。
然后在第三個mini-batch()上同樣這樣做,繼續訓練。
現在,我想澄清此參數的一個細節。先前我說過每層的參數是和,還有和,請注意計算的方式如下,,但Batch歸一化做的是,它要看這個mini-batch,先將歸一化,結果為均值0和標準方差,再由?和?重新縮放,但這意味著,無論的值是多少,都是要被減去的,因為在Batch歸一化的過程中,你要計算的均值,再減去平均值,在此例中的mini-batch中增加任何常數,數值都不會改變,因為加上的任何常數都將會被均值減去所抵消。
所以,如果你在使用Batch歸一化,其實你可以消除這個參數(),或者你也可以,暫時把它設置為0,那么,參數變成,然后你計算歸一化的,,你最后會用參數,以便決定的取值,這就是原因。
所以總結一下,因為Batch歸一化超過了此層的均值,這個參數沒有意義,所以,你必須去掉它,由代替,這是個控制參數,會影響轉移或偏置條件。
最后,請記住的維數,因為在這個例子中,維數會是,的尺寸為,如果是l層隱藏單元的數量,那和的維度也是,因為這是你隱藏層的數量,你有隱藏單元,所以和用來將每個隱藏層的均值和方差縮放為網絡想要的值。
讓我們總結一下關于如何用Batch歸一化來應用梯度下降法,假設你在使用mini-batch梯度下降法,你運行到batch數量的for循環,你會在mini-batch?上應用正向prop,每個隱藏層都應用正向prop,用Batch歸一化代替為。接下來,它確保在這個mini-batch中,值有歸一化的均值和方差,歸一化均值和方差后是,然后,你用反向prop計算和,及所有l層所有的參數,和。盡管嚴格來說,因為你要去掉,這部分其實已經去掉了。最后,你更新這些參數:α,和以前一樣,α,對于也是如此α。
如果你已將梯度計算如下,你就可以使用梯度下降法了,這就是我寫到這里的,但也適用于有Momentum、RMSprop、Adam的梯度下降法。與其使用梯度下降法更新mini-batch,你可以使用這些其它算法來更新,我們在之前幾個星期中的視頻中討論過的,也可以應用其它的一些優化算法來更新由Batch歸一化添加到算法中的?和?參數。
我希望,你能學會如何從頭開始應用Batch歸一化,如果你想的話。如果你使用深度學習編程框架之一,我們之后會談,希望,你可以直接調用別人的編程框架,這會使Batch歸一化的使用變得很容易。
現在,以防Batch歸一化仍然看起來有些神秘,尤其是你還不清楚為什么其能如此顯著的加速訓練,我們進入下一個視頻,詳細討論Batch歸一化為何效果如此顯著,它到底在做什么。
3.6 Batch Norm 為什么奏效?(Why does Batch Norm work?)
為什么Batch歸一化會起作用呢?
一個原因是,你已經看到如何歸一化輸入特征值,使其均值為0,方差1,它又是怎樣加速學習的,有一些從0到1而不是從1到1000的特征值,通過歸一化所有的輸入特征值,以獲得類似范圍的值,可以加速學習。所以Batch歸一化起的作用的原因,直觀的一點就是,它在做類似的工作,但不僅僅對于這里的輸入值,還有隱藏單元的值,這只是Batch歸一化作用的冰山一角,還有些深層的原理,它會有助于你對Batch歸一化的作用有更深的理解,讓我們一起來看看吧。
Batch歸一化有效的第二個原因是,它可以使權重比你的網絡更滯后或更深層,比如,第10層的權重更能經受得住變化,相比于神經網絡中前層的權重,比如第1層,為了解釋我的意思,讓我們來看看這個最生動形象的例子。
這是一個網絡的訓練,也許是個淺層網絡,比如logistic回歸或是一個神經網絡,也許是個淺層網絡,像這個回歸函數。或一個深層網絡,建立在我們著名的貓臉識別檢測上,但假設你已經在所有黑貓的圖像上訓練了數據集,如果現在你要把此網絡應用于有色貓,這種情況下,正面的例子不只是左邊的黑貓,還有右邊其它顏色的貓,那么你的cosfa可能適用的不會很好。
如果圖像中,你的訓練集是這個樣子的,你的正面例子在這兒,反面例子在那兒(左圖),但你試圖把它們都統一于一個數據集,也許正面例子在這,反面例子在那兒(右圖)。你也許無法期待,在左邊訓練得很好的模塊,同樣在右邊也運行得很好,即使存在運行都很好的同一個函數,但你不會希望你的學習算法去發現綠色的決策邊界,如果只看左邊數據的話。
所以使你數據改變分布的這個想法,有個有點怪的名字“Covariate shift”,想法是這樣的,如果你已經學習了到?的映射,如果?的分布改變了,那么你可能需要重新訓練你的學習算法。這種做法同樣適用于,如果真實函數由?到?映射保持不變,正如此例中,因為真實函數是此圖片是否是一只貓,訓練你的函數的需要變得更加迫切,如果真實函數也改變,情況就更糟了。
“Covariate shift”的問題怎么應用于神經網絡呢?試想一個像這樣的深度網絡,讓我們從這層(第三層)來看看學習過程。此網絡已經學習了參數和,從第三隱藏層的角度來看,它從前層中取得一些值,接著它需要做些什么,使希望輸出值接近真實值。
讓我先遮住左邊的部分,從第三隱藏層的角度來看,它得到一些值,稱為,,,,但這些值也可以是特征值,,,,第三層隱藏層的工作是找到一種方式,使這些值映射到,你可以想象做一些截斷,所以這些參數和或和或和,也許是學習這些參數,所以網絡做的不錯,從左邊我用黑色筆寫的映射到輸出值。
現在我們把網絡的左邊揭開,這個網絡還有參數,和,,如果這些參數改變,這些的值也會改變。所以從第三層隱藏層的角度來看,這些隱藏單元的值在不斷地改變,所以它就有了“Covariate shift”的問題,上張幻燈片中我們講過的。
Batch歸一化做的,是它減少了這些隱藏值分布變化的數量。如果是繪制這些隱藏的單元值的分布,也許這是重整值,這其實是,,我要繪制兩個值而不是四個值,以便我們設想為2D,Batch歸一化講的是,的值可以改變,它們的確會改變,當神經網絡在之前層中更新參數,Batch歸一化可以確保無論其怎樣變化,的均值和方差保持不變,所以即使,的值改變,至少他們的均值和方差也會是均值0,方差1,或不一定必須是均值0,方差1,而是由和決定的值。如果神經網絡選擇的話,可強制其為均值0,方差1,或其他任何均值和方差。但它做的是,它限制了在前層的參數更新,會影響數值分布的程度,第三層看到的這種情況,因此得到學習。
Batch歸一化減少了輸入值改變的問題,它的確使這些值變得更穩定,神經網絡的之后層就會有更堅實的基礎。即使使輸入分布改變了一些,它會改變得更少。它做的是當前層保持學習,當改變時,迫使后層適應的程度減小了,你可以這樣想,它減弱了前層參數的作用與后層參數的作用之間的聯系,它使得網絡每層都可以自己學習,稍稍獨立于其它層,這有助于加速整個網絡的學習。
所以,希望這能帶給你更好的直覺,重點是Batch歸一化的意思是,尤其從神經網絡后層之一的角度而言,前層不會左右移動的那么多,因為它們被同樣的均值和方差所限制,所以,這會使得后層的學習工作變得更容易些。
Batch歸一化還有一個作用,它有輕微的正則化效果,Batch歸一化中非直觀的一件事是,每個mini-batch,我會說mini-batch的值為,,在mini-batch計算中,由均值和方差縮放的,因為在mini-batch上計算的均值和方差,而不是在整個數據集上,均值和方差有一些小的噪聲,因為它只在你的mini-batch上計算,比如64或128或256或更大的訓練例子。因為均值和方差有一點小噪音,因為它只是由一小部分數據估計得出的。縮放過程從到,過程也有一些噪音,因為它是用有些噪音的均值和方差計算得出的。
所以和dropout相似,它往每個隱藏層的激活值上增加了噪音,dropout有增加噪音的方式,它使一個隱藏的單元,以一定的概率乘以0,以一定的概率乘以1,所以你的dropout含幾重噪音,因為它乘以0或1。
對比而言,Batch歸一化含幾重噪音,因為標準偏差的縮放和減去均值帶來的額外噪音。這里的均值和標準差的估計值也是有噪音的,所以類似于dropout,Batch歸一化有輕微的正則化效果,因為給隱藏單元添加了噪音,這迫使后部單元不過分依賴任何一個隱藏單元,類似于dropout,它給隱藏層增加了噪音,因此有輕微的正則化效果。因為添加的噪音很微小,所以并不是巨大的正則化效果,你可以將Batch歸一化和dropout一起使用,如果你想得到dropout更強大的正則化效果。
也許另一個輕微非直觀的效果是,如果你應用了較大的mini-batch,對,比如說,你用了512而不是64,通過應用較大的min-batch,你減少了噪音,因此減少了正則化效果,這是dropout的一個奇怪的性質,就是應用較大的mini-batch可以減少正則化效果。
說到這兒,我會把Batch歸一化當成一種正則化,這確實不是其目的,但有時它會對你的算法有額外的期望效應或非期望效應。但是不要把Batch歸一化當作正則化,把它當作將你歸一化隱藏單元激活值并加速學習的方式,我認為正則化幾乎是一個意想不到的副作用。
所以希望這能讓你更理解Batch歸一化的工作,在我們結束Batch歸一化的討論之前,我想確保你還知道一個細節。Batch歸一化一次只能處理一個mini-batch數據,它在mini-batch上計算均值和方差。所以測試時,你試圖做出預測,試著評估神經網絡,你也許沒有mini-batch的例子,你也許一次只能進行一個簡單的例子,所以測試時,你需要做一些不同的東西以確保你的預測有意義。
在下一個也就是最后一個Batch歸一化視頻中,讓我們詳細談談你需要注意的一些細節,來讓你的神經網絡應用Batch歸一化來做出預測。
3.7 測試時的 Batch Norm(Batch Norm at test time)
Batch歸一化將你的數據以mini-batch的形式逐一處理,但在測試時,你可能需要對每個樣本逐一處理,我們來看一下怎樣調整你的網絡來做到這一點。
回想一下,在訓練時,這些就是用來執行Batch歸一化的等式。在一個mini-batch中,你將mini-batch的值求和,計算均值,所以這里你只把一個mini-batch中的樣本都加起來,我用m來表示這個mini-batch中的樣本數量,而不是整個訓練集。然后計算方差,再算,即用均值和標準差來調整,加上是為了數值穩定性。是用和再次調整得到的。
請注意用于調節計算的和是在整個mini-batch上進行計算,但是在測試時,你可能不能將一個mini-batch中的6428或2056個樣本同時處理,因此你需要用其它方式來得到和,而且如果你只有一個樣本,一個樣本的均值和方差沒有意義。那么實際上,為了將你的神經網絡運用于測試,就需要單獨估算和,在典型的Batch歸一化運用中,你需要用一個指數加權平均來估算,這個平均數涵蓋了所有mini-batch,接下來我會具體解釋。
我們選擇層,假設我們有mini-batch,,,……以及對應的值等等,那么在為層訓練時,你就得到了,我還是把它寫做第一個mini-batch和這一層的吧,()。當你訓練第二個mini-batch,在這一層和這個mini-batch中,你就會得到第二個()值。然后在這一隱藏層的第三個mini-batch,你得到了第三個()值。正如我們之前用的指數加權平均來計算,,的均值,當時是試著計算當前氣溫的指數加權平均,你會這樣來追蹤你看到的這個均值向量的最新平均值,于是這個指數加權平均就成了你對這一隱藏層的均值的估值。同樣的,你可以用指數加權平均來追蹤你在這一層的第一個mini-batch中所見的的值,以及第二個mini-batch中所見的的值等等。因此在用不同的mini-batch訓練神經網絡的同時,能夠得到你所查看的每一層的和的平均數的實時數值。
最后在測試時,對應這個等式(),你只需要用你的值來計算,用和的指數加權平均,用你手頭的最新數值來做調整,然后你可以用左邊我們剛算出來的和你在神經網絡訓練過程中得到的和參數來計算你那個測試樣本的值。
總結一下就是,在訓練時,和是在整個mini-batch上計算出來的包含了像是64或28或其它一定數量的樣本,但在測試時,你可能需要逐一處理樣本,方法是根據你的訓練集估算和,估算的方式有很多種,理論上你可以在最終的網絡中運行整個訓練集來得到和,但在實際操作中,我們通常運用指數加權平均來追蹤在訓練過程中你看到的和的值。還可以用指數加權平均,有時也叫做流動平均來粗略估算和,然后在測試中使用和的值來進行你所需要的隱藏單元值的調整。在實踐中,不管你用什么方式估算和,這套過程都是比較穩健的,因此我不太會擔心你具體的操作方式,而且如果你使用的是某種深度學習框架,通常會有默認的估算和的方式,應該一樣會起到比較好的效果。但在實踐中,任何合理的估算你的隱藏單元值的均值和方差的方式,在測試中應該都會有效。
Batch歸一化就講到這里,使用Batch歸一化,你能夠訓練更深的網絡,讓你的學習算法運行速度更快,在結束這周的課程之前,我還想和你們分享一些關于深度學習框架的想法,讓我們在下一段視頻中一起討論這個話題。
3.8 Softmax 回歸(Softmax regression)
到目前為止,我們講到過的分類的例子都使用了二分分類,這種分類只有兩種可能的標記0或1,這是一只貓或者不是一只貓,如果我們有多種可能的類型的話呢?有一種logistic回歸的一般形式,叫做Softmax回歸,能讓你在試圖識別某一分類時做出預測,或者說是多種分類中的一個,不只是識別兩個分類,我們來一起看一下。
假設你不單需要識別貓,而是想識別貓,狗和小雞,我把貓加做類1,狗為類2,小雞是類3,如果不屬于以上任何一類,就分到“其它”或者說“以上均不符合”這一類,我把它叫做類0。這里顯示的圖片及其對應的分類就是一個例子,這幅圖片上是一只小雞,所以是類3,貓是類1,狗是類2,我猜這是一只考拉,所以以上均不符合,那就是類0,下一個類3,以此類推。我們將會用符號表示,我會用大寫的來表示你的輸入會被分入的類別總個數,在這個例子中,我們有4種可能的類別,包括“其它”或“以上均不符合”這一類。當有4個分類時,指示類別的數字,就是從0到,換句話說就是0、1、2、3。
在這個例子中,我們將建立一個神經網絡,其輸出層有4個,或者說個輸出單元,因此,即輸出層也就是層的單元數量,等于4,或者一般而言等于。我們想要輸出層單元的數字告訴我們這4種類型中每個的概率有多大,所以這里的第一個節點(最后輸出的第1個方格+圓圈)輸出的應該是或者說我們希望它輸出“其它”類的概率。在輸入的情況下,這個(最后輸出的第2個方格+圓圈)會輸出貓的概率。在輸入的情況下,這個會輸出狗的概率(最后輸出的第3個方格+圓圈)。在輸入的情況下,輸出小雞的概率(最后輸出的第4個方格+圓圈),我把小雞縮寫為bc(baby chick)。因此這里的將是一個維向量,因為它必須輸出四個數字,給你這四種概率,因為它們加起來應該等于1,輸出中的四個數字加起來應該等于1。
讓你的網絡做到這一點的標準模型要用到Softmax層,以及輸出層來生成輸出,讓我把式子寫下來,然后回過頭來,就會對Softmax的作用有一點感覺了。
在神經網絡的最后一層,你將會像往常一樣計算各層的線性部分,這是最后一層的變量,記住這是大寫層,和往常一樣,計算方法是,算出了之后,你需要應用Softmax激活函數,這個激活函數對于Softmax層而言有些不同,它的作用是這樣的。首先,我們要計算一個臨時變量,我們把它叫做t,它等于,這適用于每個元素,而這里的,在我們的例子中,是4×1的,四維向量,這是對所有元素求冪,也是一個4×1維向量,然后輸出的,基本上就是向量,但是會歸一化,使和為1。因此,換句話說,也是一個4×1維向量,而這個四維向量的第個元素,我把它寫下來,,以防這里的計算不夠清晰易懂,我們馬上會舉個例子來詳細解釋。
我們來看一個例子,詳細解釋,假設你算出了,是一個四維向量,假設為,我們要做的就是用這個元素取冪方法來計算,所以,如果你按一下計算器就會得到以下值,我們從向量得到向量就只需要將這些項目歸一化,使總和為1。如果你把的元素都加起來,把這四個數字加起來,得到176.3,最終。
例如這里的第一個節點,它會輸出,這樣說來,對于這張圖片,如果這是你得到的值(),它是類0的概率就是84.2%。下一個節點輸出,也就是4.2%的幾率。下一個是。最后一個是,也就是11.4%的概率屬于類3,也就是小雞組,對吧?這就是它屬于類0,類1,類2,類3的可能性。
神經網絡的輸出,也就是,是一個4×1維向量,這個4×1向量的元素就是我們算出來的這四個數字(),所以這種算法通過向量計算出總和為1的四個概率。
如果我們總結一下從到的計算步驟,整個計算過程,從計算冪到得出臨時變量,再歸一化,我們可以將此概括為一個Softmax激活函數。設,這一激活函數的與眾不同之處在于,這個激活函數?需要輸入一個4×1維向量,然后輸出一個4×1維向量。之前,我們的激活函數都是接受單行數值輸入,例如Sigmoid和ReLu激活函數,輸入一個實數,輸出一個實數。Softmax激活函數的特殊之處在于,因為需要將所有可能的輸出歸一化,就需要輸入一個向量,最后輸出一個向量。
那么Softmax分類器還可以代表其它的什么東西么?我來舉幾個例子,你有兩個輸入,,它們直接輸入到Softmax層,它有三四個或者更多的輸出節點,輸出,我將向你展示一個沒有隱藏層的神經網絡,它所做的就是計算,而輸出的出,或者說,,就是的Softmax激活函數,這個沒有隱藏層的神經網絡應該能讓你對Softmax函數能夠代表的東西有所了解。
這個例子中(左邊圖),原始輸入只有和,一個個輸出分類的Softmax層能夠代表這種類型的決策邊界,請注意這是幾條線性決策邊界,但這使得它能夠將數據分到3個類別中,在這張圖表中,我們所做的是選擇這張圖中顯示的訓練集,用數據的3種輸出標簽來訓練Softmax分類器,圖中的顏色顯示了Softmax分類器的輸出的閾值,輸入的著色是基于三種輸出中概率最高的那種。因此我們可以看到這是logistic回歸的一般形式,有類似線性的決策邊界,但有超過兩個分類,分類不只有0和1,而是可以是0,1或2。
這是(中間圖)另一個Softmax分類器可以代表的決策邊界的例子,用有三個分類的數據集來訓練,這里(右邊圖)還有一個。對吧,但是直覺告訴我們,任何兩個分類之間的決策邊界都是線性的,這就是為什么你看到,比如這里黃色和紅色分類之間的決策邊界是線性邊界,紫色和紅色之間的也是線性邊界,紫色和黃色之間的也是線性決策邊界,但它能用這些不同的線性函數來把空間分成三類。
我們來看一下更多分類的例子,這個例子中(左邊圖),因此這個綠色分類和Softmax仍舊可以代表多種分類之間的這些類型的線性決策邊界。另一個例子(中間圖)是類,最后一個例子(右邊圖)是,這顯示了Softmax分類器在沒有隱藏層的情況下能夠做到的事情,當然更深的神經網絡會有,然后是一些隱藏單元,以及更多隱藏單元等等,你就可以學習更復雜的非線性決策邊界,來區分多種不同分類。
我希望你了解了神經網絡中的Softmax層或者Softmax激活函數有什么作用,下一個視頻中,我們來看一下你該怎樣訓練一個使用Softmax層的神經網絡。
3.9 訓練一個 Softmax 分類器(Training a Softmax classifier)
上一個視頻中我們學習了Softmax層和Softmax激活函數,在這個視頻中,你將更深入地了解Softmax分類,并學習如何訓練一個使用了Softmax層的模型。
回憶一下我們之前舉的的例子,輸出層計算出的如下,我們有四個分類,可以是4×1維向量,我們計算了臨時變量,,對元素進行冪運算,最后,如果你的輸出層的激活函數是Softmax激活函數,那么輸出就會是這樣的:
簡單來說就是用臨時變量將它歸一化,使總和為1,于是這就變成了,你注意到向量中,最大的元素是5,而最大的概率也就是第一種概率。
Softmax這個名稱的來源是與所謂hardmax對比,hardmax會把向量變成這個向量,hardmax函數會觀察的元素,然后在中最大元素的位置放上1,其它位置放上0,所這是一個hard max,也就是最大的元素的輸出為1,其它的輸出都為0。與之相反,Softmax所做的從到這些概率的映射更為溫和,我不知道這是不是一個好名字,但至少這就是softmax這一名稱背后所包含的想法,與hardmax正好相反。
有一點我沒有細講,但之前已經提到過的,就是Softmax回歸或Softmax激活函數將logistic激活函數推廣到類,而不僅僅是兩類,結果就是如果,那么的Softmax實際上變回了logistic回歸,我不會在這個視頻中給出證明,但是大致的證明思路是這樣的,如果,并且你應用了Softmax,那么輸出層將會輸出兩個數字,如果的話,也許輸出0.842和0.158,對吧?這兩個數字加起來要等于1,因為它們的和必須為1,其實它們是冗余的,也許你不需要計算兩個,而只需要計算其中一個,結果就是你最終計算那個數字的方式又回到了logistic回歸計算單個輸出的方式。這算不上是一個證明,但我們可以從中得出結論,Softmax回歸將logistic回歸推廣到了兩種分類以上。
接下來我們來看怎樣訓練帶有Softmax輸出層的神經網絡,具體而言,我們先定義訓練神經網絡使會用到的損失函數。舉個例子,我們來看看訓練集中某個樣本的目標輸出,真實標簽是,用上一個視頻中講到過的例子,這表示這是一張貓的圖片,因為它屬于類1,現在我們假設你的神經網絡輸出的是,是一個包括總和為1的概率的向量,,你可以看到總和為1,這就是,。對于這個樣本神經網絡的表現不佳,這實際上是一只貓,但卻只分配到20%是貓的概率,所以在本例中表現不佳。
那么你想用什么損失函數來訓練這個神經網絡?在Softmax分類中,我們一般用到的損失函數是,我們來看上面的單個樣本來更好地理解整個過程。注意在這個樣本中,因為這些都是0,只有,如果你看這個求和,所有含有值為0的的項都等于0,最后只剩下,因為當你按照下標全部加起來,所有的項都為0,除了時,又因為,所以它就等于。?
這就意味著,如果你的學習算法試圖將它變小,因為梯度下降法是用來減少訓練集的損失的,要使它變小的唯一方式就是使變小,要想做到這一點,就需要使盡可能大,因為這些是概率,所以不可能比1大,但這的確也講得通,因為在這個例子中是貓的圖片,你就需要這項輸出的概率盡可能地大(中第二個元素)。
概括來講,損失函數所做的就是它找到你的訓練集中的真實類別,然后試圖使該類別相應的概率盡可能地高,如果你熟悉統計學中最大似然估計,這其實就是最大似然估計的一種形式。但如果你不知道那是什么意思,也不用擔心,用我們剛剛講過的算法思維也足夠了。
這是單個訓練樣本的損失,整個訓練集的損失又如何呢?也就是設定參數的代價之類的,還有各種形式的偏差的代價,它的定義你大致也能猜到,就是整個訓練集損失的總和,把你的訓練算法對所有訓練樣本的預測都加起來,
因此你要做的就是用梯度下降法,使這里的損失最小化。
最后還有一個實現細節,注意因為,是一個4×1向量,也是一個4×1向量,如果你實現向量化,矩陣大寫就是,例如如果上面這個樣本是你的第一個訓練樣本,那么矩陣,那么這個矩陣最終就是一個維矩陣。類似的,,這個其實就是(),或是第一個訓練樣本的輸出,那么,本身也是一個維矩陣。
最后我們來看一下,在有Softmax輸出層時如何實現梯度下降法,這個輸出層會計算,它是維的,在這個例子中是4×1,然后你用Softmax激活函數來得到或者說,然后又能由此計算出損失。我們已經講了如何實現神經網絡前向傳播的步驟,來得到這些輸出,并計算損失,那么反向傳播步驟或者梯度下降法又如何呢?其實初始化反向傳播所需要的關鍵步驟或者說關鍵方程是這個表達式,你可以用這個4×1向量減去這個4×1向量,你可以看到這些都會是4×1向量,當你有4個分類時,在一般情況下就是,這符合我們對的一般定義,這是對損失函數的偏導數(),如果你精通微積分就可以自己推導,或者說如果你精通微積分,可以試著自己推導,但如果你需要從零開始使用這個公式,它也一樣有用。
有了這個,你就可以計算,然后開始反向傳播的過程,計算整個神經網絡中所需要的所有導數。
但在這周的初級練習中,我們將開始使用一種深度學習編程框架,對于這些編程框架,通常你只需要專注于把前向傳播做對,只要你將它指明為編程框架,前向傳播,它自己會弄明白怎樣反向傳播,會幫你實現反向傳播,所以這個表達式值得牢記(),如果你需要從頭開始,實現Softmax回歸或者Softmax分類,但其實在這周的初級練習中你不會用到它,因為編程框架會幫你搞定導數計算。
Softmax分類就講到這里,有了它,你就可以運用學習算法將輸入分成不止兩類,而是個不同類別。接下來我想向你展示一些深度學習編程框架,可以讓你在實現深度學習算法時更加高效,讓我們在下一個視頻中一起討論。
3.10 深度學習框架(Deep Learning frameworks)
你已經差不多從零開始學習了使用Python和NumPy實現深度學習算法,很高興你這樣做了,因為我希望你理解這些深度學習算法實際上在做什么。但你會發現,除非應用更復雜的模型,例如卷積神經網絡,或者循環神經網絡,或者當你開始應用很大的模型,否則它就越來越不實用了,至少對大多數人而言,從零開始全部靠自己實現并不現實。
幸運的是,現在有很多好的深度學習軟件框架,可以幫助你實現這些模型。類比一下,我猜你知道如何做矩陣乘法,你還應該知道如何編程實現兩個矩陣相乘,但是當你在建很大的應用時,你很可能不想用自己的矩陣乘法函數,而是想要訪問一個數值線性代數庫,它會更高效,但如果你明白兩個矩陣相乘是怎么回事還是挺有用的。我認為現在深度學習已經很成熟了,利用一些深度學習框架會更加實用,會使你的工作更加有效,那就讓我們來看下有哪些框架。
現在有許多深度學習框架,能讓實現神經網絡變得更簡單,我們來講主要的幾個。每個框架都針對某一用戶或開發群體的,我覺得這里的每一個框架都是某類應用的可靠選擇,有很多人寫文章比較這些深度學習框架,以及這些深度學習框架發展得有多好,而且因為這些框架往往不斷進化,每個月都在進步,如果你想看看關于這些框架的優劣之處的討論,我留給你自己去網上搜索,但我認為很多框架都在很快進步,越來越好,因此我就不做強烈推薦了,而是與你分享推薦一下選擇框架的標準。
一個重要的標準就是便于編程,這既包括神經網絡的開發和迭代,還包括為產品進行配置,為了成千上百萬,甚至上億用戶的實際使用,取決于你想要做什么。
第二個重要的標準是運行速度,特別是訓練大數據集時,一些框架能讓你更高效地運行和訓練神經網絡。
還有一個標準人們不常提到,但我覺得很重要,那就是這個框架是否真的開放,要是一個框架真的開放,它不僅需要開源,而且需要良好的管理。不幸的是,在軟件行業中,一些公司有開源軟件的歷史,但是公司保持著對軟件的全權控制,當幾年時間過去,人們開始使用他們的軟件時,一些公司開始逐漸關閉曾經開放的資源,或將功能轉移到他們專營的云服務中。因此我會注意的一件事就是你能否相信這個框架能長時間保持開源,而不是在一家公司的控制之下,它未來有可能出于某種原因選擇停止開源,即便現在這個軟件是以開源的形式發布的。但至少在短期內,取決于你對語言的偏好,看你更喜歡Python,Java還是**C++**或者其它什么,也取決于你在開發的應用,是計算機視覺,還是自然語言處理或者線上廣告,等等,我認為這里的多個框架都是很好的選擇。
程序框架就講到這里,通過提供比數值線性代數庫更高程度的抽象化,這里的每一個程序框架都能讓你在開發深度機器學習應用時更加高效。
3.11 TensorFlow
歡迎來到這周的最后一個視頻,有很多很棒的深度學習編程框架,其中一個是TensorFlow,我很期待幫助你開始學習使用TensorFlow,我想在這個視頻中向你展示TensorFlow程序的基本結構,然后讓你自己練習,學習更多細節,并運用到本周的編程練習中,這周的編程練習需要花些時間來做,所以請務必留出一些空余時間。
先提一個啟發性的問題,假設你有一個損失函數需要最小化,在本例中,我將使用這個高度簡化的損失函數,,這就是損失函數,也許你已經注意到該函數其實就是,如果你把這個二次方式子展開就得到了上面的表達式,所以使它最小的值是5,但假設我們不知道這點,你只有這個函數,我們來看一下怎樣用TensorFlow將其最小化,因為一個非常類似的程序結構可以用來訓練神經網絡。其中可以有一些復雜的損失函數取決于你的神經網絡的所有參數,然后類似的,你就能用TensorFlow自動找到使損失函數最小的和的值。但讓我們先從左邊這個更簡單的例子入手。
我在我的Jupyter notebook中運行Python,
import numpy as np import tensorflow as tf #導入TensorFloww = tf.Variable(0,dtype = tf.float32) #接下來,讓我們定義參數w,在TensorFlow中,你要用tf.Variable()來定義參數#然后我們定義損失函數:cost = tf.add(tf.add(w**2,tf.multiply(- 10.,w)),25) #然后我們定義損失函數J 然后我們再寫:train = tf.train.GradientDescentOptimizer(0.01).minimize(cost) #(讓我們用0.01的學習率,目標是最小化損失)。#最后下面的幾行是慣用表達式:init?=?tf.global_variables_initializer() session?=?tf.Session()#這樣就開啟了一個TensorFlow?session。 session.run(init)#來初始化全局變量。#然后讓TensorFlow評估一個變量,我們要用到:session.run(w) #上面的這一行將w初始化為0,并定義損失函數,我們定義train為學習算法,它用梯度下降法優化器使損失函數最小化,但實際上我們還沒有運行學習算法,所以#上面的這一行將w初始化為0,并定義損失函數,我們定義train為學習算法,它用梯度下降法優化器使損失函數最小化,但實際上我們還沒有運行學習算法,所以session.run(w)評估了w,讓我::print(session.run(w))所以如果我們運行這個,它評估等于0,因為我們什么都還沒運行。
#現在讓我們輸入:$session.run(train),它所做的就是運行一步梯度下降法。 #接下來在運行了一步梯度下降法后,讓我們評估一下w的值,再print:print(session.run(w)) #在一步梯度下降法之后,w現在是0.1。現在我們運行梯度下降1000次迭代:
這是運行了梯度下降的1000次迭代,最后變成了4.99999,記不記得我們說最小化,因此的最優值是5,這個結果已經很接近了。
希望這個讓你對TensorFlow程序的大致結構有了了解,當你做編程練習,使用更多TensorFlow代碼時,我這里用到的一些函數你會熟悉起來,這里有個地方要注意,是我們想要優化的參數,因此將它稱為變量,注意我們需要做的就是定義一個損失函數,使用這些add和multiply之類的函數。TensorFlow知道如何對add和mutiply,還有其它函數求導,這就是為什么你只需基本實現前向傳播,它能弄明白如何做反向傳播和梯度計算,因為它已經內置在add,multiply和平方函數中。
對了,要是覺得這種寫法不好看的話,TensorFlow其實還重載了一般的加減運算等等,因此你也可以把寫成更好看的形式,把之前的cost標成注釋,重新運行,得到了同樣的結果。
一旦被稱為TensorFlow變量,平方,乘法和加減運算都重載了,因此你不必使用上面這種不好看的句法。
TensorFlow還有一個特點,我想告訴你,那就是這個例子將的一個固定函數最小化了。如果你想要最小化的函數是訓練集函數又如何呢?不管你有什么訓練數據,當你訓練神經網絡時,訓練數據會改變,那么如何把訓練數據加入TensorFlow程序呢?
我會定義,把它想做扮演訓練數據的角色,事實上訓練數據有和,但這個例子中只有,把定義為:
x = tf.placeholder(tf.float32,[3,1]),讓它成為數組,我要做的就是,因為這個二次方程的三項前有固定的系數,它是,我們可以把這些數字1,-10和25變成數據,我要做的就是把替換成:
cost = x[0][0]*w**2 +x[1][0]*w + x[2][0],現在變成了控制這個二次函數系數的數據,這個placeholder函數告訴TensorFlow,你稍后會為提供數值。
讓我們再定義一個數組,coefficient = np.array([[1.],[-10.],[25.]]),這就是我們要接入的數據。最后我們需要用某種方式把這個系數數組接入變量,做到這一點的句法是,在訓練這一步中,要提供給的數值,我在這里設置:
feed_dict = {x:coefficients}
好了,希望沒有語法錯誤,我們重新運行它,希望得到和之前一樣的結果。
現在如果你想改變這個二次函數的系數,假設你把:
coefficient = np.array([[1.],[-10.],[25.]])
改為:coefficient = np.array([[1.],[-20.],[100.]])
現在這個函數就變成了,如果我重新運行,希望我得到的使最小化的值為10,讓我們看一下,很好,在梯度下降1000次迭代之后,我們得到接近10的。
在你做編程練習時,見到更多的是,TensorFlow中的placeholder是一個你之后會賦值的變量,這種方式便于把訓練數據加入損失方程,把數據加入損失方程用的是這個句法,當你運行訓練迭代,用feed_dict來讓x=coefficients。如果你在做mini-batch梯度下降,在每次迭代時,你需要插入不同的mini-batch,那么每次迭代,你就用feed_dict來喂入訓練集的不同子集,把不同的mini-batch喂入損失函數需要數據的地方。
希望這讓你了解了TensorFlow能做什么,讓它如此強大的是,你只需說明如何計算損失函數,它就能求導,而且用一兩行代碼就能運用梯度優化器,Adam優化器或者其他優化器。
這還是剛才的代碼,我稍微整理了一下,盡管這些函數或變量看上去有點神秘,但你在做編程練習時多練習幾次就會熟悉起來了。
還有最后一點我想提一下,這三行(藍色大括號部分)在TensorFlow里是符合表達習慣的,有些程序員會用這種形式來替代,作用基本上是一樣的。
但這個with結構也會在很多TensorFlow程序中用到,它的意思基本上和左邊的相同,但是Python中的with命令更方便清理,以防在執行這個內循環時出現錯誤或例外。所以你也會在編程練習中看到這種寫法。那么這個代碼到底做了什么呢?讓我們看這個等式:
cost =x[0][0]*w**2 +x[1][0]*w + x[2][0]#(w-5)**2
TensorFlow程序的核心是計算損失函數,然后TensorFlow自動計算出導數,以及如何最小化損失,因此這個等式或者這行代碼所做的就是讓TensorFlow建立計算圖,計算圖所做的就是取,取,然后將它平方,然后和相乘,你就得到了,以此類推,最終整個建立起來計算,最后你得到了損失函數。
TensorFlow的優點在于,通過用這個計算損失,計算圖基本實現前向傳播,TensorFlow已經內置了所有必要的反向函數,回憶一下訓練深度神經網絡時的一組前向函數和一組反向函數,而像TensorFlow之類的編程框架已經內置了必要的反向函數,這也是為什么通過內置函數來計算前向函數,它也能自動用反向函數來實現反向傳播,即便函數非常復雜,再幫你計算導數,這就是為什么你不需要明確實現反向傳播,這是編程框架能幫你變得高效的原因之一。
如果你看TensorFlow的使用說明,我只是指出TensorFlow的說明用了一套和我不太一樣的符號來畫計算圖,它用了,,然后它不是寫出值,想這里的,TensorFlow使用說明傾向于只寫運算符,所以這里就是平方運算,而這兩者一起指向乘法運算,以此類推,然后在最后的節點,我猜應該是一個將加上去得到最終值的加法運算。
為本課程起見,我認為計算圖用第一種方式會更容易理解,但是如果你去看TensorFlow的使用說明,如果你看到說明里的計算圖,你會看到另一種表示方式,節點都用運算來標記而不是值,但這兩種呈現方式表達的是同樣的計算圖。
在編程框架中你可以用一行代碼做很多事情,例如,你不想用梯度下降法,而是想用Adam優化器,你只要改變這行代碼,就能很快換掉它,換成更好的優化算法。所有現代深度學習編程框架都支持這樣的功能,讓你很容易就能編寫復雜的神經網絡。
我希望我幫助你了解了TensorFlow程序典型的結構,概括一下這周的內容,你學習了如何系統化地組織超參數搜索過程,我們還講了Batch歸一化,以及如何用它來加速神經網絡的訓練,最后我們講了深度學習的編程框架,有很多很棒的編程框架,這最后一個視頻我們重點講了TensorFlow。有了它,我希望你享受這周的編程練習,幫助你更熟悉這些概念。
參考資料
[1]
深度學習課程:?https://mooc.study.163.com/university/deeplearning_ai
[2]黃海廣:?https://github.com/fengdu78
[3]github:?https://github.com/fengdu78/deeplearning_ai_books
總結
以上是生活随笔為你收集整理的深度学习笔记第二门课 改善深层神经网络 第三周 超参数调试、Batch正则化和程序框架...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习笔记第一门课第一周:深度学习引言
- 下一篇: 深度学习笔记第二门课 改善深层神经网络