Tensorflow快餐教程(9)-卷積
卷積
卷積就是滑動中提取特徵的過程
在數學中,卷積convolution是一種函式的定義。它是通過兩個函式f和g生成第三個函式的一種數學運算元,表徵函式f與g經過翻轉和平移的重疊部分的面積。其定義為:
$h(x)=f(x)*g(x) =int_{-infty}^{infty}f(t)g(x-t)dt$
也可以用星號表示:$h(x)=(f*g)(x)$
卷積的第一個引數(上例中的f),通常叫做輸入。第二個引數(函式g)叫做核函式kernel function。輸出有時候叫特徵對映feature map.
也可以定義離散形式的卷積:
$h(x)=(f*g)(x) = sum_{t=-infty}^{infty}f(t)g(x-t)$
g(x-t)是變化的,而f(t)是固定不動的。我們可以將卷積理解成是g(x-t)滑動過程中對f(t)進行取樣。
我們一般可以用$f(x)=wx+b$來作為核函式提取特徵
我們來舉個小例子說明一下卷積對於特徵提取的過程。
假設有一個5*5的矩陣做為輸入:
array([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]], dtype=float32)
y=wx+b我們取w為3*3的全1矩陣,b=0。
這樣我們計算左邊第一個3*3的小塊,得$1*1+1*1+1*1+1*1+1*1+1*1+1*1+1*1+1*1=9$。
以此類推,最後我們得到一個
[[9,9,9],
[9,9,9],
[9,9,9]]
的矩陣。
相當於我們把一個55的黑白矩陣壓縮成了33的灰度矩陣。
全是1的話大家看不太清楚,我們選一個對角矩陣再來計算一下:
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]], dtype=float32)
計算卷積之後的結果為:
[[3,2,1],
[2,3,2],
[1,2,3]]
影像縮小了之後,仍然是主對角線最黑。基本特徵還是被提取出來了。
填充Padding
從前面對角線的例子可以看出,由於圖片中間的點被計算的次數多,而邊緣上的點計算的次數少,所以明明右上角和左下角都是0,提取完特徵之後被中間的1給影響了。
我們可以選擇給這個55的矩陣外邊加上一圈padding,將其變成77的矩陣。
我們再重新計算一下卷積,獲取下面一個5*5的新矩陣:
[[2,2,1,0,0],
[2,3,2,1,0],
[1,2,3,2,1],
[0,1,2,3,2],
[0,0,1,2,2]]
這樣邊緣的0就被識別出來了。Padding的最主要作用就是讓邊界變得更清晰。
步幅Stride
上面我們求卷積的時候,每次向右移到一步,這個移動距離就是Stride。
比如我們想把圖片壓縮得更狠一點,取得更高的壓縮率,我們就可以加大步幅。
卷積用Tensorflow實現
上面知識儲備已足,我們開始用Tensorflow來計算卷積吧。
首先是輸入,按照Tensorflow的要求,我們得把5*5的,resize成[1,5,5,1]格式的,如下:
>>> c
array([[[[1.],
[0.],
[0.],
[0.],
[0.]],
[[0.],
[1.],
[0.],
[0.],
[0.]],
[[0.],
[0.],
[1.],
[0.],
[0.]],
[[0.],
[0.],
[0.],
[1.],
[0.]],
[[0.],
[0.],
[0.],
[0.],
[1.]]]], dtype=float32)
然後我們還需要準備卷積核,先生成一個3*3全1矩陣:
>>> a2 = sess.run(tf.ones([3,3]))
>>> a2
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=float32)
然後將其reshape成[3,3,1,1]格式的:
>>> a3 = sess.run(tf.reshape(a2,[3,3,1,1]))
>>> a3
array([[[[1.]],
[[1.]],
[[1.]]],
[[[1.]],
[[1.]],
[[1.]]],
[[[1.]],
[[1.]],
[[1.]]]], dtype=float32)
步幅我們設成[1,1,1,1],其實就是x軸1,y軸1,前面和後面的1先不用管它。padding設成`SAME`:
>>> a1 = tf.nn.conv2d(c,a3,strides=[1,1,1,1],padding=`SAME`)
>>> sess.run(a1)
array([[[[2.],
[2.],
[1.],
[0.],
[0.]],
[[2.],
[3.],
[2.],
[1.],
[0.]],
[[1.],
[2.],
[3.],
[2.],
[1.]],
[[0.],
[1.],
[2.],
[3.],
[2.]],
[[0.],
[0.],
[1.],
[2.],
[2.]]]], dtype=float32)
結果看起來不爽的話,我們再重新將其reshape成[5,5]的:
>>> a5 = tf.reshape(a4,[5,5])
>>> sess.run(a5)
array([[2., 2., 1., 0., 0.],
[2., 3., 2., 1., 0.],
[1., 2., 3., 2., 1.],
[0., 1., 2., 3., 2.],
[0., 0., 1., 2., 2.]], dtype=float32)
嗯,是不是跟我們手動計算的一樣呢?恭喜你,已經學會卷積啦!
池化層
池化層跟卷積也很像,但是計算要簡單得多。池化主要有兩種,一種是取最大值,一種是取平均值。而卷積是要做矩陣內積運算的。
我們以2*2最大池化為例,處理一下上節加了padding的卷積
[[2,2,1,0,0],
[2,3,2,1,0],
[1,2,3,2,1],
[0,1,2,3,2],
[0,0,1,2,2]]
最大池化就是取最大值,比如[[2,2],[2,3]]就取3。結果如下:
[[3,3,2,1],
[3,3,3,2],
[2,3,3,3],
[1,2,3,3,]]
可以看到,池化雖然進一步丟失了資訊,但是基本規律還是不變的。
池化被認為可以提高泛化性,對於微小的變動不敏感。比如對於少量的平移,旋轉或者縮放保持同樣的識別。但是,池化層不是必須的。
在Tensorflow中,可以用tf.nn.max_pool來實現最大池功能。
首先我們要把圖片resize成(-1,高,寬,1)這樣格式的:
>>> b = tf.reshape(a,[-1,5,5,1])
>>> c = sess.run(b)
array([[[[1.],
[0.],
[0.],
[0.],
[0.]],
[[0.],
[1.],
[0.],
[0.],
[0.]],
[[0.],
[0.],
[1.],
[0.],
[0.]],
[[0.],
[0.],
[0.],
[1.],
[0.]],
[[0.],
[0.],
[0.],
[0.],
[1.]]]], dtype=float32)
然後我們用步幅為2。2*2視窗計算max pooling。
命令如下:
d =tf.nn.max_pool(c,ksize=[1,2,2,1], strides=[1,2,2,1], padding=`SAME`)
四元組中我們不必管第一個和最後一個,中間兩個是高和寬。ksize和步幅皆如此。
執行結果是一個3*3的對角陣:
>>> sess.run(d)
array([[[[1.],
[0.],
[0.]],
[[0.],
[1.],
[0.]],
[[0.],
[0.],
[1.]]]], dtype=float32)
卷積網路的結構
卷積神經網路也叫卷積網路,是一種善於處理網格資料的網路。典型應用是處理一維網格資料語音和二維網格資料影像。只要是在網路結構中使用了哪怕一層的卷積層,就叫做卷積神經網路。
與之前介紹的神經網路都是全連線網路,即每一層的每個節點都是上一層的所有節點相連線。
而卷積網路一般是五種連線結構的組合:
- 輸入層:一般認為就是原圖片
- 卷積層:與全連線網路不同,卷積層中每一個節點的輸入只是上一層神經網路的一小塊,常用的塊大小為33或者55。一般來說,通過卷積層處理過的節點的矩陣的深度會變深
- 池化層:Pooling層不會改變矩陣的深度,但是會使矩陣變小。可以理解為池化層是把高解析度的圖片轉化成低解析度的圖片
- 全連線層:最後的分類工作一般還是由一至兩個全連線層來實現的。
- Softmask層:可以得到當前樣例屬於不同分類的概率情況
卷積網路簡史
上節深度學習簡史中我們提到過,第一個卷積網路模型於1989年由Yann LeCun提出。卷積網路的主要概念如為什麼要卷積,為什麼要降取樣,什麼是徑向基函式RBF(Radial Basis Function)等。
10年後的1998年,Yann LeCun設計了LeNet網路。在論文《Gradient-Based Learning Applied to Document Recognition》中提出了LeNet-5的模型,結構如下:
論文原文在:http://yann.lecun.com/exdb/publis/pdf/lecun-98.pdf
但是,正如我們前面介紹的,當時還是SVM輝煌的時代。
轉折點要到十幾年後的2012年,Hinton的學生Alex Krizhevsky發明的AlexNet之時。AlexNet在2012年的影像分類競賽中將Top-5錯誤率從上一年的25.8%降到15.3%.
AlexNet成功之後,大家的研究熱情空前高漲。主要方向有網路加深和功能增強。
- 網路加深:深度學習的優勢就是突破了加深層數的關鍵點。那麼就可以構建比AlexNet層數更多的網路。代表作是2014年ImageNet比賽的亞軍牛津大學的VGGNet,它的層數可以達到16~19層。從而將Top-5錯誤率從AlexNet的15.3%降到了7.32%.
- 功能增強:代表作是GoogLeNet。GoogLeNet參考了NIN(Network In Network)的思想,將原來的線性卷積層改成了多層感知機。同時,將全連線層改進為全域性平均池化。功能增強之後,GoogLeNet力壓VGGNet,獲得2014年ImageNet的冠軍,將Top-5錯誤率降到6.67%. 雖然功能有增強,但是在層數上GoogLeNet也毫沒客氣地增加到22層。後來在GoogLeNet的基礎上又推出Inception V3, V4等網路。
- 既加深也增強:代表作是2015年的ImageNet分類冠軍,由微軟亞洲研究院發明的ResNet殘差網路。ResNet在2015年的成績把錯誤率降到3.57%.
話說ImageNet真是個群英薈萃的地方。2012年第一名是Alex。2013的第一名是Matthew Zeiler,之前講過他提出的AdaGrad。
值得一提的是,在最近幾年的ImageNet中,華人屢創佳績。比如2016年的冠軍被公安部第三研究所搜神團隊獲得,成績是錯誤率2.99%。
相關文章
- Tensorflow快餐教程(4) - 矩陣矩陣
- 用TensorFlow搭建卷積神經網路識別數字0~9卷積神經網路
- Tensorflow-卷積神經網路CNN卷積神經網路CNN
- 利用 TensorFlow 實現卷積自編碼器卷積
- 【Tensorflow_DL_Note6】Tensorflow實現卷積神經網路(1)卷積神經網路
- 【Tensorflow_DL_Note7】Tensorflow實現卷積神經網路(2)卷積神經網路
- Tensorflow快餐教程(11) – 不懂機器學習就只調API行不行?機器學習API
- Tensorflow快餐教程(11)-不懂機器學習就只調API行不行?機器學習API
- TensorFlow上實現卷積神經網路CNN卷積神經網路CNN
- TensorFlow實戰卷積神經網路之LeNet卷積神經網路
- TensorFlow 卷積神經網路之貓狗識別卷積神經網路
- TensorFlow卷積網路常用函式引數詳細總結卷積函式
- TensorFlow 卷積神經網路系列案例(1):貓狗識別卷積神經網路
- TensorFlow 一步一步實現卷積神經網路卷積神經網路
- 5.2.1.1 卷積卷積
- 卷積核卷積
- 【TVM 教程】如何在 GPU 上最佳化卷積GPU卷積
- 帶你認識9種常用卷積神經網路卷積神經網路
- 基於卷積神經網路和tensorflow實現的人臉識別卷積神經網路
- 數字訊號處理:線性卷積、迴圈卷積、圓周卷積計算卷積
- 卷積神經網路四種卷積型別卷積神經網路型別
- 影像處理中的valid卷積與same卷積卷積
- 5.2.1.3 卷積層卷積
- 1*1卷積卷積
- 卷積步長卷積
- 圖卷積神經網路(GCN)理解與tensorflow2.0程式碼實現卷積神經網路GC
- 9 大主題卷積神經網路(CNN)的 PyTorch 實現卷積神經網路CNNPyTorch
- 卷積導向快速傅立葉變換(FFT/NTT)教程卷積FFT
- 卷積自編碼卷積
- Dilated Convolutions 空洞卷積卷積
- 空洞卷積 Dilated Convolution卷積
- 2.0 卷積網路卷積
- 深度可分離卷積卷積
- 卷積神經網路中的Winograd快速卷積演算法卷積神經網路演算法
- 使用tensorflow和cnn(卷積神經網路)識別驗證碼並構建APICNN卷積神經網路API
- 神經網路之卷積篇:詳解卷積步長(Strided convolutions)神經網路卷積IDE
- 卷積神經網路卷積神經網路
- 卷積 隨筆備份卷積