日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[caffe解读] caffe从数学公式到代码实现5-caffe中的卷积

發布時間:2025/3/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [caffe解读] caffe从数学公式到代码实现5-caffe中的卷积 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天要講的就是跟卷積相關的一些layer了

im2col_layer.cpp

base_conv_layer.cpp

conv_layer.cpp

deconv_layer.cpp

inner_product_layer.cpp

01

im2col_layer.cpp

這是caffe里面的重要操作,caffe為什么這么耗顯存,跟這個有很大關系。im2col的目的,就是把要滑動卷積的圖像,先一次性存起來,然后再進行矩陣乘操作。簡單來說,它的輸入是一個C*H*W的blob,經過im2col操作會變成K' x (H x W) 的矩陣,其中K' =C*kernel_r*kernel_r,kernel_r就是卷積核的大小,這里只看正方形的卷積核。

如果不用這樣的操作,賈揚清有一個吐槽,對于輸入大小為W*H,維度為D的blob,卷積核為M*K*K,那么如果利用for循環,會是這樣的一個操作,6層for循環,計算效率是極其低下的。

for w in 1..W

具體im2col是什么原理呢?先貼出賈揚清的回答,https://www.zhihu.com/question/28385679

上面說了,要把C*H*W的blob,變成K' x (H x W)或者 (H x W) xK' 的矩陣,把filters也復制成一個大矩陣,這樣兩者直接相乘就得到結果,下面看一個簡單小例子。

借用網友一張圖,雖然和caffe細節上不同,但是還是有助于理解。http://blog.csdn.net/mrhiuser/article/details/52672824

4*4的原始數據,進行stride=1的3*3操作,其中im2col的操作就是:

也就是說4*4的矩陣,經過了im2col后,變成了9*4的矩陣,卷積核可以做同樣擴展,卷積操作就變成了兩個矩陣相乘。

下面看im2col的代碼;

template <typename Dtype>

相關注釋已經放在了上面,col2im的操作非常類似,可以自行看源碼,這一段要自己寫出來怕是需要調試一些時間。

有了上面的核心代碼后,Forward只需要調用im2col,輸入為bottom_data,輸出為top_data,Backward只需要調用col2im,輸入為top_diff,輸出為bottom_diff即可,代碼就不貼出了。

02

conv_layer.cpp,base_conv_layer.cpp

數學定義不用說,我們直接看代碼,這次要兩個一起看。由于conv_layer.cpp依賴于base_conv_layer.cpp,我們先來看看base_conv_layer.hpp中包含了什么東西,非常多。

base_conv_layer.hpp變量:

/// @brief The spatial dimensions of a filter kernel.

非常之多,因為卷積發展到現在,已經有很多的參數需要控制。無法一一解釋了,stride_,pad_,dilation是和卷積步長有關參數,kernel_shape_是卷積核大小,conv_input_shape_是輸入大小,output_shape是輸出大小,其他都是以后遇到了再說,現在我們先繞過。更具體的解答,有一篇博客可以參考

http://blog.csdn.net/lanxuecc/article/details/53188738

下面直接看conv_layer.cpp。既然是卷積,輸出的大小就取決于很多參數,所以先要計算輸出的大小。

void ConvolutionLayer<Dtype>::compute_output_shape() {

然后,在forward函數中,

template <typename Dtype>

我們知道卷積層的輸入,是一個blob,輸出是一個blob,從上面代碼知道卷積核的權重存在了this->blobs_[0]->cpu_data()中, this->blobs_[1]->cpu_data()則是bias,當然不一定有值。外層循環大小為bottom.size(),可見其實可以有多個輸入。

看看里面最核心的函數,this>forward_cpu_gemm。

輸入input,輸出col_buff,關于這個函數的解析,https://tangxman.github.io/2015/12/07/caffe-conv/解釋地挺詳細,我大概總結一下。

首先,按照調用順序,對于3*3等正常的卷積,forward_cpu_gemm會調用conv_im2col_cpu函數(在base_conv_layer.hpp中),它的作用看名字就知道,將圖像先轉換為一個大矩陣,將卷積核也按列復制成大矩陣;

然后利用caffe_cpu_gemm計算矩陣相乘得到卷積后的結果。

template <typename Dtype>

反向傳播:

template <typename Dtype>

略去bias,從上面源碼可以看出,有this->weight_cpu_gemm和this->backward_cpu_gemm兩項。

this->backward_cpu_gemm是計算bottom_data的反向傳播的,也就是feature map的反向傳播。

template <typename Dtype>

}

weight_cpu_gemm是計算權重的反向傳播的;

template <typename Dtype>

其中諸多細節,看不懂就再去看源碼,一次看不懂就看多次。

03

?deconv_layer.cpp

卷積,就是將下圖轉換為上圖,一個輸出像素,和9個輸入像素有關。反卷積則反之,計算反卷積的時候,就是把上圖輸入的像素乘以卷積核,然后放在下圖對應的輸出各個位置,移動輸入像素,最后把所有相同位置的輸出相加。

template <typename Dtype>

forward直接調用了backward_cpu_gemm函數,反向的時候就直接調用forward函數,這里肯定是需要反復去理解的,一次不懂就多次。

template <typename Dtype>

04

inner_product_layerfilter.hpp

既然卷積層已經讀過了,現在該讀一讀全連接層了。

全連接層和卷積層的區別是什么?就是沒有局部連接,每一個輸出都跟所有輸入有關,如果輸入feature map是H*W,那么去卷積它的核也是這么大,得到的輸出是一個1*1的值。

它在setup函數里面要做一些事情,其中最重要的就是設定weights的尺寸,下面就是關鍵代碼。num_output是一個輸出標量數,比如imagenet1000類,最終輸出一個1000維的向量。

K是一個樣本的大小,當axis=1,實際上就是把每一個輸入樣本壓縮成一個數,C*H*W經過全連接變成1個數。

const int num_output = this->layer_param_.inner_product_param().num_output();

所以,weight的大小就是N*K_。

有了這個之后,forward就跟conv_layer是一樣的了。

好了,這一節雖然沒有復雜的公式,但是很多東西夠大家喝一壺了,得仔細推敲才能好好理解的。caffe_cpu_gemm是整節計算的核心,感興趣的去看吧!

同時,在我的知乎專欄也會開始同步更新這個模塊,歡迎來交流

https://zhuanlan.zhihu.com/c_151876233

注:部分圖片來自網絡


—END—

打一個小廣告,我的攝影中的圖像基礎技術公開課程《AI 程序員碼說攝影圖像基礎》上線了,主要從一個圖像處理工程師的角度來說說攝影中的基礎技術和概念,歡迎大家訂閱交流。

加入我們做點趣事

微信

Longlongtogo

公眾號內容

1 心路分享|2 攝影知識|3 深度學習

往期精彩

?

[caffe解讀] caffe從數學公式到代碼實現4-認識caffe自帶的7大loss。

?

如何步入深度學習刷榜第一重境界。

總結

以上是生活随笔為你收集整理的[caffe解读] caffe从数学公式到代码实现5-caffe中的卷积的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。