深入淺出Tensorflow(四):卷積神經網路
作者 | 鄭澤宇
AI前線出品| ID:ai-front
2017年2月16日,Google正式對外發布Google TensorFlow 1.0版本,並保證本次的發布版本API介面完全滿足生產環境穩定性要求。這是TensorFlow的一個重要里程碑,標誌著它可以正式在生產環境放心使用。在國內,從InfoQ的判斷來看,TensorFlow仍處於創新傳播曲線的創新者使用階段,大部分人對於TensorFlow還缺乏了解,社區也缺少幫助落地和使用的中文資料。InfoQ期望通過深入淺出TensorFlow系列文章能夠推動Tensorflow在國內的發展。歡迎加入QQ群(群號:183248479)深入討論和交流。下面為本系列的前三篇文章:
深入淺出Tensorflow(一):深度學習及TensorFlow簡介
深入淺出TensorFlow(二):TensorFlow解決MNIST問題入門
深入淺出Tensorflow(三):訓練神經網路模型的常用方法
卷積神經網路簡介
斯坦福大學(Stanford University)李飛飛(Feifei Li)教授帶頭整理的ImageNet是圖像識別領域非常有名的數據集。在ImageNet中,將近1500萬圖片被關聯到了WordNet的大約20000個名詞同義詞集上。ImageNet每年都舉辦圖像識別相關的競賽(ImageNet Large Scale Visual Recognition Challenge,ILSVRC),其中最有名的就是ILSVRC2012圖像分類數據集。ILSVRC2012圖像分類數據集包含了來自1000個類別的120萬張圖片,其中每張圖片屬於且只屬於一個類別。因為ILSVRC2012圖像分類數據集中的圖片是直接從互聯網上爬取得到的,圖片的大小從幾千位元組到幾百萬位元組不等。
圖1給出了不同演算法在ImageNet圖像分類數據集上的top-5正確率。top-N正確率指的是圖像識別演算法給出前N個答案中有一個是正確的概率。在圖像分類問題上,很多學術論文都將前N個答案的正確率作為比較的方法,其中N的取值一般為3或5。從圖1中可以看出,在ImageNet問題上,基於卷積神經網路的圖像識別演算法可以遠遠超過人類的表現。在圖1的左側對比了傳統演算法與深度學習演算法的正確率。從圖中可以看出,深度學習,特別是卷積神經網路,給圖像識別問題帶來了質的飛躍。2013年之後,基本上所有的研究都集中到了深度學習演算法上。
圖2 全連接神經網路與卷積神經網路結構示意圖
在前面的文章中所介紹的神經網路每兩層之間的所有結點都是有邊相連的,所以我們稱這種網路結構為全連接層網路結構。圖2顯示了全連接神經網路與卷積神經網路的結構對比圖。雖然圖2中顯示的全連接神經網路結構和卷積神經網路的結構直觀上差異比較大,但實際上它們的整體架構是非常相似的。從圖2中可以看出,卷積神經網路也是通過一層一層的節點組織起來的。和全連接神經網路一樣,卷積神經網路中的每一個節點都是一個神經元。在全連接神經網路中,每相鄰兩層之間的節點都有邊相連,於是一般會將每一層全連接層中的節點組織成一列,這樣方便顯示連接結構。而對於卷積神經網路,相鄰兩層之間只有部分節點相連,為了展示每一層神經元的維度,一般會將每一層卷積層的節點組織成一個三維矩陣。
除了結構相似,卷積神經網路的輸入輸出以及訓練流程與全連接神經網路也基本一致。以圖像分類為例,卷積神經網路的輸入層就是圖像的原始像素,而輸出層中的每一個節點代表了不同類別的可信度。這和全連接神經網路的輸入輸出是一致的。在TensorFlow中訓練一個卷積神經網路的流程和訓練一個全連接神經網路沒有任何區別。卷積神經網路和全連接神經網路的唯一區別就在於神經網路中相鄰兩層的連接方式。
使用全連接神經網路處理圖像的最大問題在於全連接層的參數太多。對於MNIST數據,每一張圖片的大小是,其中為圖片的大小,表示圖像是黑白的,只有一個色彩通道。假設第一層隱藏層的節點數為500個,那麼一個全鏈接層的神經網路將有個參數。當圖片更大時,比如在Cifar-10數據集中,圖片的大小為,其中表示圖片的大小,表示圖片是通過紅綠藍三個色彩通道(channel)表示的。這樣輸入層就有3072個節點,如果第一層全連接層仍然是500個節點,那麼這一層全鏈接神經網路將有個參數。參數增多除了導致計算速度減慢,還很容易導致過擬合問題。所以需要一個更合理的神經網路結構來有效地減少神經網路中參數個數。卷積神經網路就可以達到這個目的。
圖3給出了一個更加具體的卷積神經網路架構圖。在卷積神經網路的前幾層中,每一層的節點都被組織成一個三維矩陣。比如處理Cifar-10數據集中的圖片時,可以將輸入層組織成一個的三維矩陣。圖3中虛線部分展示了卷積神經網路的一個連接示意圖,從圖中可以看出卷積神經網路中前幾層中每一個節點只和上一層中部分的節點相連。卷積神經網路的具體連接方式將在下文中介紹。
卷積層網路結構
圖4中顯示了卷積層神經網路結構中最重要的部分,這個部分被稱之為過濾器(filter)或者內核(kernel)。因為TensorFlow文檔中將這個結構稱之為過濾器(filter),所以我們將統稱這個結構為過濾器。如圖4所示,過濾器可以將當前層神經網路上的一個子節點矩陣轉化為下一層神經網路上的一個單位節點矩陣。單位節點矩陣指的是一個長和寬都為1,但深度不限的節點矩陣。
在一個卷積層中,過濾器所處理的節點矩陣的長和寬都是由人工指定的,這個節點矩陣的尺寸也被稱之為過濾器的尺寸。常用的過濾器尺寸有3×3或5×5。因為過濾器處理的矩陣深度和當前層神經網路節點矩陣的深度是一致的,所以雖然節點矩陣是三維的,但過濾器的尺寸只需要指定兩個維度。過濾器中另外一個需要人工指定的設置是處理得到的單位節點矩陣的深度,這個設置稱為過濾器的深度。注意過濾器的尺寸指的是一個過濾器輸入節點矩陣的大小,而深度指的是輸出單位節點矩陣的深度。如圖4所示,左側小矩陣的尺寸為過濾器的尺寸,而右側單位矩陣的深度為過濾器的深度。
如圖4所示,過濾器的前向傳播過程就是通過左側小矩陣中的節點計算出右側單位矩陣中節點的過程。為了直觀地解釋過濾器的前向傳播過程,在下面的篇幅中將給出一個具體的樣例。在這個樣例中將展示如何通過過濾器將一個2×2×3的節點矩陣變化為一個1×1×5的單位節點矩陣。一個過濾器的前向傳播過程和全連接層相似,它總共需要個參數,其中最後的+5為偏置項參數的個數。假設使用來表示對於輸出單位節點矩陣中的第i個節點,過濾器輸入節點的權重,使用表示第i個輸出節點對應的偏置項參數,那麼單位矩陣中的第i個節點的取值為:
其中為過濾器中節點的取值,為激活函數。如果將和組織成兩個向量,那麼一個過濾器的計算過程完全可以通過向量乘法來完成。卷積層結構的前向傳播過程就是通過將一個過濾器從神經網路當前層的左上角移動到右下角,並且在移動中計算每一個對應的單位矩陣得到的。圖5展示了卷積層結構前向傳播的過程。為了更好地可視化過濾器的移動過程,圖5中使用的節點矩陣深度都為1。在圖5中,展示了在3×3矩陣上使用2×2過濾器的卷積層前向傳播過程。在這個過程中,首先將這個過濾器用於左上角子矩陣,然後移動到左下角矩陣,再到右上角矩陣,最後到右下角矩陣。過濾器每移動一次,可以計算得到一個值(當深度為k時會計算出k個值)。將這些數值拼接成一個新的矩陣,就完成了卷積層前向傳播的過程。圖5的右側顯示了過濾器在移動過程中計算得到的結果與新矩陣中節點的對應關係。
在圖5中,只講解了移動過濾器的方式,沒有涉及到過濾器中的參數如何設定。在卷積神經網路中,每一個卷積層中使用的過濾器中的參數都是一樣的。這是卷積神經網路一個非常重要的性質。從直觀上理解,共享過濾器的參數可以使得圖像上的內容不受位置的影響。以MNIST手寫體數字識別為例,無論數字「1」出現在左上角還是右下角,圖片的種類都是不變的。因為在左上角和右下角使用的過濾器參數相同,所以通過卷積層之後無論數字在圖像上的哪個位置,得到的結果都一樣。
共享每一個卷積層中過濾器中的參數可以巨幅減少神經網路上的參數。以Cifar-10問題為例,輸入層矩陣的維度是32×32×3。假設第一層卷積層使用尺寸為5×5,深度為16的過濾器,那麼這個卷積層的參數個數為個。上文提到過,使用500個隱藏節點的全連接層將有150萬個參數。相比之下,卷積層的參數個數要遠遠小於全連接層。而且卷積層的參數個數和圖片的大小無關,它只和過濾器的尺寸、深度以及當前層節點矩陣的深度有關。這使得卷積神經網路可以很好地擴展到更大的圖像數據上。
結合過濾器的使用方法和參數共享的機制,圖6給出了使用了全0填充、移動步長為2的卷積層前向傳播的計算流程。下面的公式給出了左上角格子取值的計算方法,其他格子可以依次類推。
ReLu(0×1+0×(-1)+0×0+1×2+1)=ReLu(3)=3
TensorFlow對卷積神經網路提供了非常好的支持,下面的程序實現了一個卷積層的前向傳播過程。從以下代碼可以看出,通過TensorFlow實現卷積層是非常方便的。
池化層網路結構
在卷積神經網路中,卷積層之間往往會加上一個池化層(pooling layer)。池化層可以非常有效地縮小矩陣的尺寸,從而減少最後全連接層中的參數。使用池化層既可以加快計算速度也有防止過擬合問題的作用。和卷積層類似,池化層前向傳播的過程也是通過移動一個類似過濾器的結構完成的。不過池化層過濾器中的計算不是節點的加權和,而是採用更加簡單的最大值或者平均值運算。使用最大值操作的池化層被稱之為最大池化層(max pooling),這是被使用得最多的池化層結構。使用平均值操作的池化層被稱之為平均池化層(average pooling)。
與卷積層的過濾器類似,池化層的過濾器也需要人工設定過濾器的尺寸、是否使用全0填充以及過濾器移動的步長等設置,而且這些設置的意義也是一樣的。卷積層和池化層中過濾器移動的方式是相似的,唯一的區別在於卷積層使用的過濾器是橫跨整個深度的,而池化層使用的過濾器隻影響一個深度上的節點。所以池化層的過濾器除了在長和寬兩個維度移動之外,它還需要在深度這個維度移動。下面的TensorFlow程序實現了最大池化層的前向傳播演算法。
對比池化層和卷積層前向傳播在TensorFlow中的實現,可以發現函數的參數形式是相似的。在tf.nn.max_pool函數中,首先需要傳入當前層的節點矩陣,這個矩陣是一個四維矩陣,格式和tf.nn.conv2d函數中的第一個參數一致。第二個參數為過濾器的尺寸。雖然給出的是一個長度為4的一維數組,但是這個數組的第一個和最後一個數必須為1。這意味著池化層的過濾器是不可以跨不同輸入樣例或者節點矩陣深度的。在實際應用中使用得最多的池化層過濾器尺寸為[1,2,2,1]或者[1,3,3,1]。
tf.nn.max_pool函數的第三個參數為步長,它和tf.nn.conv2d函數中步長的意義是一樣的,而且第一維和最後一維也只能為1。這意味著在TensorFlow中,池化層不能減少節點矩陣的深度或者輸入樣例的個數。tf.nn.max_pool函數的最後一個參數指定了是否使用全0填充。這個參數也只有兩種取值——VALID或者SAME,其中VALID表示不使用全0填充,SAME表示使用全0填充。TensorFlow還提供了tf.nn.avg_pool來實現平均池化層。tf.nn.avg_pool函數的調用格式和tf.nn.max_pool函數是一致的。
LeNet-5模型
LeNet-5模型是Yann LeCun教授於1998年在論文Gradient-based learning applied to document recognition中提出的,它是第一個成功應用於數字識別問題的卷積神經網路。在MNIST數據集上,LeNet-5模型可以達到大約99.2%的正確率。LeNet-5模型總共有7層,圖7展示了LeNet-5模型的架構。
圖7 LeNet-5模型結構圖。
在下面的篇幅中將詳細介紹LeNet-5模型每一層的結構。論文GradientBased Learning
Applied to Document Recognition提出的LeNet-5模型中,卷積層和池化層的實現與上文中介紹的TensorFlow的實現有細微的區別,這裡不過多的討論具體細節,而是著重介紹模型的整體框架。第一層,卷積層
這一層的輸入就是原始的圖像像素,LeNet-5模型接受的輸入層大小為32×32×1。第一個卷積層過濾器的尺寸為5×5,深度為6,不使用全0填充,步長為1。因為沒有使用全0填充,所以這一層的輸出的尺寸為,深度為6。這一個卷積層總共有個參數,其中6個為偏置項參數。因為下一層的節點矩陣有個節點,每個節點和個當前層節點相連,所以本層卷積層總共有個連接。
第二層,池化層
這一層的輸入為第一層的輸出,是一個28×28×6的節點矩陣。本層採用的過濾器大小為2×2,長和寬的步長均為2,所以本層的輸出矩陣大小為14×14×6。原始的LeNet-5模型中使用的過濾器和本文中介紹的有些細微差別,這裡不做具體介紹。
第三層,卷積層
本層的輸入矩陣大小為14×14×6,使用的過濾器大小為5×5,深度為16。本層不使用全0填充,步長為1。本層的輸出矩陣大小為10×10×16。按照標準的卷積層,本層應該有個參數,個連接。
第四層,池化層
本層的輸入矩陣大小為10×10×16,採用的過濾器大小為2×2,步長為2。本層的輸出矩陣大小為5×5×16。
第五層,全連接層
本層的輸入矩陣大小為5×5×16,在LeNet-5模型的論文中將這一層稱為卷積層,但是因為過濾器的大小就是5×5,所以和全連接層沒有區別,在之後的TensorFlow程序實現中也會將這一層看成全連接層。如果將5×5×16矩陣中的節點拉成一個向量,那麼這一層和在第四章中介紹的全連接層輸入就一樣了。本層的輸出節點個數為120,總共有個參數。
第六層,全連接層
本層的輸入節點個數為120個,輸出節點個數為84個,總共參數為個。
第七層,全連接層
本層的輸入節點個數為84個,輸出節點個數為10個,總共參數為個。
上面介紹了LeNet-5模型每一層結構和設置,下面給出一個TensorFlow的程序來實現一個類似LeNet-5模型的卷積神經網路來解決MNIST數字識別問題。通過TensorFlow訓練卷積神經網路的過程和第五章中介紹的訓練全連接神經網路是完全一樣的。損失函數的計算、反向傳播過程的實現都可以復用上一篇中給出的mnist_train.py程序。唯一的區別在於因為卷積神經網路的輸入層為一個三維矩陣,所以需要調整一下輸入數據的格式:
在調整完輸入格式之後,只需要在程序mnist_inference.py中實現類似LeNet-5模型結構的前向傳播過程即可。下面給出了修改後的mnist_infernece.py程序。
運行修改後的mnist_train.py和mnist_eval.py,可以得到一下測試結果:
上面的程序可以將MNIST正確率達到~99.4%。
本文內容來自作者圖書作品《TensorFlow:實戰Google深度學習框架》。
作者介紹
鄭澤宇,才雲首席大數據科學家,前谷歌高級工程師。從 2013 年加入谷歌至今,鄭澤宇作為主要技術人員參與並領導了多個大數據項目,擁有豐富機器學習、數據挖掘工業界及科研項目經驗。2014 年,他提出產品聚類項目用於銜接谷歌購物和谷歌知識圖譜(Knowledge Graph)數據,使得知識卡片形式的廣告逐步取代傳統的產品列表廣告,開啟了谷歌購物廣告在搜索頁面投遞的新紀元。他於2013 年 5 月獲得美國 Carnegie Mellon University(CMU)大學計算機碩士學位, 期間在頂級國際學術會議上發表數篇學術論文,並獲得西貝爾獎學金。
-全文完-
關注人工智慧的落地實踐,與企業一起探尋 AI 的邊界,AICon 全球人工智慧技術大會火熱售票中,8 折倒計時一周搶票,詳情點擊:
https://aicon.geekbang.org/?utm_source=ai-front&utm_medium=zhihu
《深入淺出TensorFlow》迷你書現已發布,關注公眾號「AI前線」,ID:ai-front,回復關鍵字:TF,獲取下載鏈接!
推薦閱讀:
※利用TensorFlow搞定知乎驗證碼之《讓你找中文倒轉漢字》
※深入淺出Tensorflow(五):循環神經網路簡介
※cs20si:tensorflow for research 學習筆記2
TAG:TensorFlow | 卷积神经网络CNN |