最近,在看caffe源碼時,偶然在網上看到一個問題?覺得挺有意思,於是,仔細的查了相關資料,並將總結寫在這里,供大家迷惑時,起到一點啟示作用吧。
問題的題目是CNN中的一個卷積層輸入64個通道的特征子圖,輸出256個通道的特征子圖,那么,該層一共包含多少個卷積核?
對於上面這個問題,目前有兩種答案,每一種答案的區別是所基於的卷積核的維度不同而導致的。下面是兩種答案的解析過程:
第一種答案:卷積核是二維的(caffe源碼中以卷積核二維轉化成相應矩陣),那么就需要64*256個卷積核來對輸入特征子圖進行卷積,其中,輸入的每個通道對應64種不同的卷積核進行卷積,再將64種卷積核得到的卷積結果合並成一張輸出特征子圖;這樣,就會得到256個通道的特征子圖。
第二種答案:卷積核是三維的(caffe大神賈楊清老師的回答中就是這么認為的),那么一個卷積核的表示為C*H*W(C:通道數,H:卷積核的高,W:卷積核寬)。那么對於輸入的特征子圖,就需要一個大小為64*h*w的卷積核進行卷積,得到一張特征子圖。這樣,就需要256個不同卷積核,每個卷積核的通道數為64,從而得到256個通道的特征子圖。
顯然,這兩種答案都有一定的依據,不管如何認為,其最終的目的都是要將卷積層復雜的卷積問題轉化為矩陣的相乘問題,從而大大的提高計算速度。
那么,肯定有很多朋友,尤其是像我這種深度學習的菜鳥,一開始還是比較迷糊的,對於上面的解釋還是不知所雲。那么,下面,我就來對這兩種觀點進行具體分析,不足之處,希望大家能指出來,共同學習。
一,卷積核是二維的:
我們知道,在caffe中卷積層的運算是首先通過img2col()將各個卷積核和輸入特征子圖轉化為向量,然后多個卷積核或輸入特征子圖的向量組合成為矩陣;接下來,通過矩陣相乘運算得到卷積的結果,再通過col2img()將向量轉化為特征子圖。M個卷積核卷積一張輸入圖像的矩陣計算如下圖所示:
圖來自http://www.cnblogs.com/laiqun/p/6055498.html
其中,M表示二維卷積核的個數,K=k*k表示二維卷積核的大小;這樣,每個k*k大小的二維卷積核轉化為一個行向量,M個二維卷積核對應M個行向量就得到了M*K的卷積矩陣A。
再說矩陣B:假設輸入的每張特征子圖大小為r*r,二維卷積核的大小為k*k,擴展大小pad,步長為stride,那么對於每張特征子圖,按卷積核每次卷積圖像的大小k*k,將該塊卷積的圖像轉化為行向量,長度也為k*k=K,這樣,依據卷積核與輸入圖像卷積的過程,將每一次卷積核卷積的區域轉化為一個行向量,各個行向量按照卷積先后順序以列進行排列,從而得到了矩陣B。此外,對於卷積后得到的二維特征子圖的大小,在caffe中的計算公式如下(這里假設,輸入圖像和卷積和大小都是q*q的,即長與寬相等):
輸出特征子圖大小:n*n=[(r+2*pad-k)/strde+1]*[(r+2*pad-k)/strde+1]
如果我們令pad=0,stride=1,那么就會變成我們熟悉的形式,即n*n=[(r-k)+1]*[(r-k)/+1]。比如,輸入特征圖大小為32*32,卷積核大小為3*3,那么輸出的特征子圖大小為(32-3+1)*(32-3+1)=28*28。
好了,現在我們知道了矩陣B的列N=n*n,然后通過矩陣相乘運行,即A*BT=(M*K)*(N*K)T=(M*K)*(K*N)=(M*N)=C,即得到了最終的矩陣C。當然,在caffe中可能會存在偏置項,那么這個矩陣C還要加上偏置矩陣P,然后得到最終的輸出矩陣D,再通過col2img()將D中的每一行轉化為一張特征圖,就得到了輸出的各個特征子圖,從而完成了該卷積層的卷積運算。
二,卷積核是三維的:
對於卷積核是三維的情況,主要參考的是賈楊清老師在知乎上的一個解答。即認為每個輸入圖像和每個卷積核的大小表示為C*H*W,即:
由上圖知道,一個輸入特征圖的表示是C*H*W(通道數*長*寬),一個卷積核的大小表示為C*K*K(注意:這里,如果認為卷積核是三維的,就必須保證卷積核的通道數跟輸入特征圖的通道數相同,否則卷積失敗),那么根據卷積核一次卷積的圖像區域,將該區域圖像轉化為行向量,即得到一個C*k*k的行向量。
按此方式,將一張圖像按照卷積的順序得到的行向量按列排列,就得到了最終的特征矩陣如下:
上圖知道,對於一個C*H*W的圖像,按照卷積核大小進行卷積,轉化為的特征矩陣大小為:(H*W)*(C*K*K)。
那么,對於多個卷積核而言,將多個卷積核轉化為卷積矩陣過程如下:
這里,卷積核的個數為Cout,每個卷積核的大小為C*K*K,同理,將每個卷積核轉化為一個行向量C*K*K,按照卷積核個數按列排列,就得到卷積矩陣Cout*(C*K*K)。
最后,將卷積矩陣與輸入特征矩陣的轉置進行相乘,就得到了最終的輸出特征矩陣[Cout*(C*K*K)]*[(H*W)*(C*K*K)]T=[Cout*(C*K*K)]*[(C*K*K)*(H*W)]=Cout*(H*W)。這樣,再將輸出矩陣的每一行轉化為一張特征圖,就得到了Cout張輸出特征子圖。而這,也就印證了:卷積層輸出的特征圖個數等於卷積核的個數。
以上,就是對兩種對於卷積核的維度不同看法的具體分析,不管怎么定義,都有其充分的理由和實踐證明。並且,最重要的是,不管卷積核定義為二維還是三維,都是為了數據轉化為矩陣的形式,從而將卷積層的復雜的卷積過程,轉化為矩陣的相乘的簡單運算,大大的提高了計算的速度。
最后,通過一個具體的例子,來看一下將卷積轉化為矩陣運算的過程:
參考鏈接:http://www.cnblogs.com/laiqun/p/6055498.html
https://www.zhihu.com/question/28385679
Convolution in Caffe: a memo · Yangqing/caffe Wiki · GitHub
https://hal.archives-ouvertes.fr/file/index/docid/112631/filename/p1038112283956.pdf