機器學習16:簡單, 直觀的方法理解CNN(卷積神經網絡)核心原理及實現

1.CNN(卷積神經網絡)的典型應用場景

1.1 WaveNet 模型:

https://deepmind.com/blog/wavenet-generative-model-raw-audio/

如果你能訓練人工智能機器人唱歌,幹嘛還訓練它聊天?在 2017 年 4 月,研究人員使用 WaveNet 模型的變體生成了歌曲。原始論文和演示可以在此處找到。

http://www.creativeai.net/posts/W2C3baXvf2yJSLbY6/a-neural-parametric-singing-synthesizer

1.2 文本分類 CNN

http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/

你或許想註冊作者的深度學習簡訊!

1.3 Facebook的創新CNN方法

https://code.facebook.com/posts/1978007565818999/a-novel-approach-to-neural-machine-translation/

該方法專門用於解決語言翻譯任務,準確率達到了前沿性水平,並且速度是 RNN 模型的 9 倍。

1.4 Atari 遊戲

利用 CNN 和強化學習玩 Atari 遊戲。你可以下載此論文附帶的代碼

如果你想研究一些(深度強化學習)初學者代碼,建議你參閱 Andrej Karpathy 的帖子。

1.5 利用 CNN 玩看圖說詞遊戲!

https://quickdraw.withgoogle.com/#

此外,還可以參閱 A.I.Experiments 網站上的所有其他很酷的實現。別忘了 AutoDraw!

1.6 詳細瞭解 AlphaGo。

https://deepmind.com/research/alphago/

閱讀這篇文章,其中提出了一個問題:如果掌控 Go“需要人類直覺”,那麼人性受到挑戰是什麼感覺?_

1.7 觀看這些非常酷的視頻,其中的無人機都受到 CNN 的支持。

這是初創企業 Intelligent Flying Machines (IFM) (Youtube)的訪談。
戶外自主導航通常都要藉助全球定位系統 (GPS),但是下面的演示展示的是由 CNN 提供技術支持的自主無人機(Youtube)。

1.8 無人駕駛汽車使用的 CNN 感興趣

我們在此項目中對德國交通標誌數據集中的標誌進行分類。

優達學城交通標誌分類項目

德國交通標誌數據集

我們在此項目中對街景門牌號數據集中的門牌號進行分類。

https://github.com/udacity/machine-learning/tree/master/projects/digit_recognition

http://ufldl.stanford.edu/housenumbers/

這些系列博客,其中詳細講述瞭如何訓練用 Python 編寫的 CNN,以便生成能夠玩“俠盜獵車手”的無人駕駛 AI。

https://pythonprogramming.net/game-frames-open-cv-python-plays-gta-v/

1.9 其他應用情形

一些全球最著名的畫作被轉換成了三維形式,以便視力受損人士也能欣賞。雖然這篇文章沒有提到是怎麼做到的,我們注意到可以使用 CNN 預測單個圖片的深度

參閱這篇關於使用 CNN 確定乳腺癌位置的研究論文(google research)。

CNN 被用來拯救瀕危物種!

一款叫做 FaceApp 的應用使用 CNN 讓你在照片中是微笑狀態或改變性別。

2.CNN原理

相對於多層感知機(MLP), 當知道兩個輸入可能包含相同類型信息時,可以共享它們的權重,並利用這些輸入共同訓練權重。

統計不變量,即基本上不會隨時間或空間改變的事物,無處不在;

對於圖像,權重共享的思想引出了卷積網絡的研究;

對於一般的文本和序列,則涉及嵌入和循環神經網絡。

局部連接性

在這裏插入圖片描述

參數共享性

在這裏插入圖片描述

對於多層網絡輸出入

在這裏插入圖片描述

卷積網絡本質上就是一個深度網絡,但用共享權重的“卷積層”替代了一般的“全連接層”。

CNN總的想法是讓整個網絡形成金字塔狀,金字塔底部是一個非常大而淺的圖片,僅包含RGB三通道,通過卷積操作逐漸擠壓空間的維度,同時不斷增加深度,使深度信息大體上可以表示出複雜的語義。

在金字塔尖頂端可以放一個分類器,所有空間信息都被壓縮成一個表示,僅映射到圖片內容的參數被保留。

在這裏插入圖片描述

卷積層的stride和pad

在這裏插入圖片描述

3.Keras中的卷積層

導入必要的模塊:

from keras.layers import Conv2D

創建卷積層

Conv2D(filters, kernel_size, strides, padding, activation=‘relu’, input_shape)

參數

必須傳遞以下參數:

filters - 過濾器數量。
kernel_size - 指定(方形)卷積窗口的高和寬的數字。

你可能還需要調整其他可選參數:

strides - 卷積 stride。如果不指定任何值,則 strides 設爲 1。

padding - 選項包括 ‘valid’ 和 ‘same’。如果不指定任何值,則 padding 設爲 ‘valid’。

activation - 通常爲 ‘relu’。如果未指定任何值,則不應用任何激活函數。強烈建議你向網絡中的每個卷積層添加一個 ReLU 激活函數。

注意:可以將 kernel_size 和 strides 表示爲數字或元組

在模型中將卷積層當做第一層級(出現在輸入層之後)時,必須提供另一個 input_shape 參數:

input_shape - 指定輸入的高度、寬度和深度(按此順序)的元組。

你還可以設置很多其他元組參數,以便更改卷積層的行爲。要詳細瞭解這些參數,建議參閱官方文檔。

https://keras.io/layers/convolutional/

示例 1

假設要構建一個 CNN,輸入層接受的是 200 x 200 像素(對應於高 200、寬 200、深 1 的三維數組)的灰度圖片。

然後,假設我希望下一層級是卷積層,具有 16 個過濾器,每個寬和高分別爲 2。

在進行卷積操作時,我希望過濾器每次跳轉 2 個像素。並且,我不希望過濾器超出圖片界限之外;

也就是說,我不想用 0 填充圖片。要構建該卷積層,我將使用下面的代碼:

Conv2D(filters=16, kernel_size=2, strides=2, activation='relu', input_shape=(200, 200, 1))

示例 2

假設我希望 CNN 的下一層級是卷積層,並將示例 1 中構建的層級作爲輸入。

假設新層級是 32 個過濾器,每個的寬和高都是 3。

在進行卷積操作時,我希望過濾器每次移動 1 個像素。

我希望卷積層查看上一層級的所有區域,因此不介意過濾器在進行卷積操作時是否超過上一層級的邊緣。

然後,要構建此層級,我將使用以下代碼:

from keras.layers import Conv2D
Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')

示例 3

如果在線查看代碼,經常會在 Keras 中見到以下格式的卷積層:

Conv2D(64, (2,2), activation='relu')

在這種情況下,有 64 個過濾器,每個的大小是 2x2,層級具有 ReLU 激活函數。層級中的其他參數使用默認值,因此卷積的 stride 爲 1,填充設爲 ‘valid’。

from keras.models import Sequential
from keras.layers import Conv2D

model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, strides=2, padding='valid', 
    activation='relu', input_shape=(200, 200, 1)))
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_4 (Conv2D)            (None, 100, 100, 16)      80        
=================================================================
Total params: 80
Trainable params: 80
Non-trainable params: 0
_________________________________________________________________

3.1 卷積層中的參數數量

卷積層中的參數數量取決於 filters、kernel_size 和 input_shape 的值。我們定義幾個變量:

K - 卷積層中的過濾器數量

F - 卷積過濾器的高度和寬度

D_in - 上一層級的深度

注意:K = filters,F = kernel_size。類似地,D_in 是 input_shape 元組中的最後一個值。

因爲每個過濾器有 FFDinF*F*D_{in} 個權重,卷積層由 K 個過濾器組成,因此卷積層中的權重總數是KFFDinK*F*F*D_{in}。因爲每個過濾器有 1 個偏差項,卷積層有 K 個偏差。因此,卷積層中的參數數量是 KFFDin+KK*F*F*D_in + K

3.2 卷積層的形狀

卷積層的形狀取決於 kernel_size、input_shape、padding 和 stride 的值。我們定義幾個變量:

K - 卷積層中的過濾器數量

F - 卷積過濾器的高度和寬度

H_in - 上一層級的高度

W_in - 上一層級的寬度

注意:K = filters、F = kernel_size,以及S = stride。類似地,H_in 和 W_in 分別是 input_shape 元組的第一個和第二個值。

卷積層的深度始終爲過濾器數量 K。

如果 padding = ‘same’,那麼卷積層的空間維度如下:

import math
math.ceil( x ) #上入整數

height = ceil(float(H_in) / float(S))

width = ceil(float(W_in) / float(S))

如果 padding = ‘valid’,那麼卷積層的空間維度如下:

height = ceil(float(H_in - F + 1) / float(S))

width = ceil(float(W_in - F + 1) / float(S))

from keras.models import Sequential
from keras.layers import Conv2D

model = Sequential()
model.add(Conv2D(filters=32, kernel_size=3, strides=2, padding='same', 
    activation='relu', input_shape=(128, 128, 3)))
model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_5 (Conv2D)            (None, 64, 64, 32)        896       
=================================================================
Total params: 896
Trainable params: 896
Non-trainable params: 0
_________________________________________________________________

KFFDin+K==>33332+32=896K*F*F*D_in + K==> 3*3*3*32 + 32 = 896

可見,相對MLP全連接網絡,卷積網絡大量減小了參數個數。

4.池化層

卷積層,是指特徵映射堆棧,每個過濾器對應一個特徵映射,具有很多不同對象類別的複雜數據集,需要大量過濾器,

每個過濾器負責從圖片中查找一種規律,過濾器越多,則堆棧越大,意味着卷積層維度越高,則需要使用更多參數。這樣可能會導致過擬合,

在這裏插入圖片描述

因此,需要降低維度,這就是卷積神經網絡中的池化層。

4.1最大池化層

將一組特徵映射作爲輸入,單獨處理每個特徵映射,

在這裏插入圖片描述

則輸出是一組具有相同數量的特徵映射,但每個特徵映射的寬和高都減小了;

在這裏插入圖片描述

4.2 全局平均池化層

採用更極端的降低維度方法,對每個特徵映射,取平均值

在這裏插入圖片描述

將三維數組變成了向量

在這裏插入圖片描述

4.3keras其他不同池化層:

https://keras.io/layers/pooling/

論文:

https://arxiv.org/abs/1312.4400

5. Keras 中的最大池化層

導入必要的模塊:

from keras.layers import MaxPooling2D

創建卷積層:

MaxPooling2D(pool_size, strides, padding)

5.1 參數

你必須包含以下參數:

pool_size - 指定池化窗口高度和寬度的數字。

你可能還需要調整其他可選參數:

strides - 垂直和水平 stride。如果不指定任何值,則 strides 默認爲 pool_size。

padding - 選項包括 ‘valid’ 和 ‘same’。如果不指定任何值,則 padding 設爲 ‘valid’。

注意:可以將 pool_size 和 strides 表示爲數字或元組。

官方文檔:https://keras.io/layers/pooling/#maxpooling2d

from keras.models import Sequential
from keras.layers import MaxPooling2D

model = Sequential()
model.add(MaxPooling2D(pool_size=2, strides=2, input_shape=(100, 100, 15)))
model.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 15)        0         
=================================================================
Total params: 0
Trainable params: 0
Non-trainable params: 0
_________________________________________________________________

6.設計圖片CNN

卷積層,可以檢測圖片中的區域性規律,池化層在卷積層之後,可以降低數組的維數,加上全連接層,是CNN中常用的網絡層。

對於圖片的CNN,必須將圖片數組作爲輸入(一般統一大小),一般使空間維度等於2的冪次方,計算機將任何圖片解讀爲三維數組,輸入數組的寬和高始終大於深度。

CNN架構的設計目標,是獲取該輸入,然後逐漸使其深度大於寬和高。

在這裏插入圖片描述

卷積層將用於使穿過卷積層的數組更深,池化層用於減小空間維度,
在這裏插入圖片描述

卷積層設置:
在這裏插入圖片描述

池化層,一般在一個或多個卷基層後面,其經典設置:

在這裏插入圖片描述

這樣空間維度變爲上一層的一半,這樣通過組合使用卷積層和最大池化層,我們就能夠獲得很深,且空間維度很小的數組。

這種層級序列發現了圖片中包含的空間規律,它逐漸獲取空間數據,並將數組準換爲包含圖片內容的表示,所有空間信息最終會丟失,

在原始圖片中很容易知道各個像素與其他哪些像素相鄰,在最末尾層會發現數組中的條目與哪個項目相鄰已經不重要了。
在這裏插入圖片描述

一旦獲得不再具有圖片中的空間信息的數組,我們就可以扁平化該數組,並將其提供給一個或多個全連接層,判斷圖片中包含什麼對象。

在這裏插入圖片描述
設計一個簡單的CNN分類網絡

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense

model = Sequential()
model.add(Conv2D(filters=16, kernel_size=2, padding='same', activation='relu', input_shape=(32, 32, 3)))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=32, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Flatten())
model.add(Dense(500, activation='relu'))
model.add(Dense(10, activation='softmax'))

model.summary()
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_6 (Conv2D)            (None, 32, 32, 16)        208       
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 16, 16, 16)        0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 16, 16, 32)        2080      
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 8, 8, 32)          0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 8, 8, 64)          8256      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 4, 4, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1024)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 500)               512500    
_________________________________________________________________
dense_2 (Dense)              (None, 10)                5010      
=================================================================
Total params: 528,054
Trainable params: 528,054
Non-trainable params: 0
_________________________________________________________________

該網絡以三個卷積層(後面跟着最大池化層)序列開始。前 6 個層級旨在將圖片像素數組輸入轉換爲所有空間信息都丟失、僅保留圖片內容信息的數組 。然後在 CNN 的第七個層級將該數組扁平化爲向量。後面跟着兩個密集層,旨在進一步說明圖片中的內容。最後一層針對數據集中的每個對象類別都有一個條目,並具有一個 softmax 激活函數,使其返回概率。

注意事項

始終向 CNN 中的 Conv2D 層添加 ReLU 激活函數。但是網絡的最後層級除外,密集層也應該具有 ReLU 激活函數。

在構建分類網絡時,網絡中的最後層級應該是具有 softmax 激活函數的密集層。最後層級的節點數量應該等於數據集中的類別總數。

要開心!如果你覺得有點泄氣,建議參閱 Andrej Karpathy 的 tumblr(來自外網,可能打不開),其中包含了用戶提交的損失函數,對應的是本身有問題的模型。損失函數在訓練期間應該是減小的,但是這些圖表顯示的卻是非常不同的行爲 😃。

要設計自己的模型,你需要親自嘗試各種架構和不同的超參數,深度學習是一種需要實踐操作的領域,所以不要怕麻煩,去實踐,並且不要擔心違背了規則,儘量去嘗試不同的事物。提出問題,並通過實驗來回答你的問題,而不僅僅是思考。

課外資料

這是用於在 Keras 中指定神經網絡(包括 CNN)的備忘單。

https://s3.amazonaws.com/assets.datacamp.com/blog_assets/Keras_Cheat_Sheet_Python.pdf

參閱 CIFAR-10 競賽的獲勝架構!

http://blog.kaggle.com/2015/01/02/cifar-10-competition-winners-interviews-with-dr-ben-graham-phil-culliton-zygmunt-zajac/

7.突破性的cnn架構

7.1 AlexNet

2012年多倫多大學團隊完成,採用Relu激活函數和Dropout來避免過擬合。

在這裏插入圖片描述

參閱 AlexNet 論文!

http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf

7.2 VGG

2014年,牛津大學視覺集合小組開發,包括VGG16,VGG19兩個版本

在這裏插入圖片描述

在此處詳細瞭解 VGGNet

https://arxiv.org/pdf/1409.1556.pdf

7.3 ResNet

2015微軟開發,在ImageNet數據庫的圖片分類方面取得了驚人的效果;

在這裏插入圖片描述

此處是 ResNet 論文。
https://arxiv.org/pdf/1512.03385v1.pdf

其他文檔:

這是用於訪問一些著名 CNN 架構的 Keras 文檔。
https://keras.io/applications/

閱讀這一關於梯度消失問題的詳細處理方案。

http://neuralnetworksanddeeplearning.com/chap5.html

這是包含不同 CNN 架構的基準的 GitHub 資源庫。
https://github.com/jcjohnson/cnn-benchmarks

訪問 ImageNet Large Scale Visual Recognition Competition (ILSVRC) 網站。

http://www.image-net.org/challenges/LSVRC/

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