AI佳作解讀系列(一)——深度學習模型訓練痛點及解決方法


1 模型訓練基本步驟

進入了AI領域,學習了手寫字識別等幾個demo后,就會發現深度學習模型訓練是十分關鍵和有挑戰性的。選定了網絡結構后,深度學習訓練過程基本大同小異,一般分為如下幾個步驟

  1. 定義算法公式,也就是神經網絡的前向算法。我們一般使用現成的網絡,如inceptionV4,mobilenet等。
  2. 定義loss,選擇優化器,來讓loss最小
  3. 對數據進行迭代訓練,使loss到達最小
  4. 在測試集或者驗證集上對准確率進行評估

下面我們來看深度學習模型訓練中遇到的難點及如何解決

2 模型訓練難點及解決方法

2.1 收斂速度慢

深度學習其實就是一個反復調整模型參數的過程,得力於GPU等硬件性能的提升,使得復雜的深度學習訓練成為了可能。收斂速度過慢,訓練時間過長,一方面使得相同總訓練時間內的迭代次數變少,從而影響准確率,另一方面使得訓練次數變少,從而減少了嘗試不同超參數的機會。因此,加快收斂速度是一大痛點。那么怎么解決它呢?

2.1.1 設置合理的初始化權重w和偏置b

深度學習通過前向計算和反向傳播,不斷調整參數,來提取最優特征,以達到預測的目的。其中調整的參數就是weight和bias,簡寫為w和b。根據奧卡姆剃刀法則,模型越簡單越好,我們以線性函數這種最簡單的表達式來提取特征,也就是

​ f(x) = w * x + b

深度學習訓練時幾乎所有的工作量都是來求解神經網絡中的w和b。模型訓練本質上就是調整w和b的過程,如果將他們初始化為一個合理的值,那么就能夠加快收斂速度。怎么初始化w和b呢?

我們一般使用截斷的正態分布(也叫高斯分布)來初始化w。如下

# 權重weight,標准差0.1。truncated_normal截斷的正態分布來初始化weight。權重初始化很有講究的,會決定學習的快慢 def weight_variable(shape, vname): initial = tf.truncated_normal(shape, stddev=0.1, name=vname) return tf.Variable(initial)

tf.truncated_normal定義如下

tf.truncated_normal(
    shape,            # 正態分布輸出數據結構,1維tensor mean=0.0, # 平均值,默認為0.我們一般取默認值0 stddev=1.0, # 標准差 dtype=tf.float32, # 輸出數據類型 seed=None, # 隨機分布都會有一個seed來決定分布 name=None )

什么叫截斷的正態分布呢,看下圖就明白了

左圖為標准正態分布,也叫高斯分布,利用TensorFlow中的tf.random_normal()即可得到x取值范圍負無窮到正無窮內的值。所有的y值加起來概率為1。初始化w時,我們沒必要將w初始化為很大或很小的數。故更傾向於使用截斷正態分布,如右圖。它和標准正態分布的區別在於,限制了x取值必須在[-2 x stddev, 2 x stddev]之間。

b由於是加和關系,對收斂速度影響不大。我們一般將它初始化為0,如下。

# 偏置量bias,初始化為0,偏置可直接使用常量初始化 def bias_variable(shape, vname): initial = tf.constant(0, shape=shape, name=vname) return tf.Variable(initial)

2.1.2 優化學習率

模型訓練就是不斷嘗試和調整不同的w和b,那么每次調整的幅度是多少呢,這個就是學習率。w和b是在一定范圍內調整的,那么增大學習率不就減少了迭代次數,也就加快了訓練速度了嗎?路雖長,步子邁大點不就行了嗎?非也,步子邁大了可是會扯到蛋的!深度學習中也是如此,學習率太小,會增加迭代次數,加大訓練時間。但學習率太大,容易越過局部最優點,降低准確率。

那有沒有兩全的解決方法呢,有!我們可以一開始學習率大一些,從而加速收斂。訓練后期學習率小一點,從而穩定的落入局部最優解。使用Adam,Adagrad等自適應優化算法,就可以實現學習率的自適應調整,從而保證准確率的同時加快收斂速度。

如上圖所示,隨着迭代次數的增加,學習率從0.1逐步衰減為0.02以下。

2.1.3 網絡節點輸入值正則化 batch normalization

神經網絡訓練時,每一層的輸入分布都在變化。不論輸入值大還是小,我們的學習率都是相同的,這顯然是很浪費效率的。而且當輸入值很小時,為了保證對它的精細調整,學習率不能設置太大。那有沒有辦法讓輸入值標准化得落到某一個范圍內,比如[0, 1]之間呢,這樣我們就再也不必為太小的輸入值而發愁了。

辦法當然是有的,那就是正則化!由於我們學習的是輸入的特征分布,而不是它的絕對值,故可以對每一個mini-batch數據內部進行標准化,使他們規范化到[0, 1]內。這就是Batch Normalization,簡稱BN。由大名鼎鼎的inception V2提出。它在每個卷積層后,使用一個BN層,從而使得學習率可以設定為一個較大的值。使用了BN的inceptionV2,只需要以前的1/14的迭代次數就可以達到之前的准確率,大大加快了收斂速度。

2.1.4 采用更先進的網絡結構,減少參數量

訓練速度慢,歸根結底還是網絡結構的參數量過多導致的。減少參數量,可以大大加快收斂速度。采用先進的網絡結構,可以用更少的參數量達到更高的精度。如inceptionV1參數量僅僅為500萬,是AlexNet的1/12, 但top-5准確率卻提高了一倍多。如何使用較少的參數量達到更高的精度,一直是神經網絡結構研究中的難點。目前大致有如下幾種方式

  1. 使用小卷積核來代替大卷積核。VGGNet全部使用3x3的小卷積核,來代替AlexNet中11x11和5x5等大卷積核。小卷積核雖然參數量較少,但也會帶來特征面積捕獲過小的問題。inception net認為越往后的卷積層,應該捕獲更多更高階的抽象特征。因此它在靠后的卷積層中使用的5x5等大面積的卷積核的比率較高,而在前面幾層卷積中,更多使用的是1x1和3x3的卷積核。
  2. 使用兩個串聯小卷積核來代替一個大卷積核。inceptionV2中創造性的提出了兩個3x3的卷積核代替一個5x5的卷積核。在效果相同的情況下,參數量僅為原先的3x3x2 / 5x5 = 18/25
  3. 1x1卷積核的使用。1x1的卷積核可以說是性價比最高的卷積了,沒有之一。它在參數量為1的情況下,同樣能夠提供線性變換,relu激活,輸入輸出channel變換等功能。VGGNet創造性的提出了1x1的卷積核
  4. 非對稱卷積核的使用。inceptionV3中將一個7x7的卷積拆分成了一個1x7和一個7x1, 卷積效果相同的情況下,大大減少了參數量,同時還提高了卷積的多樣性。
  5. depthwise卷積的使用。mobileNet中將一個3x3的卷積拆分成了串聯的一個3x3 depthwise卷積和一個1x1正常卷積。對於輸入channel為M,輸出為N的卷積,正常情況下,每個輸出channel均需要M個卷積核對輸入的每個channel進行卷積,並疊加。也就是需要MxN個卷積核。而在depthwise卷積中,輸出channel和輸入相同,每個輸入channel僅需要一個卷積核。而將channel變換的工作交給了1x1的卷積。這個方法在參數量減少到之前1/9的情況下,精度仍然能達到80%。
  6. 全局平均池化代替全連接層。這個才是大殺器!AlexNet和VGGNet中,全連接層幾乎占據了90%的參數量。inceptionV1創造性的使用全局平均池化來代替最后的全連接層,使得其在網絡結構更深的情況下(22層,AlexNet僅8層),參數量只有500萬,僅為AlexNet的1/12

網絡結構的推陳出新,先進設計思想的不斷提出,使得減少參數量的同時提高准確度變為了現實。

2.1.5 使用GPU並行計算

深度學習模型訓練,基本由卷積計算和矩陣乘法構成,他們都很適合並行計算。使用多塊GPU並行加速已經成為了深度學習的主流,可以大大加快收斂速度。要達到相同的精度,50塊GPU需要的時間僅為10塊的1/4左右。當前Google早已開始了TPU這種專門用於深度學習的Asic芯片的研究,國內的寒武紀等公司也在大張旗鼓的研究專用於AI的芯片。AI芯片的前景也是十分廣闊的。

2.2 線性模型的局限性

根據奧卡姆剃刀法則,我們使用了最簡單的線性模型,也就是wx+b,來表征了神經網絡。線性模型的特點是,任意線性模型的組合仍然是線性模型。不論我們采用如何復雜的神經網絡,它仍然是一個線性模型。然而線性模型能夠解決的問題畢竟是有限的,所以必須在神經網絡中增加一些非線性元素。

2.2.1 激活函數的使用

在每個卷積后,加入一個激活函數,已經是通用的做法,相信大家都知道。激活函數,如relu,tanh,sigmod都是非線性函數,一方面可以增加模型的非線性元素,另一方面可以降低梯度彌散問題(我們后面詳細講解)。目前使用較多的就是relu函數。他模擬了生物學上的閾值響應機制,利用人腦只對大於某個值的信號才產生響應的機制,提出了單側抑制的理念。它的表達式很簡單,f(x)=max(0,x)。當x>0時,y=x, x<0時,y=0. 如下圖所示。

相比於tanh和sigmod,relu的優點有:

  1. 計算速度快,容易收斂。relu就是一個取max的函數,沒有復雜的運算,故計算速度很快。相比於tanh,收斂速度可加快6倍
  2. 梯度不會大幅縮小。x>0時,relu的梯度為1(梯度還不懂是啥意思的同學最好翻下數學書,梯度簡單理解就是偏導數),故相比sigmod這種x稍微遠離0,梯度就會大幅減小的函數,不會使得梯度縮小,從而引發多層傳播后的梯度彌散問題。

2.2.2 兩個小卷積核的疊加代替一個大卷積核

激活函數可是一個增加非線性的大法寶,但我們一般只能在卷積完之后再使用它。那怎么增加它的使用場景呢?增加卷積層不就行了嗎。inception V2創造性的提出了用兩個3x3的卷積核代替一個5x5的卷積核。每次卷積后,都使用一次relu非線性激活。如下圖。

2.2.3 1x1小卷積核的使用

1x1的卷積核應該是性價比最高的卷積,它在參數量為1的情況下,同樣能夠提供線性變換,relu激活,輸入輸出channel變換等功能。inceptionV1利用Network in Network的思想,提出了inception module這一結構,它在每個並行分支的最前面,使用了一個1x1的卷積,卷積后緊跟一個relu激活。從而大大增加了relu的使用率。從而提高了模型的非線性特征。

2.3 過擬合問題

過擬合在機器學習中廣泛存在,指的是經過一定次數的迭代后,模型准確度在訓練集上越來越好,但在測試集上卻越來越差。究其原因,就是模型學習了太多無關特征,將這些特征認為是目標所應該具備的特征。如下圖

如上圖所示,樹葉訓練樣本中邊緣帶有鋸齒,模型學習了鋸齒這一特征,認為樹葉必須帶有鋸齒,從而判定右側的不帶鋸齒的樹葉不是樹葉。這就是典型的過擬合問題。神經網絡中,因為參數眾多,經常出現參數比輸入樣本數據還多的情況,這就導致很容易出現模型只記住了訓練集特征的情況。我們有兩個思路來解決這個問題。一是增大樣本量,另外就是減少特征量。

2.3.1 輸入增強,增大樣本量

收集更多且更全的樣本,能有效降低過擬合。但尋找樣本本來就是一件很費力的事情,我們到哪兒去尋找更多更全的樣本呢。素材整理和數據獲取成為了深度學習的一大瓶頸,否則再牛逼的神經網絡結構,也會稱為無米之炊。這也是當前遷移學習變得比較火熱的一大原因(這是后話,就不詳細展開了)。那我們有沒有辦法簡單快捷的增加樣本量呢?

答案是有的,可以使用輸入增強方法。對樣本進行旋轉,裁剪,加入隨機噪聲等方式,可以大大增加樣本數量和泛化性。目前TensorFlow就提供了大量方法進行數據增強,大大方便了我們增加樣本數量。

2.3.2 dropout,減少特征量

使用dropout,將神經網絡某一層的輸出節點數據隨機丟棄,從而減少特征量。這其實相當於創造了很多新的隨機樣本。我們可以理解為這是對特征的一次采樣。一般在神經網絡的全連接層使用dropout。

2.4 梯度彌散, 無法使用更深的網絡

深度學習利用正向傳播來提取特征,同時利用反向傳播來調整參數。反向傳播中梯度值逐漸減小,神經網絡層數較多時,傳播到前面幾層時,梯度接近於0,無法對參數做出指導性調整了,此時基本起不到訓練作用。這就稱為梯度彌散。梯度彌散使得模型網絡深度不能太大,但我們都知道網絡越深,提取的特征越高階,泛化性越好。因此優化梯度彌散問題就很重要了

2.4.1 relu代替sigmoid激活函數

sigmoid函數值在[0,1],ReLU函數值在[0,+無窮]。relu函數,x>0時的導數為1, 而sigmoid函數,當x稍微遠離0,梯度就會大幅減小,幾乎接近於0,所以在反向傳播中無法指導參數更新。

2.4.2 殘差網絡

大名鼎鼎的resNet將一部分輸入值不經過正向傳播網絡,而直接作用到輸出中。這樣可以提高原始信息的完整性了,從而在反向傳播中,可以指導前面幾層的參數的調整了。如下圖所示。

使用了殘差網絡的resNet,將網絡深度提高到了152層,大大提高了模型的泛化性,從而提高了預測准確率,並一舉問鼎當年的imageNet冠軍!

3 總結

深度學習模型訓練是一個很費時間,但也很有技巧的過程。模型訓練中有梯度彌散,過擬合等各種痛點,正是為了解決這些問題,不斷涌現出了各種設計精巧的網絡結構。學習時,我們不僅要學習網絡結構的設計方式,還要掌握它們的設計思想,了解它們是為了解決哪些問題而產生的,以及准確率和性能為何能夠得到提升。

 

 

本文主體內容參考鏈接:https://yq.aliyun.com/articles/598429?spm=a2c4e.11153940.blogrightarea598428.36.640a783bV593ki


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM