機器學習實戰(十三):Convolutional Neural Networks

一城山河發表於2020-12-27

本章,首先介紹CNN從哪裡來,構建模組是怎樣的,以及如何使用TF實現

The Architecture of the Visual Cortex

視覺皮層神經元有一塊小的區域性接受野(receptive field),即只對視野的區域性區域視覺刺激做出反應。不同神經元的接受野可能會有重複,一起平鋪在整個視覺區域,可能作用於不用方向。

CNN由此逐漸形成,LeNet-5除了熟知的全連線層、S形啟用函式以外,引入了卷積層和池化層兩個新的構建塊。

為什麼用部分連線層而不是全連線層DNN進行影像識別的原因是,全連線層對小圖片集(MNIST)作用,但由於大圖片神經元,連線數過多,全連線層就不能很好工作。

Convolutional Layer

CNN最重要的構建塊就是卷積層:在這裡插入圖片描述
如上所示,第一卷積層的6個神經元不會連線到輸入神經元的美俄畫素,而只與接受野內的畫素連線。第二卷積層的每個神經元僅連線第一層中小矩陣內的神經元。總結來說,這種結構允許網路集中在第一個隱藏層的低階特徵中,在下一個隱藏層組裝成比較高階的特徵。這種特性使得CNN在影像識別方面效果好。

我們目前看到的許多神經網路都有 由長神經組成的層,我們必須將圖片平滑到一維才能提供給神經網路。現在每層用二位表示更能將神經元與輸入相匹配。

本層i行,j列的神經元與上次層輸入中的i到i+f_h-1行,j到j+f_w-1列神經元相關聯,f_h和f_w表示接受野的高和寬,為了使本層與上一層同寬高,通常在周圍填充0——零填充(zero padding)。
在這裡插入圖片描述
下圖所示可以通過間隔接受野的方式使得大的輸入層連線到更小的層,兩個連續接受野之間的距離叫步幅。如下圖 5x7輸入層(加零填充)連線3x4,使用3x3接受野,步幅為2(不確定)。即位於上一層的i行、j列神經元與下層is_h到is_h+f_h-1行,js_w到js_w+f_w-1列相連線,其中s_h和s_w分別代表垂直和水平方向步幅。
在這裡插入圖片描述

Filters

神經元權重大小可由接受野大小表示。
在這裡插入圖片描述
如上圖所示的兩個權重集合,稱為過濾器,垂直線過濾器白線為1,其餘 為0,神經元忽略除白線外的內容。水平線過濾器忽略接受野除白色外的部分。
輸入影像分別引用兩過濾器後,輸出特徵圖1、特徵圖2.

Stacking Multiple Feature Maps(特徵圖疊加)

如下圖所示,一個薄層表示一個卷積層(由大小相同的特徵圖組成),所以用三維表示。
同一個特徵圖所有神經元擁有相同引數(權重與偏差)。卷積層同時對輸入使用多個過濾器,使其 能檢測到輸入的多個特徵。
同一特徵圖神經元既可以顯著減少模型中引數數量,而且一旦識別某個地方某個模式,就可以最親愛任何地方識別該模式(傳統DNN只能特定位置識別該模式).
在這裡插入圖片描述
下面輸入影像也是有多個子層(RGB),灰度圖通常只有一個通道。

卷積層l的特徵圖k上的i行j列神經元,與上一層l-1層(穿過本層所有特徵圖)的神經元相連線,位置在is_w到is_w+f_w-1行,js_h到js_h+f_h-1列。
所有位於不同特徵圖i行j列神經元都連線到前一層輸出中完全相同的神經元。

下用公式表明,作用是計算所有輸出的加權值+偏置引數:
在這裡插入圖片描述

  • z (i, j, k)是卷積層l特徵圖k上的神經元在i行j列輸出。
  • s_h、s_w分別是水平方向垂直方向步幅,f_h、f_w分筆試接受野的高和寬,f_n’是l-1層特徵圖數量
  • x(i′, j′, k′)是l-1層位於i’行j’列的特徵圖k’神經元輸出
  • b_k為特徵圖k(l層)偏置引數,即特徵圖k微調亮度按鈕
  • w(u, v, k′ ,k)是l層中任意特徵圖k與位於k’的u行v列輸入之間的連線權重

TensorFlow Implementation

import numpy as np
from sklearn.datasets import load_sample_images

# Load sample images
china = load_sample_image("china.jpg")
flower = load_sample_image("flower.jpg")
dataset = np.array([china, flower], dtype=np.float32)
batch_size, height, width, channels = dataset.shape

# Create 2 filters
filters = np.zeros(shape=(7, 7, channels, 2), dtype=np.float32)#建立兩個7*7過濾器
filters[:, 3, :, 0] = 1  # vertical line
filters[3, :, :, 1] = 1  # horizontal line

# Create a graph with input X plus a convolutional layer applying the 2 filters
X = tf.placeholder(tf.float32, shape=(None, height, width, channels))
convolution = tf.nn.conv2d(X, filters, strides=[1,2,2,1], padding="SAME")
#用卷積層構建構建兩張圖象(0填充,步幅為2)
#conv2d X小批次,filters過濾器(四維張量)
#strides [1,sh,sw,1],中間倆為垂直水平步幅,外面倆為1,可能用來指定批次步幅(跳例項),通道步幅(跳特徵圖或通道)
#padding :SAME 0填充 neural_output = neural_output/stride,向上取整
#          VALID 非0填充 忽略右側和底部的行和列
with tf.Session() as sess:
    output = sess.run(convolution, feed_dict={X: dataset})

plt.imshow(output[0, :, :, 1], cmap="gray") # plot 1st image's 2nd feature map
plt.show()

卷積層有很多超引數,必須選擇過濾器數量、高、寬、步幅以及填充數值。用交叉驗證尋找正確引數過於耗費時間,有很多CNN架構稍後會被討論。

Memory Requirements

CNN領一下問題是需要大量記憶體,訓練期間尤甚(反向椽筆的反向傳遞需要在正向傳遞中計算所有中間值)。
所以當記憶體不足時:

  • 減小mini-batch 尺寸
  • 減少步幅或刪除幾個圖層來降低維度
  • 使用16浮點取代32浮點
  • 分發CNN到多臺裝置上

Pooling Layer

池化層的目的是通過對輸入影像進行二次取樣來減小計算負載,記憶體利用率和引數數量,從而降低over-fitting風險。減小輸入影像大小可以使網路容忍一定的圖樣移位在(位置不變性)。

池化層和卷積層一樣,每個神經元都連線到上一層輸出中矩形的有限個神經元,必須定義接受野的大小、步幅、填充型別,但池化神經元沒有權重,而使用聚合函式(mean or max)聚合輸出。
如圖所示為最大池化層(max pooling layer):池化核心為 2x2,步幅為2,無填充,每個核心最大值才會進入下一層,其他輸入丟棄
在這裡插入圖片描述

兩個方向輸入減少為1/2,總共面積減少75%,即減少75%輸入值。
池化層在各個輸入通道獨立工作,輸出深度輸入深度相同,可以選擇在深度維度疊加(影像高寬不變,通道減少)
TF實現:
建立張量,過濾器

batch_size, height, width, channels = dataset.shape

filters = np.zeros(shape=(7, 7, channels, 2), dtype=np.float32)
filters[:, 3, :, 0] = 1  # vertical line
filters[3, :, :, 1] = 1  # horizontal line

X = tf.placeholder(tf.float32, shape=(None, height, width, channels))
max_pool = tf.nn.max_pool(X, ksize=[1,2,2,1], strides=[1,2,2,1],padding="VALID")
#ksize第一個元素必為1(不支援多個例項相加),不支援空間維度和深度維度相加,ksize[1]、ksize[2]同時為1,否則ksize[3]=1
with tf.Session() as sess:
    output = sess.run(max_pool, feed_dict={X: dataset})
#建立平均池化層(用avg_pool代替max_pool)
plt.imshow(output[0].astype(np.uint8))  # plot the output for the 1st image
plt.show()

CNN Architectures

典型的CNN結構如下所示:在這裡插入圖片描述
堆疊幾個卷積層(每個卷積層通常都有一個ReLU層),然後是一個池化層,接著是另外幾個卷積層(+ReLU)再接一個池化層……影像越來越小,越來越深(有更多的特徵圖),棧頂新增了幾個全連線層組成的常規前反饋神經網路,最後層輸出預測。(卷積核心不要設定太大)
下面介紹經典的LeNet-5架構,然後三個ILVRC獲獎者:AlexNex、GoogLeNet、ResNet。

LeNet-5

在這裡插入圖片描述

  • MNIST 28X28被0填充到32X32,輸入到網路之前進行歸一化處理。其餘不部分不使用填充(影像尺寸越來越小)
  • 池化層:每個神經元計算輸入,乘一個可學習係數(每個特徵圖 一個)並新增一個可學習偏置引數(每個特徵圖一個),最終應用啟用函式。
  • 大多數C3圖中神經元只連線到S2圖中三到四個神經元
  • 輸出層:每個神經元輸出其輸入向量和權值向量之間的歐幾里得距離的平方。每個輸出衡量該圖片屬於某類的可能性,交叉熵代價函式可以很大程度上減少不良預測,產生更大的梯度並因此更快地收斂

演示網址

AlexNet

網址
在這裡插入圖片描述
直接將卷積層堆疊到其它層上。

為了減小過度擬合,使用兩種正則化:

  • 訓練期間輸出層F8、F9使用淘汰策略(50%)
  • 使用偏移、水平翻轉、改變光照條件來訓練移動移動資料

本地響應歸一化(LRN):C1、C3層ReLU後的使用具有競爭性的歸一化步驟,能夠使得最強啟用來抑制不同特徵圖的神經元,改善泛化:
在這裡插入圖片描述
字母含義介紹:
在這裡插入圖片描述
例如,r=2且神經元強啟用,它將一直其上面和下面特徵圖的神經元啟用
Alex超引數設定(r=2, α = 0.00002, β = 0.75,k=1),用TF的 local_response_normaliza
tion()實現

ZF Net是AlexNet變體,只調整了些超引數。

GoogLeNet

網址

GoogLeNet比CNN更深,通過初始化模組使子網變成可能,引數數量只是AlexNet1/10.
在這裡插入圖片描述
3+3+2(S)表示3X3核心,步幅為2,SAME填充。輸入訊號首先複製到四個不同的層,所有的卷積函式使用ReLU啟用函式,第二組卷積層使用不同核心大小(1X1,3X3,5X5),這樣能改用捕捉到不同尺寸的影像模式,每層步長為1,填充為SAME,所以輸入輸出都有相同高寬,使其可以沿著最終的Depth Concat的深度維度連線到所有輸出(從所有的四個頂部的卷積層堆疊特徵圖)。該級聯層可以使用TF的concat(),axis=3(深度)。
核心為1X1卷積層目的:

  • 配置成輸出特徵圖比輸入少,作為瓶頸降低緯度。3X3,5X5之前使用
  • 每個卷積層對[1X1,3X3],[1X1,5X5]作用像同一個強大單獨的卷積層,捕捉更復雜的模式,卷積層能夠掃描影像中兩層神經網路。

將整個初始化模組看成一個超級卷積層,能夠輸出一些用以捕捉各種尺寸複雜模式的特徵圖。

每個卷積層的卷積核心數量是一個超引數,但每個初始層都有6個或更多個超引數。

在這裡插入圖片描述

GoogLeNet包括9個初始化模組(帶轉筒的框),每個包含三層,每個卷積層和每個池化層輸出的特徵圖數量顯示在該核心尺寸之前,初始化模組的6個數字表示模組中每個卷積層輸出特徵圖的數量。
所有卷積層都有ReLU啟用函式。

  • 前兩層影像長寬/4(面積/16)
  • 一個本地響應標準化層確保之前的圖層學習各種各樣的特徵
  • 後面接著兩個卷積層,第一個像瓶頸層,可以看做單一智慧卷積層
  • 本地響應標準化層可確保前面的圖層捕捉到各種各樣的模式
  • 最大池化層將影像高寬減小為1/2增快計算
  • 為了減少緯度加快計算,九個初始化模組與最大池化層堆疊
  • 平均池化層使用具有相同尺寸,填充為VALID的核心,輸入1X1特徵圖——全域性平均池化。有效強制前面的各層產生特徵圖,特徵圖實際上是每個目標類的置信圖(其他型別特徵被平均步驟破壞),無需在CNN頂部配置幾個完全連線層(AlexNet等),從而大大減少了網路中引數數量,降低過度配置風險。
  • 最後一層放棄正則化,使用一個具有softmax啟用函式的完全連線層輸出估計類的概率。

原始GoogLeNet還包括位於第三個第六個初始化模組上的兩個輔助分類器,由一個平均池化層、一個卷積層,兩個全連線層,一個softmax啟用層組成,損失(縮小70%)加到整體損失中,目的是解決梯度消失和網路規範問題。作用相對較小。

ResNet

網址
使用了快捷連線(跳過連線):輸入到一個層中的訊號也被新增到位於堆疊上面的層的輸出端。

訓練神經網路是的目標函式h(x)模型化。若將輸入x新增到網路輸出(新增跳過連線),則網路強制模型化為f(x)=h(x)-x,稱為殘差學習。
在這裡插入圖片描述
初始化一個常規神經網路時,權重接近0,網路輸出接近0,新增跳過連線只是輸出一個輸入的複製。(對認證函式建模),若目標函式接近認證函式將加快訓練速度。

若新增多個跳過連線,即一些層學習還沒有開始,網路就可以開始處理程式。由於跳過連線,訊號輕鬆跨過這個網路。深度殘差網路看做殘差單元,就是一個具有跳過連線的小型網路。
在這裡插入圖片描述
看下ResNet架構,除了沒有淘汰層與谷歌net特別相似,中間是一個很深的簡單殘差單元(由兩個具有BN和ReLU啟用功能的卷積層組成)使用核心並保留維度空間(步幅為1,填充為SAME)

在這裡插入圖片描述
特徵圖數量是每個殘差單元兩倍,同時高寬減半(步幅為2的卷積層),此時不能直接新增到殘差單元輸出(形狀不同),所以需要輸入通過一個具有步幅為2和輸出正常數量特徵圖的1X1卷積層。

ResNet-34是34層ResNet(只計算卷積層和全連線層),包含3個輸出64個特徵圖的殘差單元(RU),4個包含129特徵圖的RU,6個包含256特徵圖的RU和3個包含512張特徵圖的RU:
在這裡插入圖片描述
更深層的ResNets,如-152,輸出殘差單元略歐不同,這裡不深究,有需要看書。

TF其他卷積層:

  • conv1d()用於一維輸入卷積層,如一維陣列,同時接受野覆蓋幾個相鄰單詞
  • conv3d()用於建立三維輸入卷積層,例如三維PET掃描
  • atrous_conv2d()用於建立帶孔卷積層。
  • conv2d_transpose()用於 建立轉置卷積層,用來進行影像提升取樣
  • depthwise_conv2d()用來建立深度卷積層,將每個過濾器應用到每個獨立輸入通道。
  • separable_conv2d()用於建立可分離卷積層,首先類似一個深度卷積層,然後應用一個卷積層輸出特徵圖。

相關文章