2.1. 基本結(jié)構(gòu)
CNN全名叫卷積神經(jīng)網(wǎng)絡(luò)猴鲫,主要的模型結(jié)構(gòu)有卷積敷燎、池化、激活三個組成部分澄惊。下面分塊來介紹每個部分都做了什么唆途,為什么要這么做。
2.2. 卷積層
卷積層中最重要的概念是卷積核掸驱,卷積核可以理解為是一種特征肛搬,將輸入和卷積核相乘得到的結(jié)果就是輸入在這個特征上的投影,這個投影可以稱之為特征圖毕贼。特征要怎么理解呢温赔?以圖像識別為例,假設(shè)有一個特征表示物體的輪廓鬼癣,將輸入的圖像和這個特征相乘得到的就是圖像的輪廓圖陶贼。卷積過程如下圖所示啤贩。
針對圖像的卷積過程,一般來說圖像形狀為(batch_size, height, width, channel)拜秧,卷積核的形狀為(m,n)瓜晤,這里的m、n對應(yīng)的維度是其中的高度和寬度腹纳,m和n可以相等也可以不等痢掠。自然語言處理也可以使用卷積網(wǎng)絡(luò),一般來說語言輸入的形狀為(batch_size, length, embedding_size)嘲恍,語言一般來說只有一個通道足画,由于tensorflow的卷積api一般只接受四維的向量,因此需要在末尾擴(kuò)充一維向量變成(batch_size, length, embedding_size, 1)佃牛,這里對應(yīng)的卷積核形狀為(m,embedding_size)淹辞,embedding_size代表的是詞向量大小,是一個整體俘侠,一般不會拆開來卷積象缀。m對應(yīng)的是length也就是句子長度。
還有兩個參數(shù)比較常見爷速,第一個是stride央星,就是卷積核前進(jìn)的步長,同樣可以對應(yīng)高度和寬度上兩個步長惫东,如果stride只設(shè)置一個數(shù)字莉给,那么表示高度和寬度上步長一致。第二個是卷積是否padding廉沮,如果padding的話可以保持前后形狀一致颓遏。
卷積層參數(shù)計算:假設(shè)卷積核形狀為(m,n)滞时,共有p個卷積核叁幢,那么卷積過程中涉及到的參數(shù)量為m×n×p
2.3. 池化層
如上圖所示就是一個典型的池化過程,常見的池化有最大值池化和平均池化兩種坪稽,顧名思義就是在池化窗口內(nèi)計算最大值和平均值作為池化結(jié)果曼玩。值得一提的是,tensorflow的池化接口參數(shù)都是四維的刽漂,例如這個窗口的大小為(1演训,m弟孟,n贝咙,1),分別對應(yīng)的是NHWC(batch_size, height, width, channel)四個維度拂募,步長stride也是一樣庭猩。
池化層有什么作用呢窟她?一般來說至少有一下三個作用:
特征不變形:池化操作是模型更加關(guān)注是否存在某些特征而不是特征具體的位置,也就是說模型對于位置的敏感性下降了蔼水,換言之也就是說那些需要對位置敏感的任務(wù)震糖,比如圖片分區(qū)不適合使用池化操作。
特征降維:池化相當(dāng)于在空間范圍內(nèi)做了維度約減趴腋,從而使模型可以抽取更加廣范圍的特征吊说。同時減小了下一層的輸入大小,進(jìn)而減少計算量和參數(shù)個數(shù)优炬。
在一定程度上防止過擬合颁井,更方便優(yōu)化。
2.4. 激活層
激活層使用的函數(shù)叫做非線性激活函數(shù)蠢护,這里面有兩個關(guān)鍵字雅宾,非線性和激活。之所以使用非線性函數(shù)是因為如果使用線性函數(shù)葵硕,那么不管幾層的網(wǎng)絡(luò)也等價于單層的網(wǎng)絡(luò)眉抬,都是線性組合。而這層之所以會被稱為激活層的原因是激活函數(shù)模仿了人類對神經(jīng)信號的有選擇反應(yīng)懈凹。常見的激活函數(shù)有sigmoid蜀变,tanh,relu等介评。
2.5. BN層
BN層不是卷積網(wǎng)絡(luò)的標(biāo)配昏苏,但因為效果太好,不僅大大加快收斂速度威沫,模型性能也可以好上不少贤惯,因此在這里介紹一下。
我們在訓(xùn)練集上訓(xùn)練的模型之所以可以應(yīng)用于測試集棒掠,是因為一個前提假設(shè):訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)獨立同分布孵构。BatchNorm的作用簡單來說就是在深度神經(jīng)網(wǎng)絡(luò)訓(xùn)練過程中使得每一層神經(jīng)網(wǎng)絡(luò)的輸入保持相同分布的。
深層神經(jīng)網(wǎng)絡(luò)在進(jìn)入激活函數(shù)前的激活輸入值烟很,隨著網(wǎng)絡(luò)深度加深颈墅,分布逐漸往激活函數(shù)的兩端靠近,導(dǎo)致反向傳播是梯度消失雾袱,因此會出現(xiàn)訓(xùn)練效率越來越低的情況恤筛。BN做的事情就是把這個激活輸入值轉(zhuǎn)成標(biāo)準(zhǔn)正態(tài)分布,這樣就可以避免梯度消失的問題芹橡。但是這樣會造成另一個問題毒坛,如果所有的輸入都經(jīng)過標(biāo)準(zhǔn)正態(tài)化,那非線性變換帶來的對非線性關(guān)系的擬合效果就消失了,因此提出BN的作者為了保證非線性的獲得煎殷,對標(biāo)準(zhǔn)正態(tài)化后的輸入又進(jìn)行了scale加上shift操作(y=scale*x+shift)屯伞,這是把輸入分布變胖變瘦或者左右移動一下,核心是想找到非線性和線性表達(dá)的平衡點豪直,作者認(rèn)為這是BN層效果好最大的原因劣摇。這里有一個小小的爭議,MIT研究人員在論文How Does Batch Normalizetion Help Optimization認(rèn)為bn之所以有效不是因為改變了分布弓乙。該論文認(rèn)為bn之所以可以達(dá)到1末融、收斂更快2、對學(xué)習(xí)率不敏感的效果是因為經(jīng)過bn之后的loss函數(shù)變得比較平滑暇韧,論文通過計算loss的一階導(dǎo)數(shù)和二階導(dǎo)數(shù)從側(cè)面證明了這一點滑潘。
在實際使用時,我們要告訴batch normlization是在訓(xùn)練還是預(yù)測過程锨咙。為什么语卤?因為在預(yù)測階段,輸入可能只有一個實例酪刀,沒有辦法做標(biāo)準(zhǔn)化粹舵,這個時候就可以使用之前記錄下來的整體均值和方差來做標(biāo)準(zhǔn)化。
使用tensorflow的bn層有一個很大的坑需要重點關(guān)注骂倘,在使用 tf.layers.batch_normalization (input, training=is_traing)時眼滤,訓(xùn)練階段可以整個batch一起做歸一化處理,在預(yù)測階段(使用之前記錄下來的整體均值和方差來做標(biāo)準(zhǔn)化历涝。)诅需,這個記錄的參數(shù)需要更新,但是上面使用的這個層不會自動更新參數(shù)荧库。因此在計算梯度前需要with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS))來獲取最新的數(shù)據(jù)堰塌,否則預(yù)測階段會發(fā)現(xiàn)參數(shù)一直處于初始狀態(tài)。