翟高粵 高乾龍
摘 要:本文先介紹深層神經(jīng)網(wǎng)絡(luò)模型特點(diǎn)和應(yīng)用,并指出其隨著層數(shù)的加深發(fā)展的瓶頸及不足之處;然后引入深度殘差網(wǎng)絡(luò)的概念,以其實(shí)現(xiàn)代碼為例,詳細(xì)介紹深度殘差神經(jīng)網(wǎng)絡(luò)的關(guān)鍵技術(shù)特點(diǎn),最后通過一個實(shí)例說明深度殘差神經(jīng)網(wǎng)絡(luò)在深度學(xué)習(xí)方面的應(yīng)用。
關(guān)鍵詞:深度學(xué)習(xí);殘差網(wǎng)絡(luò);梯度彌散;梯度爆炸
自2012年AlexNet的提出以來,各種各樣的深度卷積神經(jīng)網(wǎng)絡(luò)模型相繼被提出,其中比較有代表性的有VGG系列,GoogLeNet系列等,它們的網(wǎng)絡(luò)層數(shù)整體趨勢逐漸增多。以網(wǎng)絡(luò)模型在ILSVRC 挑戰(zhàn)賽ImageNet數(shù)據(jù)集上面的分類性能表現(xiàn)為例,在AlexNet出現(xiàn)之前的網(wǎng)絡(luò)模型都是淺層的神經(jīng)網(wǎng)絡(luò),Top-5錯誤率均在25%以上,AlexNet 8層的深層神經(jīng)網(wǎng)絡(luò)將Top-5錯誤率降低至16.4%,性能提升巨大,后續(xù)的VGG、GoogleNet模型繼續(xù)將錯誤率降低至6.7%。
AlexNet、VGG、GoogLeNet等網(wǎng)絡(luò)模型的出現(xiàn)將神經(jīng)網(wǎng)絡(luò)的發(fā)展帶入了幾十層的階段,研究人員發(fā)現(xiàn)網(wǎng)絡(luò)的層數(shù)越深,越有可能獲得更好的泛化能力。但是當(dāng)模型加深以后,網(wǎng)絡(luò)變得越來越難訓(xùn)練,這主要是由于梯度彌散和梯度爆炸現(xiàn)象造成的。在較深層數(shù)的神經(jīng)網(wǎng)絡(luò)中,梯度信息由網(wǎng)絡(luò)的末層逐層傳向網(wǎng)絡(luò)的首層時,傳遞的過程中會出現(xiàn)梯度接近于0 或梯度值非常大的現(xiàn)象。網(wǎng)絡(luò)層數(shù)越深,這種現(xiàn)象可能會越嚴(yán)重。
一、深度殘差網(wǎng)絡(luò)簡介
針對上述問題,如何解決由于層數(shù)加深而引起的梯度彌散和梯度爆炸的現(xiàn)象?一個很自然的想法是,既然淺層神經(jīng)網(wǎng)絡(luò)不容易出現(xiàn)這些梯度現(xiàn)象,那么可以嘗試給深層神經(jīng)網(wǎng)絡(luò)添加一種回退到淺層神經(jīng)網(wǎng)絡(luò)的機(jī)制。當(dāng)深層神經(jīng)網(wǎng)絡(luò)可以輕松地回退到淺層神經(jīng)網(wǎng)絡(luò)時,深層神經(jīng)網(wǎng)絡(luò)可以獲得與淺層神經(jīng)網(wǎng)絡(luò)相當(dāng)?shù)哪P托阅?,而不至于更糟糕。通過在輸入和輸出之間添加一條直接連接的Skip Connection可以讓神經(jīng)網(wǎng)絡(luò)具有回退的能力。以 VGG13深度神經(jīng)網(wǎng)絡(luò)為例,假設(shè)觀察到VGG13模型出現(xiàn)梯度彌散現(xiàn)象,而10層的網(wǎng)絡(luò)模型并沒有觀測到梯度彌散現(xiàn)象,那么可以考慮在最后的兩個卷積層添加Skip Connection。通過這種方式,網(wǎng)絡(luò)模型可以自動選擇是否經(jīng)由這兩個卷積層完成特征變換,還是直接跳過這兩個卷積層而選擇Skip Connection,亦或結(jié)合兩個卷積層和Skip Connection的輸出。這就是深度殘差網(wǎng)絡(luò)的由來。
2015年,微軟亞洲研究院何凱明等人發(fā)表了基于Skip Connection 的深度殘差網(wǎng)絡(luò)(Residual Neural Network,簡稱ResNet)算法,并提出了18層、34層、50層、101層、152 層的ResNet-18、ResNet-34、ResNet-50、ResNet-101和ResNet-152等模型,甚至成功訓(xùn)練出層數(shù)達(dá)到1202層的極深層神經(jīng)網(wǎng)絡(luò)。
二、深度殘差網(wǎng)絡(luò)原理
一般來說,網(wǎng)絡(luò)層數(shù)越深,就可以越好的擬合出真實(shí)的函數(shù)。然而,在網(wǎng)絡(luò)深度較深時,由于梯度消失,網(wǎng)絡(luò)的性能反而變差。殘差網(wǎng)絡(luò)很好的解決了梯度消失問題。殘差網(wǎng)絡(luò)的主要思想是通過恒等映射,保證深層的效果不弱于淺層。
殘差網(wǎng)絡(luò)借鑒了高速網(wǎng)絡(luò)(Highway Network)的跨層鏈接思想,但對其進(jìn)行改進(jìn)(殘差項(xiàng)原本是帶權(quán)值的,但ResNet用恒等映射代替之)。假定某段神經(jīng)網(wǎng)絡(luò)的輸入是x,期望輸出是H(x),即H(x)是期望的復(fù)雜潛在映射,如果是要學(xué)習(xí)這樣的模型,則訓(xùn)練難度會比較大;回想前面的假設(shè),如果已經(jīng)學(xué)習(xí)到較飽和的準(zhǔn)確率(或者當(dāng)發(fā)現(xiàn)下層的誤差變大時),那么接下來的學(xué)習(xí)目標(biāo)就轉(zhuǎn)變?yōu)楹愕扔成涞膶W(xué)習(xí),也就是使輸入x近似于輸出H(x),以保持在后面的層次中不會造成精度下降。在殘差網(wǎng)絡(luò)結(jié)構(gòu)圖中,通過shortcut connections(捷徑連接)的方式,直接把輸入x傳到輸出作為初始結(jié)果,輸出結(jié)果為H(x)=F(x)+x,當(dāng)F(x)=0時,那么H(x)=x,也就是上面所提到的恒等映射。于是,ResNet相當(dāng)于將學(xué)習(xí)目標(biāo)改變了,不再是學(xué)習(xí)一個完整的輸出,而是目標(biāo)值H(X)和x的差值,也就是所謂的殘差F(x) = H(x)-x,因此,后面的訓(xùn)練目標(biāo)就是要將殘差結(jié)果逼近于0,使到隨著網(wǎng)絡(luò)加深,準(zhǔn)確率不下降。
這種殘差跳躍式的結(jié)構(gòu),打破了傳統(tǒng)的神經(jīng)網(wǎng)絡(luò)n-1層的輸出只能給n層作為輸入的慣例,使某一層的輸出可以直接跨過幾層作為后面某一層的輸入,其意義在于為疊加多層網(wǎng)絡(luò)而使得整個學(xué)習(xí)模型的錯誤率不降反升的難題提供了新的方向。
至此,神經(jīng)網(wǎng)絡(luò)的層數(shù)可以超越之前的約束,達(dá)到幾十層、上百層甚至千層,為高級語義特征提取和分類提供了可行性。
三、深度殘差網(wǎng)絡(luò)Python代碼實(shí)現(xiàn)
深度殘差網(wǎng)絡(luò)并沒有增加新的網(wǎng)絡(luò)層類型,只是通過在輸入和輸出之間添加一條 Skip Connection,因此并沒有針對ResNet的底層實(shí)現(xiàn)。在TensorFlow中通過調(diào)用普通卷積層即可實(shí)現(xiàn)殘差模塊。
首先創(chuàng)建一個新類,在初始化階段創(chuàng)建殘差塊中需要的卷積層、激活函數(shù)層等,首先新建卷積層,主要代碼如下:
class BasicBlock(layers.Layer):
# 殘差模塊類
def __init__(self, filter_num, stride=1):
super(BasicBlock, self).__init__()
# f(x)包含了2個普通卷積層,創(chuàng)建卷積層1
self.conv1 = layers.Conv2D(filter_num, (3, 3), strides=stride, padding='same')
self.bn1 = layers.BatchNormalization()
self.relu = layers.Activation('relu')
# 創(chuàng)建卷積層2
self.conv2 = layers.Conv2D(filter_num, (3, 3), strides=1, padding='same')
self.bn2 = layers.BatchNormalization()
? ?當(dāng)F(x)的形狀與x不同時,無法直接相加,我們需要新建identity(x)卷積層,來完成x的形狀轉(zhuǎn)換。緊跟上面代碼,實(shí)現(xiàn)如下:
if stride != 1: # 插入 identity 層
self.downsample = Sequential()
self.downsample.add(layers.Conv2D(filter_num, (1, 1), strides=stride))
else: # 否則,直接連接
self.downsample = lambda x:x
在前向傳播時,只需要將F(x)與identity(x)相加,并添加ReLU激活函數(shù)即可。前向計(jì)算函數(shù)代碼如下:
def call(self, inputs, training=None):
# 前向傳播函數(shù)
out = self.conv1(inputs) #通過第一個卷積層
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out) #通過第二個卷積層
out = self.bn2(out)
# 輸入通過 identity()轉(zhuǎn)換
identity = self.downsample(inputs)
# f(x)+x 運(yùn)算
output = layers.add([out, identity])
# 再通過激活函數(shù)并返回
output = tf.nn.relu(output)
return output
代碼原理圖如圖1所示。
圖1 深度殘差網(wǎng)絡(luò)實(shí)現(xiàn)原理
四、總結(jié)
殘差網(wǎng)絡(luò)結(jié)構(gòu)簡單,解決了極深度條件下深度卷積神經(jīng)網(wǎng)絡(luò)性能退化的問題,分類性能表現(xiàn)出色。本文先通過例子說明非常深的網(wǎng)絡(luò)很難訓(xùn)練,存在梯度消失和梯度爆炸問題,學(xué)習(xí) skip connection它可以從某一層獲得激活,然后迅速反饋給另外一層甚至更深層,利用 skip connection可以構(gòu)建殘差網(wǎng)絡(luò)ResNet來訓(xùn)練更深的網(wǎng)絡(luò),ResNet網(wǎng)絡(luò)是由殘差模塊構(gòu)建的。這種方式能夠到達(dá)網(wǎng)絡(luò)更深層,有助于解決梯度消失和梯度爆炸的問題,讓我們訓(xùn)練更深網(wǎng)絡(luò)同時又能保證良好的性能。
參考文獻(xiàn):
[1] 劉航等.基于深度殘差網(wǎng)絡(luò)的麥穗回歸計(jì)數(shù)方法[J],中國農(nóng)業(yè)大學(xué)學(xué)報,2021(4).
[2] 張宇等.融入注意力機(jī)制的深度學(xué)習(xí)動作識別方法[J],電訊技術(shù),2021(4).
[3] 閆濤. 深度學(xué)習(xí)算法實(shí)踐 [M]. 電子工業(yè)出版社出版社,2020.
[4] 王宇石等.一種基于卷積神經(jīng)網(wǎng)絡(luò)的違禁品探測系統(tǒng)及部署方法[J],科技創(chuàng)新與應(yīng)用,2020(7).