Lesson 16.3 卷积操作
3 卷積操作
這里有兩個長度為9的列表,我們讓對應位置的元素相乘,之后再相加:
a?9+b?8+7?c+6?d+5?e+f?4+g?3+h?2+i?1a * 9+b * 8+7 * c+6 * d+5 * e+f * 4+g * 3+h * 2+i * 1a?9+b?8+7?c+6?d+5?e+f?4+g?3+h?2+i?1如果我們把數字列表看作是權重,那以上式子就可以被看做一個加權求和的過程。現在,我們將九個數整理成如下的矩陣:
左側的矩陣我們稱之為字母矩陣,而右側的矩陣稱之為數字矩陣(也就是權重矩陣)。當表示成矩陣之后,我們可以求解兩個矩陣的點積,也就是將對應位置的元素相乘再相加等到一個標量,這與我們剛才實現的加權求和運算本質一致。但此時我們發現,在變成矩陣之前,a對應的是9,i對應的是1,而現在a對應的是1,i對應的是9。如果我們還想實現剛才的加權求和,就需要將數字矩陣在平面上順時針旋轉180度,得到旋轉矩陣:
現在,將旋轉矩陣與字母矩陣求點積,就可以得到與之前的加權求和一樣的結果了:
dotsum?=a?9+b?8+7?c+6?d+5?e+f?4+g?3+h?2+i?1\text { dotsum }=a * 9+b * 8+7 * c+6 * d+5 * e+f * 4+g * 3+h * 2+i * 1 ?dotsum?=a?9+b?8+7?c+6?d+5?e+f?4+g?3+h?2+i?1現在,dotsum的結果就是字母矩陣與原始數字矩陣的卷積。
卷積操作是一種常見的數學計算,二維矩陣的卷積表示其中一個矩陣在平面上旋轉180°后,與另一個矩陣求點積的結果。其中“卷”就是旋轉,“積”就是點積,也就是加權求和。本質上來說,卷積就是其中一個矩陣旋轉180°后,兩個矩陣對應位置元素相乘再加和的結果。這個過程可以使用數學公式表示:[x11x12?x1nx21x22?x2n????xm1xm2?xmn]?[y11y12?y1ny21y22?y2n????ym1ym2?ymn]=∑i=0m?1∑j=0n?1x(m?i)(n?j)y(1+i)(1+j)\left[\begin{array}{cccc} x_{11} & x_{12} & \cdots & x_{1 n} \\ x_{21} & x_{22} & \cdots & x_{2 n} \\ \vdots & \vdots & \ddots & \vdots \\ x_{m 1} & x_{m 2} & \cdots & x_{m n} \end{array}\right] *\left[\begin{array}{cccc} y_{11} & y_{12} & \cdots & y_{1 n} \\ y_{21} & y_{22} & \cdots & y_{2 n} \\ \vdots & \vdots & \ddots & \vdots \\ y_{m 1} & y_{m 2} & \cdots & y_{m n} \end{array}\right]=\sum_{i=0}^{m-1} \sum_{j=0}^{n-1} x_{(m-i)(n-j)} y_{(1+i)(1+j)} ??????x11?x21??xm1??x12?x22??xm2???????x1n?x2n??xmn???????????????y11?y21??ym1??y12?y22??ym2???????y1n?y2n??ymn????????=i=0∑m?1?j=0∑n?1?x(m?i)(n?j)?y(1+i)(1+j)?其中xxx表示其中一個矩陣的值,yyy表示另一個矩陣的值,mmm與nnn分別是兩個矩陣的行數和列數。在其他教材或其他說明中,你可能會見到使用其他符號的二維矩陣的卷積表示,但其本質都與我們所說的“旋轉再求內積”一致。你也可能會見到卷積的代數表示(就是帶積分的那個)、甚至是離散卷積的表示方式,幸運的是那些與矩陣卷積有所不同,因此如果你感覺困惑,你可以不用去理會。
之前我們說過,只要我們對圖像數據進行任意數學運算,且得出的結果不超出圖像的像素范圍[0,255],就可以生成新的圖像。而卷積是一種從兩個矩陣中得出新數值的方式,這個操作正好可以用于圖像的變換。但圖像的矩陣里動輒就幾百萬甚至幾千萬個像素,如何將卷積適用于圖片來得到一張新的圖片(也就是一個新的矩陣)呢?來看一個典型的操作:假設現在的權重矩陣如下:
假設現在的權重矩陣如下:[?101?202?101]\left[\begin{array}{rrr} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{array}\right] ????1?2?1?000?121????我們讓它與下圖中左側的圖像進行卷積。左側的圖像是一個6X6結構的圖像,其左半邊的像素都為10,右半邊像素都為0的圖像,因此看起來,它右側那一半是均勻的顏色,左側那半邊是另一種均勻的顏色,因此中間的豎線就是兩塊均勻顏色中的“邊緣”。為了實現卷積,我將權重矩陣進行了180°的旋轉,圖中所示的是旋轉矩陣。
對于這張圖像,卷積操作是這樣進行的。首先,我們令旋轉矩陣與綠色區域進行點積(對應位置元素相乘再相加),得到卷積結果0,成為新矩陣的第一個元素。接下來,我們在圖片上,將綠色區域向右移動一個像素,再令旋轉矩陣與綠色區域進行點積,得到卷積結果40。
同樣的,我們繼續移動綠色區域,繼續計算點積:
當橫向區域掃描完畢之后,我們向下移動一個像素,繼續從左到右掃描:
以此類推,直到綠色區域掃描完畢整張圖像,得到右側的矩陣:
此時,右側的矩陣就是我們在左圖上使用權重矩陣[?101?202?101]\left[\begin{array}{rrr} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{array}\right] ????1?2?1?000?121????進行卷積計算的結果。我們得到了一張4X4尺寸的圖像,且中間兩列像素為40,兩邊為0,所以是中間較亮,兩邊較暗。原本的圖像在中間有一條明顯的“邊界”,現在我們權重矩陣對這張圖像進行卷積后得出的圖“放大”了這個邊界,讓邊界亮了起來,讓其他地方變暗了,這就實現了對圖像進行“邊緣檢測”。當然,由于我們現在所使用的圖像非常小(像素只有6*6),所以得到的邊緣檢測結果看起來邊緣非常粗,實際上在真實案例中,白色的線會是非常細的。
邊緣檢測是卷積操作的一個常見應用,我們所使用的權重矩陣其實是縱向的索貝爾算子(Sobel
Operator),用于檢測縱向的邊緣,我們也可以使用橫向的索貝爾算子,以及拉普拉斯算子來檢測邊緣。在OpenCV當中我們可以很容易地實現這個操作:
除了邊緣檢測之外,我們還可以使用其他權重矩陣與原圖卷積來修改圖像,例如銳化、模糊等等。
在這些例子中,有一個值得注意的問題:我們首先確立權重矩陣,然后將矩陣旋轉180°之后再與感受野進行點積,這個過程叫做“卷積”,但在實際執行計算的時候,真正發揮作用的使旋轉后的旋轉矩陣。為什么我們不直接定義旋轉矩陣,而要先定義一個權重矩陣,再旋轉它呢?
事實上,就連OpenCV中的sobel和Laplacian函數都沒有進行“旋轉”,而是直接定義了旋轉后矩陣。或許是最初的研究者嘗試了“卷積”操作,就這樣流傳下來,或許是原始權重矩陣的邏輯可能來源于某些理論,不旋轉將會使邊緣檢測失效,但在今天的計算機視覺技術中,尤其是深度學習中,大部分時候我們都不再進行“旋轉”這個步驟了。甚至在許多卷積相關的講解中,會直接忽略旋轉這個步驟,導致許多人無法理解“卷積”的“卷”從何而來。
沒有旋轉,我們也無需在關心最初的矩陣。現在我們只關心與圖像相乘的旋轉矩陣,我們把旋轉矩陣的值稱為權重,將該矩陣稱為過濾器(filter,意為可以過濾出有效的特征),也被叫做卷積核(Convolution Kernel),每個卷積核在原圖上掃描的區域(被標注為綠色的區域)被稱為感受野(receiptive field),卷積核與感受野輪流點積得到的新矩陣被叫做特征圖(feature map)或激活圖(activation map)。當沒有旋轉,只有點積的時候,圖像與矩陣之間的運算就不是數學上的“卷積”,而是“互相關”(cross-correlation)了,但是基于歷史的原因和行業習慣,我們依然把整個過程稱為“卷積操作”,這個名字沿用到今天,也影響了深度學習中對卷積神經網絡的稱呼。
4 卷積遇見深度學習
檢測邊緣、銳化、模糊、圖像降噪等卷積相關的操作,在圖像處理中都可以被認為是在從圖像中提取部分信息,因此這部分圖像處理技術也被叫做“特征提取”技術。卷積操作后所產生的圖像可以作為特征被輸入到分類算法中,在傳統計算機視覺領域,這一操作常常被認為可以提升模型表現并增強計算機對圖像的識別能力。計算機視覺是研究如何讓計算機從圖像或圖像序列中獲取信息并理解其信息的學科,理解就意味著識別、判斷甚至是推斷,因此識別在計算機視覺中是非常核心的需求,卷積操作在傳統計算機視覺中的地位就不言而喻了。數十年來,計算機視覺工程師們使用前人的經驗與研究不斷提取特征,再送入機器學習算法中進行識別和分類。然而,這樣做是有極限的。
在邊緣檢測的例子中,我們看到拉普拉斯和索貝爾算子的檢測是很明顯的。但是,如果使用我們之前導入的孔雀圖像,就會發現邊緣檢測的效果有些糟糕。
img = cv2.imread('/Users/zhucan/Desktop/blue-peacock.jpg') img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)laplacian = cv2.Laplacian(img,cv2.CV_64F,ksize=5) sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5) sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)plt.figure(dpi=300) plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray') plt.title('Original'),plt.axis('off') plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray') plt.title('Laplacian'),plt.axis('off') plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray') plt.title('Sobel X'),plt.axis('off') plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray') plt.title('Sobel Y'),plt.axis('off')
為什么會這樣呢?這是因為,sobel和拉普拉斯算子對邊緣抓取的程度較輕(從圖像處理的原理上來看,他們只求取了圖像上的一維導數,因此效果不夠強),這樣的抓取對于橫平豎直的邊緣、以及色彩差異較大的邊緣有較好的效果,對于孔雀這樣色彩豐富、線條和細節非常多的圖像,這兩種算子就不太夠用了。所以在各種邊緣檢測的例子中,如果你仔細觀察原圖,你就會發現原圖都是輪廓明顯的圖像。
這說明,不同的圖像必須使用不同的權重進行特征提取,同時,我們還必須加深特征提取的深度。那什么樣的圖像應該使用什么樣的權重呢?如何才能夠提取到更深的特征呢?同時,如果過去的研究中提出的算子都不奏效,應該怎么找到探索新權重的方案呢?即便有效地實現了邊檢檢測、銳化、模糊等操作,就能夠提升最終分類算法的表現嗎?其實不然。這些問題困擾計算機視覺工程師許久,即便在傳統視覺中,我們已提出了不少對于這些問題的解決方案,但從一勞永逸的方向來考慮,如果計算機自己能夠知道應該使用什么算子、自己知道應該提取到什么程度就好了。此時,深度學習登場了。
總結
以上是生活随笔為你收集整理的Lesson 16.3 卷积操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Lesson 16.2 图像的基本操作
- 下一篇: 金融风控实战——迁移学习