一、卷積
我們在2維上說話。有兩個的函數 f(x, y) 和 g(x, y)。f 和 g 的卷積就是一個新的的函數。通過下式得到:
這式子的含義是:遍覽從負無窮到正無窮的全部 s 和 t 值,把 g 在 位置上的值乘上 f 在 (s, t) 位置上的值之后“加和”(積分意義上)到一起,就是為 c 在 (x, y) 位置上的值。說白了卷積就是一種“加權求和”。以 (x, y) 為中心,把 g 距離中心 位置上的值乘上 f 在 (s, t) 的值,最后加到一起。把卷積公式寫成離散形式就更清楚了:
如果表示一幅 100×100 大小的灰度圖像,取值 [0, 255] 區間內的整數,是圖像在 (x, y) 的灰度值。范圍外的 (x, y) 上的值全取0。令在 s 和 t 取 {-1,0,1}的時候有值,其他位置全是0。可以看作是一個 3×3 的網格。如下圖:
圖1
每個小格子里的值就是圖像在 (x, y)的灰度值。每個小格子里的值就是在(s, t)的值。
圖2
如上圖所示,將的中心(0, 0)對準的(5, 6)。把和對應的9個位置上各自的函數值相乘,再將9個乘積加在一起,就得到了卷積值 C (5, 6)。對的每一個位置求 C值,就得到了一幅新的圖像。其中有兩個問題:
如果的所有值之和不等于1.0,則 C值有可能不落在 [0,255] 區間內,那就不是一個合法的圖像灰度值。所以如果需要讓結果是一幅圖像,就得將歸一化——令它的所有位置之和等于1.0;
對于邊緣上的點,有可能它的周圍位置超出了圖像邊緣。此時可以把圖像邊緣之外的值當做0。或者只計算其周圍都不超邊緣的點的 C。這樣計算出來的圖像 C就比原圖像小一些。在上例中是小了一圈,如果覆蓋范圍更大,那么小的圈數更多。
上述操作其實就是對數字圖像進行離散卷積操作,又叫濾波。稱作卷積核或濾波器。不同的濾波器起不同的作用。想象一下,如果的大小是 3×3,每個格子里的值都是1/9。那么濾波就相當于對原圖像每一個點計算它周圍 3×3 范圍內9個圖像點的灰度平均值。這應該是一種模糊。看看效果:
圖3
左圖是 lena 灰度原圖。中圖用 3×3值都為1/9的濾波器去濾,得到一個輕微模糊的圖像。模糊程度不高是因為濾波器覆蓋范圍小。右圖選取了 9×9 值為1/81的濾波器,模糊效果就較明顯了。濾波器還有許多其他用處。例如下面這個濾波器:
嘗試用它來濾 lena 圖。注意該濾波器沒有歸一化(和不是1.0),故濾出來的值可能不在[0,255]之內。通過減去最小值、除以最大/最小值之差、再乘以255并取整,把結果值歸一到[0,255]之內,使之成為一幅灰度圖像。
圖4
該濾波器把圖像的邊緣檢測出來了。它就是 Sobel算子。圖像模糊、邊緣檢測等等都是人們設計出來的、有專門用途的濾波器。如果搞一個 9×9 的隨機濾波器,會是什么效果呢?
圖5
如上圖,效果也類似于模糊。因為把一個像素點的值用它周圍 9×9 范圍的值隨機加權求和,相當于“搗漿糊”。但可以看出模糊得并不潤滑。
這時我們不禁要想,如果不是由人來設計一個濾波器,而是從一個隨機濾波器開始,根據某種目標、用某種方法去逐漸調整它,直到它接近我們想要的樣子,可行么?這就是卷積神經網絡(Convolutional Neural Network, CNN)的思想了。可調整的濾波器是CNN的“卷積”那部分;如何調整濾波器則是CNN的“神經網絡”那部分。
二、神經網絡
人工神經網絡(Neural Network, NN)作為一個計算模型,其歷史甚至要早于計算機。W.S.McCulloch 和 W.Pitts 在四十年代就提出了人工神經元模型。但是單個人工神經元甚至無法計算異或。人工智能領域的巨擘馬文。明斯基認為這個計算模型是沒有前途的。在那時人們已經認識到將多個人工神經元連接成網絡就能克服無法計算異或的問題,但是當時沒有找到多層人工神經網絡的訓練方法,以至于人工神經網絡模型被壓抑多年。直到人們找到了多層人工神經網絡的訓練方法,人工神經網絡才迎來了輝煌。
人工神經元就是用一個數學模型簡單模擬人的神經細胞。人的神經細胞有多個樹突和一個伸長的軸突。一個神經元的軸突連接到其他神經元的樹突,并向其傳導神經脈沖。一個神經元會根據來自它的若干樹突的信號決定是否從其軸突向其他神經元發出神經脈沖。
圖6
一個人工神經元就是對生物神經元的數學建模。見下圖。
圖7
是人工神經元的輸入。a 是人工神經元的輸出。人工神經元將輸入加權求和后再加上偏置值 b,最后再施加一個函數 f,即:
上式最后是這個式子的向量形式。P 是輸入向量,W是權值向量,b 是偏置值標量 。f稱為“激活函數”。激活函數可以采用多種形式。例如 Sigmoid函數:
這是單個人工神經元的定義。人工神經網絡就是把這樣的人工神經元互聯成一個網絡:一個神經元的輸出作為另一個神經元的輸入。神經網絡可以有多種多樣的拓撲結構。其中最簡單的就是“多層全連接前向神經網絡”。它的輸入連接到網絡第一層的每個神經元。前一層的每個神經元的輸出連接到下一層每個神經元的輸入。最后一層神經元的輸出就是整個神經網絡的輸出。
如下圖,是一個三層神經網絡。它接受10個輸入,也就是一個10元向量。第一層和第二層各有12個神經元。最后一層有6個神經元。就是說這個神經網絡輸出一個6元向量。
圖8
整個神經網絡的計算可以用矩陣式給出。我們給出人工神經網絡單層的式子。每層的神經元個數不一樣,輸入/輸出維度也就不一樣,計算式中的矩陣和向量的行列數也就不一樣,但形式是一致的。假設我們考慮的這一層是第層。它接受個輸入,擁有個神經元(個輸出),那么這一層的計算如下式所示:
上標 i 表示第 i 層。是輸出向量,n 元,因為第 i 層有 n 個神經元。第 i 層的輸入,即第 i -1 層的輸出,是 m 元向量。權值矩陣 W是 n×m 矩陣:n 個神經元,每個神經元有 m 個權值。W乘以第 i -1 層輸出的 m 向量,得到一個 n 向量,加上 n 元偏置向量 b,再對結果的每一個元素施以激活函數 f,最終得到第 i 層的 n 元輸出向量。
若不嫌繁瑣,可以將第 i -1 層的輸出也展開,最終能寫出一個巨大的式子。它就是整個全連接前向神經網絡的計算式。可以看出整個神經網絡其實就是一個向量到向量的函數。至于它是什么函數,就取決于網絡拓撲結構和每一個神經元的權值和偏置值。如果隨機給出權值和偏置值,那么這個神經網絡是無用的。我們想要的是有用的神經網絡。它應該表現出我們想要的行為。
要達到這個目的,首先準備一個從目標函數采樣的包含若干“輸入-輸出對兒”的集合——訓練集。把訓練集的輸入送給神經網絡,得到的輸出肯定不是正確的輸出。因為一開始這個神經網絡的行為是隨機的。
把一個訓練樣本輸入給神經網絡,計算輸出與正確輸出的(向量)差的模平方(自己與自己的內積)。再把全部 n 個樣本的差的模平方求平均,得到 e:
e 稱為均方誤差 mse。e 越小則神經網絡的輸出與正確輸出越接近。神經網絡的行為就與想要的行為越接近。
目標是使 e 變小。在這里 e 可以看做是全體權值和偏置值的一個函數。這就成為了一個無約束優化問題。如果能找到一個全局最小點,e 值在可接受的范圍內,就可以認為這個神經網絡訓練好了。它能夠很好地擬合目標函數。這里待優化的函數也可以是 mse 外的其他函數,統稱 Cost Function,都可以用 e 表示。
經典的神經網絡的訓練算法是反向傳播算法(BP,Back Propagation)。BP 算法屬于優化理論中的梯度下降法(Gradient Descend)。將誤差 e 作為全部權值 W 和全部偏置值 B的函數。算法的目的是在自變量空間內找到 e 的全局極小點。
首先隨機初始化全體權值 W和全體偏置值 B,之后在自變量空間中沿誤差函數 e 在該點的梯度方向的反方向(該方向上方向導數最小,函數值下降最快)前進一個步長。步長稱為學習速率(Learning Rate,η)。如此反復迭代,最終(至少是期望)解運動到誤差曲面的全局最小點。
下圖是用 matlab訓練一個極簡單的神經網絡。它只有單輸入單輸出。輸入層有兩個神經元,輸出層有一個神經元。整個網絡有4個權值加3個偏置。圖中展示了固定其他權值,只把第一層第一個神經元的權值和偏置做自變量時候的 mse 曲面,以及隨著算法迭代,解的運動軌跡。
圖9
最終算法沒有收斂到全局最優解(紅+)。但是解已經運動到了一個峽谷的底部。由于底部過于平緩,解“走不動”了。所得解比最優也差不到哪去。
對于一個稍復雜的神經網絡,e 對 W和 B的函數將是一個非常復雜的函數。求梯度需要計算該函數對每一個權值和偏置值的偏導數。所幸的是,每一個權值或偏置值的偏導數公式不會因為這個權值或偏置值距離輸出層越遠而越復雜。計算過程中有一個中間量,每層的權值和偏置值的偏導數都可根據后一層的以統一形式計算出來。每層再把計算過程中產生的傳遞給前一層。這就是“反向傳播”名稱的由來——沿著反向向前傳。這與計算網絡輸出時,計算結果向后傳相反。如此可逐層計算出全部權值和偏置值的偏導數,得到梯度。具體推導這里不給出了,可以參考[1]第八章和[2]第十一章。正是反向傳播能夠讓我們訓練神經網絡“深處”的參數,這就是“Deep Learning”的含義。
梯度下降法有很多變體。通過調整步長 η 可以提高收斂速度;通過增加沖量可以避免解陷入局部最優點。還可以每一次不計算全部樣本的 mse,而是隨機取一部分樣本,根據它們的 mse 更新權值。這樣可以減少計算量。梯度下降是基于誤差函數的一階性質。還有其他方法基于二階性質進行優化,比如共軛法、牛頓法等等。優化作為一門應用數學學科,是機器學習的一個重要理論基礎,在理論和實現上均有眾多結論和方法。參考[1]。
三、卷積神經網絡
現在把卷積濾波器和神經網絡兩個思想結合起來。卷積濾波器無非就是一套權值。而神經網絡也可以有(除全連接外的)其它拓撲結構。可以構造如下圖所示意的神經網絡:
圖10
該神經網絡接受個輸入,產生個輸出。圖中左邊的平面包含 n×n 個格子,每個格子中是一個[0,255]的整數值。它就是輸入圖像,也是這個神經網絡的輸入。右邊的平面也是 n×n 個格子,每個格子是一個神經元。每個神經元根據二維位置關系連接到輸入上它周圍 3×3 范圍內的值。每個連接有一個權值。所有神經元都如此連接(圖中只畫了一個,出了輸入圖像邊緣的連接就認為連接到常數 0)。右邊層的個神經元的輸出就是該神經網絡的輸出。
這個網絡有兩點與全連接神經網絡不同。首先它不是全連接的。右層的神經元并非連接上全部輸入,而是只連接了一部分。這里的一部分就是輸入圖像的一個局部區域。我們常聽說 CNN 能夠把握圖像局部特征、alphaGO 從棋局局部狀態提取信息等等,就是這個意思。這樣一來權值少了很多,因為連接就少了。權值其實還更少,因為每一個神經元的9個權值都是和其他神經元共享的。全部個神經元都用這共同的一組9個權值,并且不要偏置值。那么這個神經網絡其實一共只有9個參數需要調整。
看了第一節的同學們都看出來了,這個神經網絡不就是一個卷積濾波器么?只不過卷積核的參數未定,需要我們去訓練——它是一個“可訓練濾波器”。這個神經網絡就已經是一個拓撲結構特別簡單的 CNN 了。
試著用 sobel 算子濾出來的圖片作為目標值去訓練這個神經網絡。給網絡的輸入是灰度 lena 圖,正確輸出是經過 sobel 算子濾波的 lena 圖,見圖4。這唯一的一對輸入輸出圖片就構成了訓練集。網絡權值隨機初始化,訓練2000輪。如下圖:
圖11
從左上到右下依次為:初始隨機濾波器輸出、每個200輪訓練后的濾波器輸出(10幅)、最后一幅是 obel 算子的輸出,也就是用作訓練的目標圖像。可以看到經過最初200輪后,神經網絡的輸出就已經和 sobel 算子的輸出看不出什么差別了。后面那些輪的輸出基本一樣。輸入與輸出的均方誤差 mse 隨著訓練輪次的變化如下圖:
圖12
1500輪過后,mse 基本就是0了。訓練完成后網絡的權值是:
與 sobel 算子比較一下:
注意訓練出來的濾波器負數列在右側而不是左側。因為用 sobel 算子算卷積的時候也許庫函數是把濾波器“反著扣上去”的。這并不重要。關鍵是一正列、一負列,中間零值列。正/負列值之比近似1:2:1。它就是近似的 sobel 算子。我們以訓練神經網絡的方式把一個隨機濾波器訓練成了 sobel 算子。這就是優化的魔力。alphaGO 之神奇的核心也在于此:優化。
在 CNN 中,這樣的濾波器層叫做卷積層。一個卷積層可以有多個濾波器,每一個叫做一個 channel,或者叫做一個 feature map。可以給卷積層的輸出施加某個激活函數 Sigmoid、tanh 等等。激活函數也構成 CNN 的一層——激活層,這樣的層沒有可訓練的參數。
還有一種層叫做 Pooling 層。它也沒有參數,起到降維的作用。將輸入切分成不重疊的一些 n×n 區域。每一個區域就包含個值。從這個值計算出一個值。計算方法可以是求平均、取最大 max 等等。假設 n=2,那么4個輸入變成一個輸出。輸出圖像就是輸入圖像的1/4大小。若把2維的層展平成一維向量,后面可再連接一個全連接前向神經網絡。
通過把這些組件進行組合就得到了一個CNN。它直接以原始圖像為輸入,以最終的回歸或分類問題的結論為輸出,內部兼有濾波圖像處理和函數擬合,所有參數放在一起訓練。這就是卷積神經網絡。
四、舉個例子
手寫數字識別。數據集中一共有42000個28×28的手寫數字灰度圖片。十個數字(0~9)的樣本數量大致相等。下圖展示其中一部分(前100個):
圖13
將樣本集合的75%用作訓練,剩下的25%用作測試。構造一個結構如下圖的CNN:
圖14
該CNN共有8層(不包括輸入層)。它接受784元向量作為輸入,就是一幅 28×28 的灰度圖片。這里沒有將圖片變形成 28×28 再輸入,因為在CNN的第一層放了一個 reshape 層,它將784元的輸入向量變形成 1×28×28 的陣列。最開始那個 1× 表示只有一個 channel,因為這是灰度圖像,并沒有 RGB 三個 channel。
接下來放一個卷積層。它包含32個濾波器,所以它的輸出維度是 32×28×28。32個濾波器搞出來32幅圖像(channel),每個都是 28×28 大小。后面又是一個32個濾波器的卷積層,輸出維度也是 32×28×28。
后面接上一個 Pooling 層,降降維。一個 2×2 的取平均值 Pooling 層,把輸出維度減小了一半:32×14×14。接著是一個展平層,沒有運算也沒有參數,只變化一下數據形狀:把 32×14×14 展平成了6272元向量。
該6272元向量送給后面一個三層的全連接神經網絡。該網絡的神經元個數是 1000×1000×10。兩個隱藏層各有1000個神經元,最后的輸出層有10個神經元,代表10個數字。假如第六個輸出為1,其余輸出為0,就表示網絡判定這個手寫數字為“5”(數字“0”占第一個輸出,所以“5”占第六個輸出)。數字“5”就編碼成了:
訓練集和測試集的數字標簽都這么編碼(one-hot 編碼)。
全連接神經網絡這部分的激活函數都采用了 Sigmoid。這出于我一個過時且膚淺的理解:用“彎彎繞”較多的 Sigmoid 給網絡貢獻非線性。實際上當代深度學習從生物神經的行為中得到啟發,設計了其它一些表現優異的激活函數,比如單邊線性 Relu。
誤差函數采用均方誤差 mse。優化算法采用 rmsprop,這是梯度下降的一個變體。它動態調整學習速率(步長 η)。訓練過程持續10輪。注意這里10輪不是指當前解在解空間只運動10步。一輪是指全部31500個訓練樣本都送進網絡迭代一次。每次權值更新以32個樣本為一個 batch 提交給算法。下圖展示了隨著訓練,mse 的下降情況:
圖15
下圖是分類正確率隨著訓練的變化情況:
圖16
該CNN在測試集上的正確率(accuracy)是96.7%,各數字的準確率 / 召回率 / f1-score 如下:
該CNN對測試集10種數字分類的混淆矩陣為:
圖17
訓練完成神經網絡后,最有趣的是將其內部權值以某種方式展現出來。看著那些神秘的、不明所以的連接強度最后竟產生表觀上有意義的行為,不由讓我們聯想起大腦中的神經元連接竟構成了我們的記憶、人格、情感 。。. 引人遐思。
在CNN上就更適合做這種事情。因為卷積層訓練出來的是濾波器。用這些濾波器把輸入圖像濾一濾,看看CNN到底“看到”了什么。下圖用第一、二卷積層的32個濾波器濾了圖13第8行第8列的那個手寫數字“6”。32個 channel 顯示如下:
圖18
圖19
其中有些把邊緣高亮(輸出值較大),有些把“6”的圈圈高亮,等等。這些就是CNN第一步濾波后“看到”的信息。再經過后面的各神經層,抽象程度逐層提高,它就這樣“認出”了手寫數字。
最后把代碼附上。CNN使用的是 keras 庫。數據集來自kaggle:這里。
-
神經網絡
+關注
關注
42文章
4809瀏覽量
102864 -
圖像
+關注
關注
2文章
1094瀏覽量
41044 -
函數
+關注
關注
3文章
4371瀏覽量
64255
發布評論請先 登錄
評論