caffe中卷積運算設計的很巧妙,今天就來討論一下caffe中卷積運算的原理,最後會給出乙個自己的實現版本,便於初學者理解。
俗話說,一圖勝千言,首先先給出原理示意圖,為了方便理解,這裡以二維核為例
滑動視窗在影象中每滑動乙個地方,將影象中該滑動視窗影象展開為一列,所有列組成圖中的滑動視窗矩陣,這裡假設pad=1,stride=1,k=3,則滑動視窗矩陣每行大小為w*h,一共k*k行.
每個核展開為一行,n個核形成的核矩陣大小為n*k*k。
最後將核矩陣和滑動視窗矩陣相乘,每一行就是乙個特徵圖,n個卷積核形成n個特徵圖。
擴充套件到三維核
三維核就是多了乙個通道的概念,原理與二維核一樣。
caffe原始碼中的src\caffe\util\im2col.cpp中的im2col_cpu函式給出了實現,但是個人覺得並不利於初學者的理解,這裡給出乙個自己根據該原理實現的**,這裡只考慮二維核的情況
#define saturate(x) (uchar)(((x) & ~255) == 0 ? (x) : ~((x)>>31))
void convolution1(const mat &srcimage, const mat &kernel, mat &dstimage)}}
// 卷積核與滑動視窗矩陣相乘,這部分可以使用矩陣運算加速(比如blas,eigen)
float *dataofkernel = (float *)kernel.data;
uchar *dataofdst = dstimage.data;
for (int x = 0; x <= slidingwindowmat.cols - 1; ++x)
// 卷積結果賦值為結果影象,注意溢位的處理!
dataofdst[x] = saturate((int)sum);
}} // convolution1
下面是測試**
void testconvolution1()
原圖
結果圖
由於示例程式中的卷積核是垂直方向的sobel運算元,所以結果影象中對垂直方向的邊緣比較敏感,而對水平方向的邊緣不敏感。
2017-5-13 17:04:46
Caffe的卷積原理
caffe中的卷積計算是將卷積核矩陣和輸入影象矩陣變換為兩個大的矩陣a與b,然後a與b進行矩陣相乘得到結果c 利用gpu進行矩陣相乘的高效性 三個矩陣的說明如下 1 在矩陣a中 m為卷積核個數,k k k,等於卷積核大小,即第乙個矩陣每行為乙個卷積核向量 是將二維的卷積核轉化為一維 總共有m行,表示...
caffe中的卷積
如上,將三維的操作轉換到二維上面去做,然後呼叫gemm庫進行矩陣間的運算得到最後結果。兩個矩陣相乘,需要中間的那個維度相同,這個相同的維度就是c k k,其中c是feature map的維度,k為卷積核的邊長。按照卷積核在feature map上面滑窗的順序將其展開成二維的。在三維上面看,就是卷積核...
Caffe中卷積層的實現
出處 將尺寸為k k的卷積核在某個位置對應的feature map區域表示為k k的一維向量 將feature map各個通道對應的向量之間,串聯起來 那麼尺寸k k的卷積核在某個位置對應的各個通道的feature map,組合起來就是長度為c k k的一維向量。當卷積核對應到新的位置上,又得到新的...