[caffe解读] caffe从数学公式到代码实现2-基础函数类
接著上一篇,本篇就開始讀layers下面的cpp,先看一下layers下面都有哪些cpp。
absval_layer.cpp
其中,下面這些layer是不需要反向傳播的,大部分都是io類,我們就不講了,自己去看。
threshold_layer.cpp
剩下的就是要講的,我們先從官方的開始看,后面再看自己寫的以及一些開源的。這些layers大概有這么幾大類,基礎數學函數類,blob shape操作類,loss類。
本節先看一些基礎函數類的layer,都只有一個輸入,一個輸出。注意其中有一些是容許inplace 的layer,有一些是不容許的。所謂inplace,輸入輸出共用一塊內存,在layer的傳播過程中,直接覆蓋,省內存。Caffe在開源框架中,是比較占內存的了。
01
absval_layer.cpp
數學定義:
由于這是第一個例子,我們說的詳細些;
Forward:
template <typename Dtype>
其中,count是blob的size,等于N*C*H*W,bottom[0]是輸入x,top[0]是輸出f(x),利用mutable_cpu_data來寫入,cpu_data來讀取。
Backward:
template <typename Dtype>
根據梯度下降法和鏈式法則,
一次標準的梯度更新過程如下,wt+1=wt+Δwt,對于sgd算法,其中 wt=?η?gt ,w為參數,t為時序,Δ為更新量,η為學習率,g為梯度
其中梯度g就是
在backward中,我們只需要計算出即可,至于上面的符號,學習率等在其他地方處理,其實就是
其中其實top_diff,就是對應:
const Dtype* top_diff = top[0]->cpu_diff();
在這里我們知道了,cpu_data就是bottom的data,而cpu_diff就是它存儲的梯度,有疑問可以返回上一篇。
propagate_down是一個參數,用于控制是否容許梯度下傳的,
caffe_cpu_sign(count, bottom_data, bottom_diff);實際上就是計算了梯度,
再利用caffe_mul(count, bottom_diff, top_diff, bottom_diff);
就OK了
沒有對應的test文件,就不解析了。
02
exp_layer.cpp
看下caffe 關于其參數的定義:
數學定義:
// Message that stores parameters used by ExpLayer
從下面的setuplayer中可以看出,如果base不是-1,則必須是大于0的數,也就是-2,-3等是不支持的。
const Dtype base = this->layer_param_.exp_param().base();
當base=-1,也就是默認時f(x)=e^{αx+β},就是我們熟悉的指數函數了
還記得指數函數求導吧;
03
log_layer.cpp
數學定義:
同樣base=-1是默認值,否則必須大于0
04
power_layer.cpp
數學定義:
梯度也是很簡單的,不過為了提高計算效率,caffe盡可能的復用了中間結果,尤其是在反向傳播的時候,分兩種case,完整的計算大家還是去看代碼,這里粘代碼太難受了。
05
tanh_layer.cpp
數學定義:
這一次咱們遇到有test layer,仔細說說。
在caffe/test目錄下test_tanh_layer.cpp
所謂測試,就是要驗證網絡的正向和反向。
這個文件是這樣測試的:
先定義了個tanh_na?ve函數,然后利用GaussianFille初始化一個bottom,將其通過forward函數,把出來的結果和tanh_na?ve的結果進行比對,完整代碼如下,感受一下:
void TestForward(Dtype filler_std) {
EXPECT_NEAR函數就會檢查梯度是否正確,如果過不了,就得回去看forward函數是否有錯了。
反向驗證:
void TestBackward(Dtype filler_std) {
其中GradientChecker(const Dtype stepsize, const Dtype threshold,
const unsigned int seed = 1701, const Dtype kink = 0.,const Dtype kink_range = -1)
可以設置stepwise和誤差閾值,CheckGradientEltwise是逐個像素檢查。
06
sigmoid_layer.cpp
數學定義:
07
?relu_layer.cpp
數學定義:
其中negative_slope a默認=0,退化為f(x)=max(x,0)
上面的relu其實包含了我們常說的relu和ReLU和LeakyReLU
08
?prelu_layer.cpp
與LeakyReLU不同的是,負號部分的參數a是可學習的并不固定。所以,在反向傳播時,該參數需要求導,默認a=0.25。
數學定義
此處的a是個變量。
首先,對x也就是bottom的求導
代碼如下
if (propagate_down[0]) {
而scale參數的求導,則會稍微復雜些,如下
if (this->param_propagate_down_[0]) {
因為對于blob中第i個數據, 當i不等于k時,yi 與xk是沒有關系的,但是a卻與blob中的所有數據有關系。
我們重新表述一下
09
elu_layer.cpp
數學定義:
10
bnll_layer.cpp
數學定義:
這次就先這樣。
同時,在我的知乎專欄也會開始同步更新這個模塊,歡迎來交流
https://zhuanlan.zhihu.com/c_151876233
注:部分圖片來自網絡
—END—
打一個小廣告,我的攝影中的圖像基礎技術公開課程《AI 程序員碼說攝影圖像基礎》上線了,主要從一個圖像處理工程師的角度來說說攝影中的基礎技術和概念,歡迎大家訂閱交流。
加入我們做點趣事
往期精彩
?
[caffe解讀] caffe從數學公式到代碼實現1-導論。
如何步入深度學習刷榜第一重境界。
為了壓榨CNN模型,這幾年大家都干了什么。
?
?
總結
以上是生活随笔為你收集整理的[caffe解读] caffe从数学公式到代码实现2-基础函数类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [caffe解读] caffe从数学公式
- 下一篇: [caffe解读] caffe从数学公式