十一、計算機視覺中的深度學習:卷積神經網絡介紹


文章代碼來源:《deep learning on keras》,非常好的一本書,大家如果英語好,推薦直接閱讀該書,如果時間不夠,可以看看此系列文章,文章為我自己翻譯的內容加上自己的一些思考,水平有限,多有不足,請多指正,翻譯版權所有,若有轉載,請先聯系本人。
個人方向為數值計算,日后會向深度學習和計算問題的融合方面靠近,若有相近專業人士,歡迎聯系。


系列文章:
一、搭建屬于你的第一個神經網絡
二、訓練完的網絡去哪里找
三、【keras實戰】波士頓房價預測
四、keras的function API
五、keras callbacks使用
六、機器學習基礎Ⅰ:機器學習的四個標簽
七、機器學習基礎Ⅱ:評估機器學習模型
八、機器學習基礎Ⅲ:數據預處理、特征工程和特征學習
九、機器學習基礎Ⅳ:過擬合和欠擬合
十、機器學習基礎Ⅴ:機器學習的一般流程十一、計算機視覺中的深度學習:卷積神經網絡介紹
十二、計算機視覺中的深度學習:從零開始訓練卷積網絡
十三、計算機視覺中的深度學習:使用預訓練網絡
十四、計算機視覺中的神經網絡:可視化卷積網絡所學到的東西


在這一章,我們會學習卷積神經網絡,一種在計算機視覺中常用的深度學習模型,你將會學著將它們運用到分類問題中。
我們首先會介紹卷積神經網絡背后的一些理論,特別的:

  • 什么是卷積和最大池化?
  • 什么是卷積網絡?
  • 卷積網絡學到了什么東西?

接下來我們會用小的數據集來概括圖像分類問題:

  • 從零開始訓練你的小卷積網絡
  • 使用數據增加來避免過擬合
  • 使用預訓練的卷積網絡來做特征提取
  • 對預訓練卷積網絡調參

最后我們會概括幾個可視化的技術來學習如何分類。

接下來是我們的第一節,卷積神經網路的介紹

我們潛入卷積神經網絡的理論,并探尋為什么它在計算機視覺任務中那么成功。首先,我們實際看看一個簡單的卷積網絡的例子。我們將會用卷積網絡來分類MNIST數字,在之前我們以及用全連接做到了97.8%的識別率。盡管我們的卷積網絡很基礎,但是其正確率和原來的全連接比,照樣完勝。
接下來6行代碼將會給你展示最基礎的卷積網絡長什么樣,其實就是一些二維卷積和二維最大池化層的堆疊。我們接下來將會看看他們到底具體做了些什么,一個卷積拿進去的張量的形狀:(長,寬,通道數)不包括批次的維數。在我們的例子中,我們將會處理輸入形狀為(28,28,1)的數據,這就是MNIST中數據的格式。

from keras import layers
from keras import models
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))

接下來讓我們看看卷積網絡的結構:

>>> model.summary()
________________________________________________________________
Layer (type) Output Shape Param #
================================================================
conv2d_1 (Conv2D) (None, 26, 26, 32) 320
________________________________________________________________
maxpooling2d_1 (MaxPooling2D) (None, 13, 13, 32) 0
________________________________________________________________
conv2d_2 (Conv2D) (None, 11, 11, 64) 18496
________________________________________________________________
maxpooling2d_2 (MaxPooling2D) (None, 5, 5, 64) 0
________________________________________________________________
conv2d_3 (Conv2D) (None, 3, 3, 64) 36928
================================================================
Total params: 55,744
Trainable params: 55,744
Non-trainable params: 0

我們可以看到每一個卷積層和池化層的輸出都是三維的張量。寬度和高度隨著網絡的加深開始收縮。通道的數量由卷積層受到的第一個參數來控制。
接下來就是將我們的輸出張量喂進全連接分類網絡。分類器處理的是一維向量,而我們的輸出是一個三維的張量,所以我們需要把我們的三維輸出壓成一維的,接下來,我們加一層密度層:

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

我們接下來要做一個10分類,我們選用了softmax作為激活函數,輸出維度為10,我們的網絡現在長成這個樣子:

>>> model.summary()
Layer (type) Output Shape Param #
================================================================
conv2d_1 (Conv2D) (None, 26, 26, 32) 320
________________________________________________________________
maxpooling2d_1 (MaxPooling2D) (None, 13, 13, 32) 0
________________________________________________________________
conv2d_2 (Conv2D) (None, 11, 11, 64) 18496
________________________________________________________________
maxpooling2d_2 (MaxPooling2D) (None, 5, 5, 64) 0
________________________________________________________________
conv2d_3 (Conv2D) (None, 3, 3, 64) 36928
________________________________________________________________
flatten_1 (Flatten) (None, 576) 0
________________________________________________________________
dense_1 (Dense) (None, 64) 36928
________________________________________________________________
dense_2 (Dense) (None, 10) 650
================================================================
Total params: 93,322
Trainable params: 93,322
Non-trainable params: 0

最后我們將使用之前使用過的代碼來訓練:

from keras.datasets import mnist
from keras.utils import to_categorical
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28, 28, 1))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype('float32') / 255
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
model.compile(optimizer='rmsprop',
 loss='categorical_crossentropy',
 metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=5, batch_size=64)

然后評測一下最終結果

>>> test_loss, test_acc = model.evaluate(test_images, test_labels)
>>> test_acc
0.99080000000000001

為什么一個簡單的卷積神經網絡能夠比全連接模型效果好那么多呢,我們需要繼續潛入卷積層和最大池化層來理解這個事情。

卷積算子

全連接層學習全局圖案,而卷積層則學習局部的圖案


Images can be broken down into local patterns such as edges, textures, etc

這個關鍵的特征給了卷積網絡兩個有意思的特性:

  • 學習到的圖案具有平移不變性,在全連接中學到的圖案和位置有關,而卷積網絡則有更高的數據效率。
  • 能學習圖案的空間層次,如下圖,第一層學習小的局部圖案例如邊緣,但第二個卷積層將會基于第一層學習更大的特征。這將使得卷積網絡更加有效的學習到進一步抽象復雜的特征。


    The visual world forms a spatial hierarchy of visual modules: hyperlocal edges combine into local objects such as eyes or ears, which combine into high-level concepts such as "cat"

    在三維張量的卷積運算稱為“特征圖”,有兩個空間坐標(寬和高),和一個深度坐標(也稱作通道數)對于RGB圖像來說,深度坐標的維度就是3。對于MNIST來說,黑白圖深度就是1。卷積算子從輸入特征圖提取補丁,并對所有的補丁做某些變換,然后產生我們的輸出特征圖。輸出特征圖仍然是三維張量,不過這里的深度不再代表什么具體的顏色了,而是我們叫做濾波器的東西。濾波器對輸入數據的某一特定方面進行編碼,在高層次,一個簡單的濾波器能編碼輸入中一個面的存在。
    卷積由以下兩個關鍵參數所定義:

  • 從輸入中提取的補丁塊的大小。在我們的例子中一般都是3\times 3的。
  • 輸出特征映射的深度,即濾波器的數量。在我們的例子中,我們從深度為32開始,深度為64結束。

在keras的卷積層中,第一個傳入的參數就是Conv2D(output_depth, (window_height, window_width))。
一個卷積通過滑動來工作,在每個可能的位置停止,并從周圍的特征里面提取三維補丁。
示意圖如下:


How convolution works

注意到我們得到的輸出的寬度和高度或許和輸入的寬度和高度不一樣,這里有兩個原因:

  • 邊框影響,由于輸入特征映射填充造成的。
  • 滑動的使用,我們稍后會定義。

讓我們來看一下這些注意點。

理解邊框效應和填充

考慮一個5\times 5的特征映射,共25個小塊。但那時只有9個不同的小塊,也就說你可以注意力放在3\times 3的小窗上。因此輸出的特征映射將會是3\times 3的:這縮小了很多,在每個維度上縮小了兩個小塊,你將會在之前的例子中看到“邊界效應”。

Valid locations of 3x3 patches in a 5x5 input feature map

如果你想要得到一個和原來的輸入有相同的輸出特征映射,你可以選擇使用填充。填充通過增加合適數量的行列向量,對于
3\times 3
的窗,可以選擇在左右側各加一列,上下各加一行。對于
5\times 5
的窗口,就是兩行了。
Padding a 5x5 input in order to be able to extract 25 3x3 patches

在卷積層中,填充可以通過“填充”參數來配置,“填充”參數中包含兩個值:"valid"和"same",前者意味著不填充,后者意味著讓輸入輸出有相同的寬高,而padding參數的默認值是"valid"。

理解卷積滑動

另一個影響輸出大小的是"stride"。在我們目前為止對于卷積的描述,我們假設卷積窗口的中心塊都配置好了。然而,兩個連續的窗口之間實際上有一個卷積的參數,叫做"stride",默認值為1。在接下來這幅圖你可以看到stride設為2的情況。


3x3 convolution patches with 2x2 strides

使用stride為2,意味著寬和高都通過因子2來下采樣。滑動卷積在實際中很少使用,盡管他們能在很多種模型中派上用場,熟悉這塊內容總是好的。
為了對特征進行下采樣,除了滑動,還可以通過最大池化算子來做到。

最大池化算子

在我們的卷積例子里面,你已經注意到特征映射的數量在經過最大池化以后會減半,就像滑動卷積一樣,對于降采樣非常的積極。
最大池化由從輸入特征來提取窗口以及輸出每個通道的最大值。這就和卷積很相似了。
我們為什么要做池化呢?如果把池化這一步去掉會發生什么呢?

model_no_max_pool = models.Sequential()
model_no_max_pool.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model_no_max_pool.add(layers.Conv2D(64, (3, 3), activation='relu'))
model_no_max_pool.add(layers.Conv2D(64, (3, 3), activation='relu'))

輸出結構:

>>> model_no_max_pool.summary()
Layer (type) Output Shape Param #
================================================================
conv2d_4 (Conv2D) (None, 26, 26, 32) 320
________________________________________________________________
conv2d_5 (Conv2D) (None, 24, 24, 64) 18496
________________________________________________________________
conv2d_6 (Conv2D) (None, 22, 22, 64) 36928
================================================================
Total params: 55,744
Trainable params: 55,744
Non-trainable params: 0

這么設置有什么錯嗎?有兩點:

  • 這不有利于學習空間層次的特征。3\times 3的窗口在第3層將只包含輸入中7\times 7的信息。卷積網絡能夠學習到的高級特征還是太小。我們需要最后一層卷積層能夠包含全部輸入的信息。
  • 最終的特征的系數太多了。

簡短的說,使用下采樣是為了減少特征系數的數量,同時讓連續的卷積層去處理更大的窗口以減少空間濾波器數量。
注意最大池化不是唯一可以取得下采樣的方法。你也知道stride也可以,你還可以使用平均池化。然而最大池化往往比這些替代方法表現得好。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容