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