《Python數據分析與機器學習實戰-唐宇迪》讀書筆記第19章--卷積神經網絡

python數據分析個人學習讀書筆記-目錄索引

19章卷積神經網絡

   本章介紹現階段神經網絡中非常火的模型——卷積神經網絡,它在計算機視覺中有着非常不錯的效果。不僅如此,卷積神經網絡在非圖像數據中也有着不錯的表現,各項任務都有用武之地,可謂在機器學習領域遍地開花。那麼什麼是卷積呢?網絡的核心就在於此,本章將帶大家一步步揭開卷積神經網絡的奧祕。

 19.1卷積操作原理

   卷積神經網絡也是神經網絡的一種,本質上來說都是對數據進行特徵提取,只不過在圖像數據中效果更好,整體的網絡模型架構都是一樣的,參數迭代更新也是類似,所以難度就在於卷積上,只需把它弄懂即可。

19.1.1卷積神經網絡應用

   卷積神經網絡既然這麼火爆,肯定能完成一些實際任務,先來看一下它都能做什麼。

  圖19-1是經典的圖像分類任務,但是神經網絡也能完成這個任務,那麼,爲什麼說卷積神經網絡在計算機視覺領域更勝一籌呢?想想之前遇到的問題,神經網絡的矩陣計算方式所需參數過於龐大,一方面使得迭代速度很慢,另一方面過擬合問題比較嚴重,而卷積神經網絡便可以更好地處理這個問題。

 邀月工作室

  圖19-1 圖像分類任務

  圖19-2是檢測任務的示例,不僅需要找到物體的位置,還要區分物體屬於哪個類別,也就是迴歸和分類任務結合在一起。現階段物體檢測任務隨處可見,當下比較火的無人駕駛也需要各種檢測任務。

 邀月工作室

  圖19-2 檢測任務

  大家早就對人臉識別不陌生了,以前去機場,安檢員都是拿着身份證來回比對,查看是不是冒牌的,現在直接對準攝像頭,就會看到你的臉被框起來進行識別。

  圖像檢索與推薦如圖19-3所示,各大購物APP都有這樣一個功能——拍照搜索,有時候我們看到一件心儀的商品,但是卻不知道它的名稱,直接上傳一張照片,同款就都出來了。

 邀月工作室

  圖19-3 檢索與推薦

  卷積網絡的應用實在太廣泛了,例如,醫學上進行細胞分析、辦公上進行拍照取字、攝像頭進行各種識別任務,這些早已融入大家的生活當中(見圖19-4)。

 邀月工作室

  圖19-4 卷積網絡廣泛的應用

  簡單介紹卷積神經網絡的應用後,再來探索一下其工作原理,卷積神經網絡作爲深度學習中的傑出代表肯定會讓大家不虛此行。

19.1.2卷積操作流程

   接下來就要深入網絡細節中,看看卷積究竟做了什麼,首先觀察一下卷積網絡和傳統神經網絡的不同之處,如圖19-5所示。

 邀月工作室

  圖19-5 卷積網絡與傳統神經網絡的不同

  傳統的神經網絡是一個平面,而卷積網絡是一個三維立體的。不難發現,卷積神經網絡中多了一個概念——深度。例如圖像輸入數據h×w×c,其中顏色通道c就是輸入的深度。

  在使用TensorFlow做神經網絡的時候,首先將圖像數據拉成像素點組成的特徵,這樣做相當於輸入一行特徵數據而非一個原始圖像數據,而卷積中要操作的對象是一個整體,所以需要定義深度。

  如果大家沒有聽過卷積這個詞,把它想象成一種特徵提取的方法就好,最終的目的還是要得到計算機更容易讀懂的特徵。下面解釋一下卷積過程。

  假設已有輸入數據(32×32×3),如圖19-6所示,此時想提取圖像中的特徵,以前是對每個像素點都進行變換處理,看起來是獨立對待每一個像素點特徵。但是圖像中的像素點是有一定連續關係的。如果能把圖像按照區域進行劃分,再對各個區域進行特徵提取應當更合理。

 邀月工作室

  圖19-6 卷積操作

  圖19-6中假設把原始數據平均分成多個小塊,接下來就要對每一小塊進行特徵提取,也可以說是從每一小部分中找出關鍵特徵代表。

  如何進行體徵提取呢?這裏需要藉助一個幫手,暫時叫它filter,它需要做的就是從其中每一小塊區域選出一個特徵值。假設filter的大小是5×5×3,表示它要對輸入的每個5×5的小區域都進行特徵提取,並且要在3個顏色通道(RGB)上都進行特徵提取再組合起來。

  通過助手filter進行特徵提取後,就得到圖19-7所示的結果,看起來像兩塊板子,它們就是特徵圖,表示特徵提取的結果,爲什麼是兩個呢?這裏在使用filter進行特徵提取的時候,不僅可以用一種特徵提取方法,也就是filter可以有多個,例如在不同的紋理、線條的層面上(只是舉例,其實就是不同的權重參數)。

 邀月工作室

  圖19-7 特徵提取

  例如,在同樣的小塊區域中,可以通過不同的方法來選擇不同層次的特徵,最終所有區域特徵再組合成一個整體。先不用管28×28×2的特徵圖大小是怎麼來的,最後會向大家介紹計算公式,現在先來理解它。

  在一次特徵提取的過程中,如果使用6種不同的filter,那麼肯定會得到6張特徵圖,再把它們堆疊在一起,就得到了h×w×6的特徵輸出結果。這其實就是一次卷積操作,如圖19-8所示。

 邀月工作室

  圖19-8 特徵圖

  剛纔從流程上解釋了卷積操作的目的,那麼是不是隻能對輸入數據執行卷積操作呢?並不是這樣,我們得到的特徵圖是28×28×6,感覺它與輸入數據的格式差不多。此時第3個維度上,顏色通道數變成特徵圖個數,所以對特徵圖依舊可以進行卷積操作,相當於在提取出的特徵上再進一步提取。

  圖19-9所示爲卷積神經網絡對輸入圖像數據進行特徵提取,使用3個卷積提取特徵,最終得到的結果就是特徵圖。

 邀月工作室

  圖19-9 卷積特徵提取

  在基本神經網絡中,用多個隱藏層進行特徵提取,卷積神經網絡也是如此,只不過用的是卷積層。

19.1.3卷積計算方法

   卷積的概念和作用已經很清晰,那麼如何執行卷積計算操作呢?下面要深入其計算細節中。

  假設輸入數據的大小爲7×7×3(圖像長度爲7;寬度爲7;顏色通道爲RGB),如圖19-10所示。此例中選擇的filter大小是3×3×3(參數需要自己設計,卷積核長度爲3;寬度爲3;分別對應輸入的3顏色通道),看起來輸入數據的顏色通道數和filter一樣,都是3個,這點是卷積操作中必須成立的,因爲需要對應計算,如果不一致,那就完全不能計算。

 邀月工作室

  圖19-10 卷積計算

  大家可以將輸入數據中的數值當作圖像中的像素點,但是filter(卷積核)中的數值是什麼意思呢?它與神經網絡中的權重參數的概念一樣,表示對特徵進行變換的方法。初始值可以是隨機初始化的,然後通過反向傳播不斷進行更新,最終要求解的就是filter中每個元素的值。

  filter(卷積核)就是卷積神經網絡中權重參數,最終特徵提取的結果主要由它來決定,所以目標就是優化得到最合適的特徵提取方式,相當於不斷更新其數值。

  特徵值計算方法比較簡單,每一個對應區域與filter(卷積核)計算內積即可,最終得到的是一個結果值,表示該區域的特徵值,如圖19-11所示。但是,還需要考慮一點,圖像中的區域並不是一個平面,而是一個帶有顏色通道的三維數據,所以還需把所有顏色通道的結果分別計算,最終求和即可。

  在圖19-10的第一塊區域中,各個顏色通道的計算結果累加在一起爲0+2+0=2,這樣就可以計算得出卷積核中權重參數作用在輸入數據上的結果,但是,不要忘記還有一個偏置項需要加起來:2+1=3,這樣就得到在原始數據中第一個3×3×3小區域的特徵代表,把它寫到右側的特徵圖第一個位置上。

 邀月工作室

  圖19-11 特徵值計算方法

  算完第一個區域,下一個計算區域應當在哪裏呢?區域的選擇與滑動窗口差不多,需要指定滑動的步長,以依次選擇特徵提取的區域位置。

  滑動兩個單元格(步長也是卷積中的參數,需要自己設置),區域選擇到中間位置,接下來還是相同的內積計算方法,得到的特徵值爲-5,同樣寫到特徵圖中相應位置,如圖19-12所示。

 邀月工作室

  圖19-12 分別計算特徵值

  繼續滑動窗口,直到計算完最後一個位置的特徵值,這樣就得到一個特徵圖(3×3×1),如圖19-13所示。通常一次卷積操作都希望能夠得到更多的特徵,所以一個特徵圖肯定不夠用,這裏實際上選擇兩個filter,也就是有兩組權重參數進行特徵提取,由於Filter W1和Filter W2中的權重參數值各不相同,所以得到的特徵圖肯定也不同,相當於用多種方式得到不同的特徵表示,再把它們堆疊在一起,就完成全部卷積操作。

 邀月工作室

  圖19-13 特徵圖組成

19.1.4卷積涉及參數

   卷積操作比傳統神經網絡的計算複雜,在設計網絡結構過程中,需要給定更多的控制參數,並且全部需要大家完成設計,所以必須掌握每一個參數的意義。

  (1)卷積核(filter)。卷積操作中最關鍵的就是卷積核,它決定最終特徵提取的效果,需要設計其大小與初始化方法。大小即長和寬,對應輸入的每一塊區域。保持數據大小不變,如果選擇較大的卷積核,則會導致最終得到的特徵比較少,相當於在很粗糙的一大部分區域中找特徵代表,而沒有深入細節。所以,現階段在設計卷積核時,基本都是使用較小的長和寬,目的是得到更細緻(數量更多)的特徵。

   一般來說,一種特徵提取方法能夠得到一個特徵圖,通常每次卷積操作都會使用多種提取方法,也就是多來幾個卷積核,只要它們的權重值不一樣,得到的結果也不同,一般256、512都是常見的特徵圖個數。對參數初始化來說,它與傳統神經網絡差不多,最常見的還是使用隨機高斯初始化。

  圖19-14表示使用兩個卷積核進行特徵提取,最後得到的就是2張特徵圖,關於具體的數值(例如4×4),需要介紹完所有參數之後,再給出計算公式。

 邀月工作室

  圖19-14 卷積核

  (2) 步長(stride)。在選擇特徵提取區域時,需要指定每次滑動單元格的大小,也就是步長。如果步長比較小,意味着要慢慢地儘可能多地選擇特徵提取區域,這樣得到的特徵圖信息也會比較豐富,如圖19-15所示。

 邀月工作室

  圖19-15 步長爲1的卷積

  如果步長較大,選中的區域就會比較少,得到的特徵圖也會比較小,如圖19-16所示。

  對比可以發現,步長會影響最終特徵圖的規模。在圖像任務中,如果屬於非特殊處理任務(文本數據中的步長可表示爲一次考慮多少上下文信息),最好選擇小一點的步長,雖然計算多了一些,但是可利用的特徵豐富了,更有利於計算機完成識別任務。

 邀月工作室

  圖19-16 步長爲2的卷積

  現階段大家看到的網絡模型步長基本上都爲1,這可以當作是科學家們公認的結果,也就是可以參考的經驗值。

  (3)邊界填充(pad)。首先考慮一個問題:在卷積不斷滑動的過程中,每一個像素點的利用情況是同樣的嗎?邊界上的像素點可能只被滑動一次,也就是隻能參與一次計算,相當於對特徵圖的貢獻比較小。而那些非邊界上的點,可能被多次滑動,相當於在計算不同位置特徵的時候被利用多次,對整體結果的貢獻就比較大。

  這似乎有些不公平,因爲拿到輸入數據或者特徵圖時,並沒有規定邊界上的信息不重要,但是卷積操作卻沒有平等對待它們,如何進行改進呢?只需要讓實際的邊界點不再處於邊界位置即可,此時通過邊界填充添加一圈數據點就可以解決上述問題。此時原本邊界上的點就成爲非邊界點,顯得更公平。

  邊界填充如圖19-17所示,仔細觀察一下輸入數據,有一點比較特別,就是邊界上所有的數值都爲0,表示這個像素點沒有實際的信息,這就是卷積中的邊界填充(pad)。

 邀月工作室

  圖19-17 邊界填充

  此時實際圖像的輸入爲5×5,由於加了一圈0,所以變成7×7,爲什麼填充的都是0呢?如果要對圖像大小進行變換,可用的方法其實有很多,這裏選擇0值進行填充,其目的是爲了結果的可靠性,因爲畢竟是填充出來的數據,如果參與到計算中,對結果有比較大的影響,那豈不是更不合理?所以一般都用0值進行填充。

  (4)特徵圖規格計算。當執行完卷積操作後會得到特徵圖,那麼如何計算特徵圖的大小呢?只要給定上述參數,就能直接進行計算:

  邀月工作室

  其中,W1、H1分別表示輸入的寬度、長度;W2、H2分別表示輸出特徵圖的寬度、長度;F表示卷積核長和寬的大小;S表示滑動窗口的步長;P表示邊界填充(加幾圈0)。

  如果輸入數據是32×32×3的圖像,用10個5×5×3的filter進行卷積操作,指定步長爲1,邊界填充爲2,最終輸入的規模爲 (32-5+2×2)/1+1=32,所以輸出規模爲32×32×10,經過卷積操作後,也可以保持特徵圖長度、寬度不變。

  在神經網絡中,曾舉例計算全連接方式所需的權重參數,一般爲千萬級別,實在過於龐大。卷積神經網絡中,不僅特徵提取方式與傳統神經網絡不同,參數的級別也差幾個數量級。

  卷積操作中,使用參數共享原則,在每一次迭代時,對所有區域使用相同的卷積覈計算特徵。可以把卷積這種特徵提取方式看成是與位置無關的,這其中隱含的原理是:圖像中一部分統計特性與其他部分是一樣的。這意味着在這一部分學習的特徵也能用在另一部分上,所以,對於這個圖像上的所有位置,都能使用相同的卷積核進行特徵計算。

  大家肯定會想,如果用不同的卷積核提取不同區域的特徵應當更合理,但是這樣一來,計算的開銷就實在太大,還得綜合考慮。

  如圖19-18所示,左圖中未使用共享原則,使得每一個區域的卷積核都不同,其結果會使得參數過於龐大,右圖中雖然區域很多,但每一個卷積核都是固定的,所需權重參數就少多了。

  例如,數據依舊是32×32×3的圖像,繼續用10個5×5×3的filter進行卷積操作,所需的權重參數有多少個呢?

  5×5×3=75,表示每一個卷積核只需要75個參數,此時有10個不同的卷積核,就需要10×75=750個卷積核參數,不要忘記還有b參數,每個卷積核都有一個對應的偏置參數,最終只需要750+10=760個權重參數,就可以完成一個卷積操作。

 邀月工作室

  圖19-18 卷積參數共享

  觀察可以發現,卷積涉及的參數與輸入圖像大小並無直接關係,這可解決了大問題,可以快速高效地完成圖像處理任務。

19.1.5池化層

   池化層也是卷積神經網絡中非常重要的組成部分,先來看看它對特徵做了什麼。

  假設把輸入(224×224×64)當作某次卷積後的特徵圖結果,池化層基本都是放到卷積層之後使用的,很少直接對原始圖像進行池化操作,所以一般輸入的都是特徵圖。經過池化操作之後,給人直觀的感覺就是特徵圖縮水了,高度和寬度都只有原來的一半,體積變成原來的1/4,但是特徵圖個數保持不變,如圖19-19所示。

 邀月工作室

  圖19-19 池化操作

  並不是所有池化操作都會使得特徵圖長度、寬度變爲原來的一半,需根據指定的步長與區域大小進行計算,但是通常“縮水”成一半的池化最常使用。

  池化層的作用就是要對特徵圖進行壓縮,因爲卷積後得到太多特徵圖,能全部利用肯定最好,但是計算量和涉及的權重參數隨之增多,不得不採取池化方法進行特徵壓縮。常用池化方法有最大池化和平均池化。

  圖19-20是最大池化的示例。最大池化的原理很簡單,首先在輸入特徵圖中選擇各個區域,然後“計算”其特徵值,這裏並沒有像卷積層那樣有實際的權重參數進行計算,而是直接選擇最大的數值即可,例如在圖19-20的左上角[1,1,5,6]區域中,經過最大池化操作得到的特徵值就是6,其餘區域也是同理。

 邀月工作室

  圖19-20 最大池化

  平均池化的基本原理也是一樣,只不過在計算過程中,要計算區域的平均值,而不是直接選擇最大值,經過平均池化操作,[1,0,3,4]區域得到特徵值就是2。

  在池化操作中,依然需要給定計算參數,通常需要指定滑動窗口的步長(stride)和選擇區域的大小(例如2×2,只有大小,沒有參數)。

  最大池化的感覺是做法相對獨特一些,只是把最大的特徵值拿出來,其他完全不管,而平均池化看起來更溫柔一些,會綜合考慮所有的特徵值。那麼,是不是平均池化效果更好呢?並不是這樣,現階段使用的基本都是最大池化,感覺它與自然界中的優勝劣汰法則差不多,只會把最合適的保留下來,在神經網絡中也是如此,需要最突出的特徵。

  池化層的操作非常簡單,因爲並不涉及實際的參數計算,通常都是接在卷積層後面。卷積操作會得到較多的特徵圖,讓特徵更豐富,池化操作會壓縮特徵圖大小,利用最有價值的特徵。

 19.2經典網絡架構

   完成了卷積層與池化層之後,就要來看一看其整體效果,可能此時大家已經考慮了一個問題,就是卷積網絡中可以調節的參數還有很多,網絡結構肯定千變萬化,那麼,做實驗時,是不是需要把所有可能都考慮進去呢?通常並不需要做這些基礎實驗,用前人實驗好的經典網絡結構是最省時省力的。所謂經典就是在各項競賽和實際任務中,總結出來比較實用而且通用性很強的網絡結構。

19.2.1卷積神經網絡整體架構

   在瞭解經典之前,還要知道基本的卷積神經網絡模型,這裏給大家先來分析一下。

  圖19-21是一個完整的卷積神經網絡,首先對輸入數據進行特徵提取,然後完成分類任務。通常卷積操作後,都會對其結果加入非線性變換,例如使用ReLU函數。池化操作與卷積操作是搭配來的,可以發現卷積神經網絡中經常伴隨着一些規律出現,例如2次卷積後進行1次池化操作。最終還需將網絡得到的特徵圖結果使用全連接層進行整合,並完成分類任務,最後一步的前提是,要把特徵圖轉換成特徵向量,因爲卷積網絡得到的特徵圖是一個三維的、立體的,而全連接層是使用權重參數矩陣計算的,也就是全連接層的輸入必須是特徵向量,需要轉換一下,在後續代碼實戰中,也會看到轉換操作。

 邀月工作室

  圖19-21 卷積神經網絡整體架構

  卷積神經網絡的核心就是得到的特徵圖,如圖19-22所示,特徵圖的大小和個數始終在發生變化,通常卷積操作要得到更多的特徵圖來滿足任務需求,而池化操作要進行壓縮來降低特徵圖規模(池化時特徵圖個數不變)。最後再使用全連接層總結好全部特徵,在這之前還需對特徵圖進行轉換操作,可以當作是一個把長方體的特徵拉長成一維特徵的過程。

 邀月工作室

  圖19-22 卷積神經網絡特徵圖變化

19.2.2AlexNet網絡

   AlexNet可以說是深度學習的開篇之作,如圖19-23所示。在2012年的ImageNet圖像分類競賽中,用卷積神經網絡擊敗傳統機器學習算法獲得冠軍,也使得越來越多的人加入到深度學習的研究中。

 邀月工作室

  圖19-23 AlexNet網絡

AlexNet網絡結構從現在的角度來看還有很多問題,整體網絡結構是8層,其中卷積層5個,全連接層3個。當計算層數的時候,只考慮帶有參數的層,也就是卷積層和全連接層,其中池化層由於沒有涉及參數計算,就不把它算作層數裏面。從結構中可以看到,3個全連接層全部放到最後,相當於把所有卷積得到的特徵組合起來再執行後續的分類或迴歸任務。

網絡結構中,卷積核的選擇都偏大,例如第一層11×11的卷積核,並且步長爲4,感覺就像是大刀闊斧地提取特徵,這樣提取的特徵肯定不夠細緻,還有很多信息沒有被利用,所以相信大家也能直觀感受到ALEXNET的缺點。總之,就是網絡層數太少,提取不夠細膩,當時這麼做的出發點估計還是硬件設備計算性能所限。

  當大家在做實際任務時,如果不考慮時間效率,還是需要使網絡結構更龐大一些,AlexNet只做瞭解即可,實際中效果還有待提高。

19.2.3VGG網絡

   由於VGG網絡層數比較多,可以直接通過表格的形式看它的組成。它是2014年的代表作,其使用價值至今還在延續,所以很值得學習。VGG有好幾種版本,下面看其最經典的結構(也就是圖19-24框住的部分)。首先其網絡層數有16層,是ALEXNET的2倍,作者曾經做過對比實驗:相同的數據集分別用ALEXNET和VGG來建模分類任務,保持學習率等其他參數不變,VGG的效果要比ALEXNET高出十幾個百分點,但是相對訓練時間也要長很多。

 邀月工作室

  圖19-24 VGG網絡

  網絡層數越多,訓練時間也會越長,通常這些經典網絡的輸入大小都是224×224×3,如果AlexNet需要8小時完成訓練,VGG大概需要2天。

  VGG網絡有一個特性,所有卷積層的卷積核大小都是3×3,可以用較小的卷積核來提取特徵,並且加入更多的卷積層。這樣做有什麼好處呢?還需要解釋一個知識點—感受野,它表示特徵圖能代表原始圖像的大小,也就是特徵圖能感受到原始輸入多大的區域。

  選擇3×3的卷積核來執行卷積操作,經過兩次卷積後,選擇最後特徵圖中的一個點,如圖19-25所示。現在要求它的感受野,也就是它能看到原始輸出多大的區域,倒着來推,它能看到第一個特徵圖3×3的區域(因爲卷積核都是3×3的),而第一個特徵圖3×3的區域能看到原始輸入5×5的區域,此時就說當前的感受野是5×5。通常都是希望感受野越大越好,這樣每一個特徵圖上的點利用原始數據的信息就更多。

 邀月工作室

  圖19-25 感受野

  同理,如果堆疊3個3×3的卷積層,並且保持滑動窗口步長爲1,其感受野就是7×7,這與一個使用7×7卷積核的結果相同,那麼,爲什麼非要堆疊3個小卷積呢?假設輸入大小都是h×w×c,並且都使用C個卷積核(得到C個特徵圖),可以計算一下其各自所需參數。

  使用1個7×7卷積核所需參數:

  C×(7×7×C)=49C2

  使用3個3×3卷積核所需參數:

  3×C×(3×3×C)=27C2

  很明顯,堆疊小的卷積核所需的參數更少,並且卷積過程越多,特徵提取也會越細緻,加入的非線性變換也隨之增多,而且不會增大權重參數個數,這就是VGG網絡的基本出發點,用小的卷積核來完成體特徵提取操作。

  觀察其網絡結構還可以發現,基本上經過maxpool(最大池化)之後的卷積操作都要使特徵圖翻倍,這是由於池化操作已經對特徵圖進行壓縮,得到的信息量相對有所下降,所以需要通過卷積操作來彌補,最直接的方法就是讓特徵圖個數翻倍。

  後續的操作還是用3個全連接層把之前卷積得到的特徵再組合起來,可以說VGG是現代深度網絡模型的代表,用更深的網絡結構來完成任務,雖然訓練速度會慢一些,但是整體效果會有很大提升。如果大家拿到一個實際任務,還不知如何下手,可以先用VGG試試,它相當於一套通用解決方案,不僅能用在圖像分類任務上,也可以用於迴歸任務。

19.2.4ResNet網絡

   通過之前的對比,大家發現深度網絡的效果更好,那麼爲什麼不讓網絡再深一點呢?100層、1000層可不可以呢?理論上是可行的,但是先來看看之前遇到的問題。

  如圖19-26所示,如果沿用VGG的思想將網絡繼續堆疊得到的效果並不好,深層的網絡(如56層)無論是在訓練集還是在測試集上的效果都不理想,那麼所謂的深度學習是不是到此爲止呢?在解決問題的過程中,又一神作誕生了——深度殘差網絡。

 邀月工作室

  圖19-26 深層網絡遇到的問題

  其基本思想就是,因網絡層數繼續增多,導致結果下降,其原因肯定是網絡中有些層學習得不好。但是,在繼續堆疊過程中,可能有些層學習得還不錯,還可以被利用。

  圖19-27爲ResNet網絡疊加方法。如果這樣設計網絡結構,相當於輸入x(可以當作特徵圖)在進行卷積操作的時候分兩條路走:一條路中,x什麼都不做,直接拿過來得到當前輸出結果;另一條路中,x需要通過兩次卷積操作,以得到其特徵圖結果。再把這兩次的結果加到一起,這就相當於讓網絡自己判斷哪一種方式更好,如果通過卷積操作後,效果反而下降,那就直接用原始的輸入x;如果效果提升,就把卷積後的結果加進來。

 邀月工作室

  圖19-27 ResNet網絡疊加方法

  這就解決了之前提出的問題,深度網絡模型可能會導致整體效果還不如之前淺層的。按照殘差網絡的設計,繼續堆疊網絡層數並不會使得效果下降,最差也是跟之前一樣。

  如圖19-28所示,通過對比可以發現,殘差網絡在整體設計中沿用了圖19-27所示的方法,使得網絡繼續堆疊下去。這裏只是簡單介紹了一下其基本原理,如果大家想詳細瞭解其細節和實驗效果,最好的方式是閱讀其原始論文,非常有學習價值。

 邀月工作室

  圖19-28 ResNet網絡整體架構

  如圖19-29所示,圖19-29(a)就是用類似VGG的方法堆疊更深層網絡模型,層數越多,效果反而越差。圖19-29(b)是ResNet,它完美地解決了深度網絡所遇到的問題。

 邀月工作室

  圖19-29 Resnet效果對比

  圖19-30列出了在ImageNet圖像分類比賽中各種網絡模型的效果,最早的時候是用淺層網絡進行實驗,後續逐步改進,每一年都有傑出的代表產生(見圖19-31)。

 邀月工作室

  圖19-30 經典網絡效果對比

  不僅在圖像分類任務中,在檢測任務中也是如此,究其根本還是特徵提取得更好,所以現階段殘差網絡已經成爲一套通用的基本解決方案。

 邀月工作室

  圖19-31 日新月異的改革

 

19.3TensorFlow實戰卷積神經網絡

   講解完卷積與池化的原理之後,還要用TensorFlow實際把任務做出來。依舊是Mnist數據集,只不過這回用卷積神經網絡來進行分類任務,不同之處是輸入數據的處理:

 1 import tensorflow as tf
 2 import random
 3 import numpy as np
 4 import matplotlib.pyplot as plt
 5 import datetime
 6 %matplotlib inline
 7 
 8 from tensorflow.examples.tutorials.mnist import input_data
 9 mnist = input_data.read_data_sets("data/", one_hot=True)
10 
11 tf.reset_default_graph() 
12 sess = tf.InteractiveSession()
13 x = tf.placeholder("float", shape = [None, 28,28,1]) #shape in CNNs is always None x height x width x color channels
14 y_ = tf.placeholder("float", shape = [None, 10]) #shape is always None x number of classes

  在卷積神經網絡中,所有數據格式就都是四維的,先向大家解釋一下輸入中每一個維度表示的含義[batchsize,h,w,c]:batchsize表示一次迭代的樣本數量,h表示圖像的長度,w表示圖像的寬度,c表示顏色通道(或者特徵圖個數)。需要注意h和w的順序,不同深度學習框架先後順序可能並不一樣。在placeholder()中對輸入數據也需要進行明確的定義,標籤與之前一樣。

  接下來就是權重參數初始化,由於是卷積操作,所以它與之前全連接的定義方式完全不同:

1 W_conv1 = tf.Variable(tf.truncated_normal([5, 5, 1, 32], stddev=0.1))#shape is filter x filter x input channels x output channels
2 b_conv1 = tf.Variable(tf.constant(.1, shape = [32])) #shape of the bias just has to match output channels of the filter

  從上述代碼可以看出,還是隨機進行初始化操作,w表示卷積核,b表示偏置。其中需要指定的就是卷積核的大小,同樣也是四維的。[5,5,1,32]表示使用卷積核的大小是5×5,前面連接的輸入顏色通道是1(如果是特徵圖,就是特徵圖個數),使用卷積核的個數是32,就是通過這次卷積操作後,得到32個特徵圖。卷積層中需要設置的參數稍微有點多,需要注意卷積核的深度(這個例子中就是這個1),一定要與前面的輸入深度一致(Mnist是黑白圖,顏色通道爲1)。

  對於偏置參數來說,方法還是相同的,只需看最終結果。卷積中設置了32個卷積核,那麼,肯定會得到32個特徵圖,偏置參數相當於要對每一個特徵圖上的數值進行微調,所以其個數爲32。

1 h_conv1 = tf.nn.conv2d(input=x, filter=W_conv1, strides=[1, 1, 1, 1], padding='SAME') + b_conv1
2 h_conv1 = tf.nn.relu(h_conv1)
3 h_pool1 = tf.nn.max_pool(h_conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

  這就是卷積的計算流程,tensorflow中已經實現卷積操作,直接使用conv2d函數即可,需要傳入當前的輸入數據、卷積核參數、步長以及padding項。

  步長同樣也是四維的,第一個維度中,1表示在batchsize上滑動,通常情況下都是1,表示一個一個樣本輪着來。第二和第三個1表示在圖像上的長度和寬度上的滑動都是每次一個單位,可以看做一個小整體[1,1],長度和寬度的滑動一般都是一致的,如果是[2,2],表示移動兩個單位。最後一個1表示在顏色通道或者特徵圖上移動,基本也是1。通常情況下,步長參數在圖像任務中只需按照網絡的設計改動中間數值,如果應用到其他領域,就需要具體分析。

  Padding中可以設置是否加入填充,這裏指定成SAME,表示需要加入padding項。在池化層中,還需要指定ksize,也就是一次選擇的區域大小,與卷積核參數類似,只不過這裏沒有參數計算。[1,2,2,1]與步長的參數含義一致,分別表示在batchsize,h,w,c上的區域選擇,通常batchsize和通道(特徵圖)上都爲1,只需要改變中間的[2,2]來控制池化層結果,這裏選擇ksize和stride都爲2,相當於長和寬各壓縮到原來的一半。

  第一層確定後,後續的卷積和池化操作也相同,繼續進行疊加即可,其實,在網絡結構中,通常都是按照相同的方式進行疊加,所以可以先定義好組合函數,這樣就方便多了:

1 def conv2d(x, W):
2     return tf.nn.conv2d(input=x, filter=W, strides=[1, 1, 1, 1], padding='SAME')
3 
4 def max_pool_2x2(x):
5     return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

  繼續做第二個卷積層:

1 #Second Conv and Pool Layers
2 W_conv2 = tf.Variable(tf.truncated_normal([5, 5, 32, 64], stddev=0.1))
3 b_conv2 = tf.Variable(tf.constant(.1, shape = [64]))
4 h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
5 h_pool2 = max_pool_2x2(h_conv2)

  對於Mnist數據集來說,用兩個卷積層就差不多,下面就是用全連接層來組合已經提取出的特徵:

1 #First Fully Connected Layer
2 W_fc1 = tf.Variable(tf.truncated_normal([7 * 7 * 64, 1024], stddev=0.1))
3 b_fc1 = tf.Variable(tf.constant(.1, shape = [1024]))
4 h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
5 h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

  這裏需要定義好全連接層的權重參數:[7×7×64,1024],全連接參數與卷積參數有些不同,此時需要一個二維的矩陣參數。第二個維度1024表示要把卷積提取特徵圖轉換成1024維的特徵。第一個維度需要自己計算,也就是當前輸入特徵圖的大小,Mnist數據集本身輸入28×28×1,給定上述參數後,經過卷積後的大小保持不變,池化操作後,長度和寬度都變爲原來的一半,代碼中選擇兩個池化操作,所以最終的特徵圖大小爲28×1/2×1/2=7。特徵圖個數是由最後一次卷積操作決定的,也就是64。這樣就把7×7×64這個參數計算出來。

  在全連接操作前,需要reshape一下特徵圖,也就是將一個特徵圖壓扁或拉長成爲一個特徵。最後進行矩陣乘法運算,就完成全連接層要做的工作。

1 #Dropout Layer
2 keep_prob = tf.placeholder("float")
3 h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

  講解神經網絡時,曾特別強調過擬合問題,此時也可以加進dropout項,基本都是在全連接層加入該操作。傳入的參數是一個比例,表示希望保存神經元的百分比,例如50%。

1 #Second Fully Connected Layer
2 W_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))
3 b_fc2 = tf.Variable(tf.constant(.1, shape = [10]))
WARNING:tensorflow:From <ipython-input-9-5ff7d49325fd>:15: calling dropout (from tensorflow.python.ops.nn_ops) with keep_prob is deprecated and
will be removed in a future version. Instructions for updating: Please use `rate` instead of `keep_prob`. Rate should be set to `rate = 1 - keep_prob`.

 

  現在的1024維特徵可不是最終想要的結果,當前任務是要做一個十分類的手寫字體識別,所以第二個全連接層的目的就是把特徵轉換成最終的結果。大家可能會想,只設置最終輸出10個結果,能和它所屬各個類別的概率對應上嗎?沒錯,神經網絡就是這麼神奇,它要做的就是讓結果和標籤儘可能一致,按照標籤設置的結果,返回的就是各個類別的概率值,其中的奧祕就在於如何定義損失函數。

1 #Final Layer
2 y = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
3 
4 crossEntropyLoss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y_, logits = y))
5 trainStep = tf.train.AdamOptimizer().minimize(crossEntropyLoss)
6 correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
7 accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
WARNING:tensorflow:From <ipython-input-10-ba3a22c42ec1>:1: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated 
and will be removed in a future version. Instructions for updating: Future major versions of TensorFlow will allow gradients to flow into the labels input on backprop by default. See `tf.nn.softmax_cross_entropy_with_logits_v2`.

  同樣是設置損失函數以及優化器,這裏使用AdamOptimizer()優化器,相當於在學習的過程中讓學習率逐漸減少,符合實際要求,而且將計算準確率當作衡量標準。

 1 sess.run(tf.global_variables_initializer())
 2 
 3 batchSize = 50
 4 for i in range(1000):
 5     batch = mnist.train.next_batch(batchSize)
 6     trainingInputs = batch[0].reshape([batchSize,28,28,1])
 7     trainingLabels = batch[1]
 8     if i%100 == 0:
 9         trainAccuracy = accuracy.eval(session=sess, feed_dict={x:trainingInputs, y_: trainingLabels, keep_prob: 1.0})
10         print ("step %d, training accuracy %g"%(i, trainAccuracy))
11     trainStep.run(session=sess, feed_dict={x: trainingInputs, y_: trainingLabels, keep_prob: 0.5})
step 0, training accuracy 0.12
step 100, training accuracy 0.96
step 200, training accuracy 0.98
step 300, training accuracy 0.92
step 400, training accuracy 1
step 500, training accuracy 0.94
step 600, training accuracy 0.96
step 700, training accuracy 0.98
step 800, training accuracy 1
step 900, training accuracy 1

  之前使用神經網絡的時候,需要1000次迭代,效果才能達到90%以上,加入卷積操作之後,準備率的提升是飛快的,差不多100次,就能滿足需求。

 本章小結:

  圖19-32就是卷積神經網絡的基本結構,先將卷積層和池化層搭配起來進行特徵提取,最後再用全連接操作把特徵整合到一起,其核心就是卷積層操作以及其中涉及的參數。在圖像處理中,卷積網絡模型使用更少的參數,識別效果卻更好,大大促進了計算機視覺領域的發展,深度學習作爲當下最熱門的領域,進步也是飛快的,每年都會有傑出的網絡代表產生,學習的任務永遠都會持續下去。

 邀月工作室

  圖19-32 卷積網絡特徵提取

 

第19章完。

《Python數據分析與機器學習實戰-唐宇迪》讀書筆記第18章--TensorFlow實戰

《Python數據分析與機器學習實戰-唐宇迪》讀書筆記第20章--神經網絡項目實戰——影評情感分析

python數據分析個人學習讀書筆記-目錄索引

 

該書資源下載,請至異步社區:https://www.epubit.com

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章