圖像識別為什么使用CNN?
我們知道CNN常常被用在圖像處理上,當然也可以用一般的神經網絡做圖像處理,input一張圖像,把圖像表示成里面的像素點,也就是一個很長的向量,output就是類別,1000個類別就是1000個維度。
實際上,我們訓練神經網絡的時候,知道網絡結構里的每一個神經元代表了一個最基本的分類器,實際很多文獻也得出這樣的結論。例如第一個隱藏層的神經元是最簡單的分類器,檢測綠色、黃色、斜紋等等特征是否出現,第二個隱藏層的神經元做比第一個隱藏層更復雜的東西,根據第一層的output,如果看到直線橫線,就判斷是窗框的一部分,看到棕色的直線紋就判斷是木紋,看到斜條紋加灰色就判斷是輪胎的一部分。第三層再根據第二層的output,會做更復雜的事情,比如看到蜂巢就激活,看到車輪被激活,看到人的上半身被激活。
現在問題是使用一般的全連接神經網絡做圖像處理,往往會需要很多的參數。如果是一張100 * 100 * 3的彩色圖像,其實算很小的圖像了,把它變成向量會有100 * 100 * 3個數,一個像素點用3個數表示,那這個向量就是3萬維。input 是3萬維,假設每層隱藏層有1000個神經元,那么第一個隱藏層的參數就有30000 * 1000個了,參數太多了。
CNN其實是簡化神經網絡的架構,根據人的知識知道有一些參數是用不上的,那么一開始就過濾掉。
CNN比一般的DNN還要簡單,把DNN里的一些參數去掉,就是CNN。
為什么可以去掉一些參數?
在圖像處理里,我們知道大部分圖案是比整張圖像小的,如果第一層隱藏層某個神經元是在偵測某一種圖案是否出現,那就只需要看圖像的一小部分。
比如上圖,有些神經元在偵測鳥嘴,有些在偵測爪子,有些在偵測翅膀、尾巴,之后合起來就可以偵測鳥是否出現。假設第一層隱藏層的某個神經元是在偵測鳥嘴是否出現,那就只需要紅色框框里的圖像就可以了。
所以每個神經元只需要連接到一個小區域,不需要連接整個圖像。
為什么可以去掉一些參數?
第二個觀察可以看到,同樣的圖案(代表同樣的含義或形狀)會出現在圖像的不同部分,但是使用同樣的神經元和參數可以偵測出來。
比如上圖里兩個鳥嘴,不需要訓練兩個不同的檢測器去分別檢測左上角鳥嘴和中間鳥嘴,這樣過於冗余。可以讓這兩個神經元用同一組參數,做的事情是一樣的。
這樣就可以減少需要的參數量。
我們可以對一張圖像做子采樣,把奇數行偶數列的像素點拿掉,變成原來的1/10的大小,這樣做不會影響人對這張圖像的理解,如上面兩張圖像,看起來可能沒有區別。
所以做子采樣這件事情,對圖像識別來說,可能沒有太多影響,用這個思想把圖像縮小,就可以減少需要的參數量
CNN架構
首先,input一張圖像,然后通過卷積層,接下來通過池化層,再通過卷積層,再通過池化層。卷積層+池化層這個流程可以反復數次(具體幾次要事先決定)。做完卷積和池化后,要做flatten(壓平),把flatten的輸出丟到全連接神經網絡里,最后得到圖像識別的結果。
我們基於對3個圖像處理的特性得出了CNN架構
第一個特性是:要偵測一個圖案,不需要看整張圖,只需要圖像的一小部分
第二個特性是:同一個圖案,會出現在一張圖像的不同區域
第三個特性是:我們可以做子采樣
第一個、第三個特性對應卷積層的處理,第三個特性對應池化層的處理
卷積層的作用
類比第一個特性:圖案比整張圖像小
假設input是一張6 * 6 的圖像(黑白的,每個像素點只需要一個值來表示),例如上圖1代表有墨水,0代表沒有墨水。在卷積層里,有一堆過濾器,每個過濾器作用等同於全連接神經網絡里的每個神經元。每個過濾器是一個矩陣,例如上圖的過濾器是3 x 3的矩陣,而矩陣里的每個值就是網絡的參數,跟神經元的權重和偏差一樣,要通過訓練數據學習出來。3 * 3 的過濾器意味着在一個3 * 3范圍內偵測圖案,不看整個圖像,只在3 * 3范圍內決定一個圖案是否出現。
過濾器如何起作用?
有第一個3 * 3 矩陣,放在圖像左上角(卷積的方式),圖像里的3 * 3 矩陣\(\begin{bmatrix} 1 & 0&0 \\ 0 & 1&0 \\0&0&1 \\ \end{bmatrix}\)和過濾器做內積,結果為3。然后過濾器移動一個步長=1到\(\begin{bmatrix} 0 & 0&0 \\ 1 & 0&0 \\0&1&1 \\ \end{bmatrix}\)和過濾器做內積為-1
如果步長=2,那么就是移動到\(\begin{bmatrix} 0 & 0&0 \\ 0 & 0&1 \\1&1&0 \\ \end{bmatrix}\),內積是-3。
類比第二個特性:同一個圖案,會出現在一張圖像的不同區域
我們這里設置步長=1
內積的結果如上圖右下所示,一個6 * 6矩陣,經過卷積后得到一個4 * 4矩陣。
觀察過濾器矩陣的值,斜對角全為1,所以作用就是檢測斜對角有沒有出現(1,1,1),在整個圖像里就是檢測有沒有斜對角為(1,1,1)的圖案,如上圖藍色斜線。
4 * 4矩陣中,左上和左下出現了最大的值,說明過濾器要偵測的圖案出現在了原圖像的左上角和左下角。
這里考慮到了特性二,兩個不同位置的相同圖案都用過濾器1就可以偵測出來。
在一個卷積層里,會有一大堆的過濾器,之前只是一個過濾器的結果。會有另一個過濾器,有不同的參數,例如上圖的過濾器2,起作用的形式和過濾器1一樣,和圖像矩陣做內積,得到另一個4 * 4的矩陣。
兩個4 * 4矩陣(上圖紅色矩陣和藍色矩陣)合起來叫做feature map(特征圖),有100個過濾器,就有100個 image。
之前是黑白的圖像,如果使用彩色圖像呢?
彩色圖像由RGB組成,一張彩色圖像就是3個矩陣(立方體)疊在一起。這時候過濾器就不是一個矩陣,過濾器也是一個立方體。彩色圖像由RGB表示一個像素點,input就是3 * 6 * 6,過濾器就是3 * 3 * 3。
三個顏色代表三個channel(通道),過濾器有3個矩陣,每個矩陣和對應的channel(通道)做內積。
卷積和全連接有什么關系?
卷積這件事情,就是一個全連接層去掉一個權重,特征圖的output就是一個隱藏層神經元的output。
給像素點編號,從左到右,從上到下編號為1,2,3...,34,35,36
把過濾器1放在左上角做內積得到一個值3,考慮的像素點編號是1,2,3,7,8,9,13,14,15
拉直6 * 6 圖像變成一個長度為36的向量,過濾器1考慮的像素點如上圖右邊所示,相當於一個output 為3的神經元連接到1,2,3,7,8,9,13,14,15像素點,神經元的連接權重就是過濾器里的值。如上圖所示顏色相同的線和圈。
本來一個全連接的神經元要連接36個像素點,現在只連接9個像素點,因為我們知道偵測一個圖案不需要看整張圖像,就看9個像素點表示的區域就行了。這么做,就用了比較少的參數。
過濾器在圖像上移動一個步長=1,output=-1。這個-1是另外一個神經元的output,這個神經元連接到編號為2,3,4,8,9,10,14,15,16的像素點,連接權重還是過濾器的值。這意味着,原本在全連接結構中有各自獨立參數的兩個神經元,在做卷積的時候,不僅連接的權重數量減少了,而且共用了權重值。例如output=3的神經元連接到像素點1的權重等於output=-1的神經元連接到像素點2的權重。那么共用權重值,意味着使用的參數數量更少了。
卷積怎么訓練參數(過濾器的值)?
跟原來的反向傳播一樣,只是有些權重永遠等於0,不去訓練。用一般的反向傳播方法,算出一個權重的梯度,然后把被共享的權重的梯度平均,再用平均后的梯度去update參數。
池化層的作用
池化,就是做子采樣。
根據過濾器1,得到一個4 * 4的矩陣,根據過濾器2,得到另一個4 * 4的矩陣。把output 4個一組,每組里可以取平均、取最大,把原來的4個值合成一個值,這樣就可以把圖像縮小。
現在取最大max
可能會有問題說把這種max操作放到網絡里不就沒法微分了嗎?
其實是可以的,類似Maxout做微分。
做一次卷積+池化后,把原來的6 * 6圖像變成了2 * 2圖像,2 * 2圖像的深度(每個像素點用多少個值表示)取決於有多少個過濾器,如果有50個過濾器,2*2 圖像就有50維,上圖是只用兩個過濾器,那就是2維。
所以上圖右邊,就是一個新的比較小的圖像,每個過濾器代表了一個channel(通道)。
卷積+池化,可以重復疊加很多次,通過一個卷積+池化,就得到一個新的比較小的圖像,再做一次又是一個更小的圖像。
這里有個問題,就是第一個卷積后得到25個矩陣,第二卷積有25個過濾器,那是不是之后會有25*25個矩陣?
不會這樣,做完第一次卷積得到25個矩陣,做完第二次后還是25個矩陣。例如輸入是三個通道的6*6矩陣數據(一個立方體,6 * 6 * 3),有兩個過濾器(也是立方體,三個通道,3 * 3 * 3),則輸出為4 * 4 * 2。
那第二層的過濾器其實是3 *3 *2 的,變成兩個通道的了,輸出后還是2個通道的。
看吳恩達老師的深度學習可能清楚一點。
最后是flatten(壓平)和全連接神經網絡部分。
flatten(壓平)的意思是,把特征圖拉直,然后丟到一個全連接神經網絡里。
CNN在學什么?
分析第一個層的過濾器是比較容易的,里面每個過濾器就是一個3 * 3 的矩陣,對應3 * 3 范圍內的9個像素點,只要看到矩陣的值,就知道在檢測什么。
第二層的過濾器沒法知道在做什么,雖然也是3 *3的矩陣,總共50個。但是這些過濾器的輸入不是像素點,而是在上一層做完卷積和池化后的輸出。就算知道第二層過濾器的矩陣值,也不知道在檢測什么。另外第二層過濾器考慮的不是原圖3 *3的像素點,而是比原圖3 *3 像素點更大的范圍,因為在第一層的池化后,壓縮了原圖3 *3的區域,第二層過濾器是在壓縮后的圖像里再選取3 * 3 像素點,相當於擴大了原圖檢測的范圍。
那怎么分析第二層過濾器在做什么?
第二層的50個過濾器,每個過濾器的輸出是一個11 * 11的矩陣。把第k個過濾器輸出拿出來如上圖左下,矩陣元素表示為\(\large a_{ij}^k\) (第k個過濾器,第i個行,第j個列)。接來下定義一個“Degree of the activation of the k-th filter”(第k個濾波器的激活程度),值代表第k個過濾器的被激活程度(input和第k個過濾器偵測的東西有多匹配)。
第k個過濾器被激活程度表示為:\(\large \alpha^k=\sum\limits_{i=1}^{11}\sum\limits_{j=1}^{11}a_{ij}^k\),11 * 11 矩陣所有元素值之和。
找一張圖像,可以讓第k個過濾器被激活程度最大,如果做到這件事情?
稱input的圖像為x,目標是找一個讓\(\alpha^k\)最大的x,如何找到這個x?
使用梯度上升,因為我們的目標是最大化\(\large \alpha^k\) 。現在是把x當做我們要找的參數,對x用梯度上升。原來CNN的input是固定的,model的參數使用梯度下降求解。現在反過來,model的參數是固定的,使用個梯度上升更新x,讓被激活程度最大。
上圖左下,是隨便取12個過濾器后對x做梯度上升后的結果,每個過濾器都找到一張圖像,這張圖像讓這個過濾器的被激活程度最高。如果有50個過濾器,理論上可以找50張圖像。
這12張圖像有一個共同的特征:是某種紋路在圖上不斷反復。為什么會這樣?
看第三張圖像,都是小小的斜條紋,這意味着第三個過濾器是在檢測是否有斜的條紋。因為過濾器考慮的范圍是很小的,所以原圖像上任何地方出現一個小小的斜紋的話,這個過濾器就會被激活,輸出值就會很大。如果原圖像所有范圍都是這種小小的條紋,那這個過濾器的被激活程度就最大。
你會發現每個過濾器都是在檢測某一種圖案(某一種線條),例如上圖左下第3個過濾器是檢測斜條紋,第4個是檢測短、直的線條,第6個是檢測斜成一定程度的線條等等。
每個過濾器都在檢測不同角度的線條。
接下來分析全連接的隱藏層。
做完卷積和池化后,會做flatten(壓平),把壓平后的結果丟到神經網絡里去。我們也想知道在這個神經網絡的隱藏層里,每個神經元都在干什么。如法炮制之前的做法,定義第j個神經元的輸出是\(\large a_j\),然后找一張圖像x,使\(\large a_j\)最大。
找到的圖像如上圖左下所示,9張圖像,是對應神經元的輸出最大。你會發現跟剛才過濾器觀察的圖案很不一樣,過濾器觀察的是類似紋路的東西,因為過濾器只考慮了原圖像的一部分區域。輸出通過壓平后,現在每個神經元是去看整張圖像,能使神經元激活程度最高的圖像不再是紋路這種小圖案,而是一個完整的圖形,雖然看起來完全不像是數字,但神經元被激活后也的確在偵測一個完整的數字。
考慮最后的輸出呢?
如果最后的輸出是10維的,每一維對應一個數字。把某一維拿出來,找一張圖像使那個維度的輸出最大。例如現在要找一張圖像,使輸出層上對應數字1的神經元的輸出最大,理論上這張圖像看起來就是數字1
但是實際的圖像如上圖左邊所示,每張圖像分別代表0,1,2,3,4,5,6,7,8
那為什么是這種像電視雪花一樣的圖像,而不是數字呢?
因為今天這個神經網絡,學習到的東西跟人類一般認知是不一樣的。
能不能讓這些圖像看起來更像數字?
我們知道,一張圖像是不是一個數字,有一些基本的假設。比如上圖左邊,人類看起來顯示不是數字。那么我們對x做一些正則約束,告訴機器,雖然有些x可以讓y很大,但是這些x不是數字。
那加些什么約束呢?
比如最簡單的想法,圖像上的白點是有墨水(筆畫)的地方,對一個數字來說,有白點的部分是有限的,數字的筆畫只占圖的一小部分,所以我們要對x做一些限制。
假設\(\large x_{ij}\)是圖像像素點的值,每張圖像有28 * 28個像素點。把所有像素點的值取絕對值並求和(相當於L1正則),我們希望找一個x,讓\(y^i\)越大的同時,也讓像素點絕對值之和越小。那我們找出來的圖像大部分的地方就不是白色的。
最后得到的結果如上圖右邊所示,和左邊的圖看起來,已經可以隱約看出來是個數字了。
Deep Dream
你給機器一張圖像,機器會在這張圖像里面,加上它學習到的東西。
比如把上圖丟到CNN里面去,然后把某過濾器或者某個全連接隱藏層拿出來(一個向量),假設是\(\begin{bmatrix} 3.9 \\ -1.5 \\ 2.3 \\ \vdots \end{bmatrix}\)
然后把3.9、2.3調大(本來是正的值調大),-1.5調小(負的值調小),正的更正,負的更負。找一個圖像使過濾器或者隱藏層(拿出來的)的輸出是調整后的向量。這么做的意思是讓CNN誇大化它看到的東西。
找到的圖像會變成上圖所示,出現很多奇怪的東西。右邊看起來是一頭熊,原來是一顆石頭。對機器來說,本來就覺得石頭像一頭熊,強化它的認知后,就學習出來更像一頭熊的圖案。這個就是Deep Dream。
Deep Style
比Deep Dream更進階的版本
今天input一張圖像,然后讓機器去修改這張圖像,讓它有另一張圖的風格,比如讓上圖看起來是吶喊。
得到的結果就如上圖。
這個做法的精神是,把原來的圖像丟給CNN,得到CNN過濾器的輸出,代表一張圖像里有什么樣的內容。
然后把吶喊這張圖也丟到CNN里,也得到過濾器的輸出,但這時候考慮的不是過濾器輸出的絕對值,而是考慮過濾器和過濾器輸出之間的關系,這個關系代表了一張圖像的風格。接下來用同一個CNN找一張圖像,這張圖像的內容像原圖像的內容(過濾器的輸出類似),同時這張圖像的風格像吶喊的風格(過濾器輸出之間的關系類似)。
找一張圖片同時最大化內容和風格(使用梯度上升更新參數),得到的結果就像兩張圖片結合一樣。
CNN應用在圍棋上
CNN現在應用在不同領域,不只是圖像處理,比如知名的應用有下圍棋。
為什么可以用在下圍棋上?
要讓機器下圍棋,不一定要用CNN,一般的神經網絡也可以做這件事情。只要學習一個網絡,也就是找一個函數,輸入是棋盤,輸出是棋盤上的位置,根據棋盤的盤勢,判斷下一步落子的位置。
輸入是19 * 19 向量,向量每一維是棋盤上的一個位置(是黑子則值為1,是白子則值為-1,反之則為0),丟到一個全連接的神經網絡,輸出也是19 * 19 的向量(每一維對應棋盤一個位置),那這樣機器就可以學會下圍棋了。
實際采用CNN會得到更好的效果
采用CNN是什么意思?
之前舉的例子都是把CNN用在圖像上面,input是一個矩陣。用到下棋上,只要把19 * 19 的向量表示為19 * 19 的矩陣。對CNN來說,就是把棋盤和棋子當成一個圖像,然后輸出下一步落子的位置。
收集很多棋譜,告訴CNN,看到落子在5之五,輸出天元的位置為1,其他位置為0
看到5之五和天元都有棋子,輸出就是5之五的位置為1,其他位置為0
這個是監督的部分,AlphaGo還有強化學習的部分
什么時候用CNN?為什么可用在圍棋上?
圖像要有該有的特性,開頭講過的根據三個特性設計出了CNN的網絡結構,在處理圖像的時候特別有效。
那為什么這樣的結構可以用在圍棋上?
因為圍棋有一些特性和圖像處理是很相似的。
我們說過,在一張圖像上面,有一些圖案是比整張圖像小的,比如鳥嘴。在圍棋也有同樣的現象,比如看到一些棋子擺放的圖案,就要做一些相應的事情(比如上圖黑子叫吃的時候,白子要落在下方保證不被吃)。不需要看整個棋盤,只需要看一個小小的范圍,就可以偵測白子是不是屬於被叫吃的狀態。AlphaGo里第一層的過濾器就是用的5 * 5過濾器,顯然設計這個過濾器的人覺得圍棋上最基本的圖案在5 *5 范圍內就可以被偵測出來。
圖像還有個特性是相同的圖案會出現在不同的區域,在圍棋上也有同樣的特征。例如叫吃的圖案,可以出現在棋盤左上角,也可以出現在棋盤右下角,圖案代表了同樣的意義(叫吃),所以可以用同一個檢測器來處理這些在不同位置的圖案。
所以圍棋是有圖像的第一個和第二個特性的。
困惑的是圖像的第三個特性,對原圖像做子采樣不會影響人看到的這張圖像的樣子,基於第三個特性有了池化層。
對圍棋來說,可以做子采樣嗎?
比如丟棄棋盤的奇數行和偶數列,想想也應該是不可以的。
也許AlphaGo里的CNN架構有特殊的地方。AlphaGo論文附錄里描述了它的網絡結構,input是一個19 *19 *48的圖像,19 *19 是棋盤可以理解,但48是怎么來的?
對AlphaGo來說,把每一個位置都用48個值來描述(卷積后有48個通道)。本來我們只要描述一個位置是不是白子、黑子就可以了,而AlphaGo加上了領域知識(看這個位置是不是出於叫吃的狀態等等)。
AlphaGo有做zero padding(零填充),在原來19 *19 的圖像外圍補上0值變成23 * 23 的圖像,第一層用的是5 *5 過濾器,總共k個過濾器(paper里用的是192個過濾器),步長stride=1,有用到ReLu作為激活函數,有2到12層的過濾器層,最后變成21 *21的圖像,接下來再使用 3 * 3的過濾器,步長stride=1。最后發現AlphaGo沒有使用池化,針對圍棋特性設計CNN結構的時候,是不需要池化這個結構的。
CNN應用在語音處理上
一段聲音被表示成頻譜圖,橫軸是時間,縱軸是聲音頻率。例如上圖偏紅色的區域,代表那一段時間里,頻率的能量比較大。
上圖是說你好的頻率圖,左邊紅色是你,右邊紅色是好。人通過訓練看頻譜圖,可以知道是什么音素、聲音訊號,判斷說的是什么。
既然人可以學習,那也可以讓機器學習。把頻譜圖當做一張圖像,input到CNN里,學習音素和聲音訊號。神奇的是,把頻譜圖丟進CNN里的時候,在語音上我們通常只考慮在頻率方向移動過濾器,也就是過濾器是長方形的,像上圖所示的過濾器移動方向。
為什么不在時間方向移動過濾器呢?
在時間方向移動沒有太大的幫助,因為在語音處理里,CNN的輸出后面還會接上別的東西,比如LSTM等等(已經考慮到了時間上的信息),所以在CNN里再考慮一次時間上的信息就沒有什么特別大的幫助。
為什么頻率上的過濾器有幫助?
過濾器的目的是為了檢測出現在不同區域的同樣的圖案,在聲音訊號上,雖然男士和女生說同樣的話,頻譜圖看起來不一樣,但實際上可能只有一個頻率的偏移而已。男士說你好和女生說你好,頻譜圖的圖案是差不多的,有差的可能就是頻率(低頻和高頻),相當於把相同的圖案放在頻率圖的不同位置,所以過濾器在頻率方向移動又有效的。
CNN用在一個領域上,永遠要想想這個領域的特性是什么,根據特性來設計網絡結構。
CNN應用在文字處理上
假設input一個句子,要做的是判斷這個句子是積極的還是消極的。首先要做的事是把句子里的詞語用向量表示,每個向量代表這個詞語本身的含義,如果兩個詞語的含義越接近,對應向量在高維空間上越接近。這個東西叫詞嵌入。
當把每個詞語用向量表示的時候,把句子里所有的詞語再排在一起,就相當於一張圖片,那就可以用CNN了。
把CNN用在文字處理上,過濾器如上圖所示,高等於圖像的高。把過濾器沿着詞語的順序移動,不同的過濾器會得到不同的向量,接下來做池化,把池化的結果放到全連接神經網絡里。
在文字處理里,過濾器只在時間的序列上移動。在詞向量上,不同維度之間是獨立的,在上面做卷積學不到維度與維度之間的關系(同樣的圖案出現在不同的位置)