發表於 2014-09-15 |
今天看全連線層的實現。
主要看的是
主要是三個方法,setup,forward,backward
主體的思路,作者的注釋給的很清晰。
主要是要弄清楚一些變數對應的含義
123
m_ 表示的樣本數為了打字方便,以下省略下劃線,縮寫為m,k,nk_ 表示單個樣本的特徵長度
n_ 表示輸出神經元的個數
實現的功能就是 y=wx+b
1234
x為輸入,維度 mxk具體到**實現,用的是這個函式y為輸出,維度 nx1
w為權重,維度 nxk
b為偏置,維度 nx1
caffe_cpu_gemm
,具體的函式頭為
1234
void caffe_cpu_gemm(const cblas_transpose transa,略長,整理它的功能其實很直觀,即c←αa×b+βcconst cblas_transpose transb, const int m, const int n, const int k,
const float alpha, const float* a, const float* b, const float beta,
float* c)
1234567
891011
1213
14
const cblas_transpose transa # a是否轉置從實際**來算,全連線層的forward包括了兩步:const cblas_transpose transb # b是否轉置
# 這部分都比較直觀不用解釋了
const int m
const int n
const int k
const float alpha
const float* a
const float* b
const float beta,
float* c
# 其中a維度是mxk,b維度是kxn,c維度為mxn
1234567
8
# 這一步表示 y←wx,或者說是y←xw'分成三步:caffe_cpu_gemmtype>(cblasnotrans, cblastrans, m_, n_, k_, (dtype)1.,
bottom_data, weight, (dtype)0., top_data);
# 這一步表示 y←y+b
caffe_cpu_gemmtype>(cblasnotrans, cblasnotrans, m_, n_, 1, (dtype)1.,
bias_multiplier_.cpu_data(),
this->blobs_[1]->cpu_data(), (dtype)1., top_data);
# 所以兩步連起來就等價於y=wx+b
用公式來說是下面三條:
一步步來,先來第一步,更新w,對應**是:
12
caffe_cpu_gemm(cblastrans, cblasnotrans, n_, k_, m_, (dtype)1.,對照公式,有top_diff, bottom_data, (dtype)0., this->blobs_[0]->mutable_cpu_diff());
123
需要更新的w的梯度的維度是nxk然後是第二步,更新b,對應**是:公式中的a^(l)_j對應的是bottom_data,維度是kxm
公式中的\delta_(l+1)_i對應的是top_diff,維度是nxm
123
caffe_cpu_gemv(cblastrans, m_, n_, (dtype)1., top_diff,這裡用到了bias_multiplier_.cpu_data(), (dtype)0.,
this->blobs_[1]->mutable_cpu_diff());
caffe_cpu_gemv
,簡單來說跟上面的caffe_cpu_gemm
類似,不過前者是計算矩陣和向量之間的乘法的(從英文命名可以分辨,v for vector, m for matrix)。函式頭:
1234567
891011
1213
1415
1617
1819
void caffe_cpu_gemv(constcblas_transpose transa, const int m,繞回到具體的**實現。。如何更新b?根據公式b的梯度直接就是deltaconst int n, const float alpha, const float* a, const float* x,
const float beta, float* y)
# 實現的功能類似 y←αax + βy
# 其中a的維度為 mxn
# x是乙個向量,維度為 nx1
# y是結果 ,也是乙個向量,維度為mx1
constcblas_transpose transa # 是否對a進行轉置
# 下面的引數很直觀,不描述了
const int m
const int n
const float alpha
const float* a
const float* x
const float beta
float* y
1234
# 所以對應的**其實就是將top_diff轉置後就可以了(忽略乘上bias_multiplier這步)第三步是計算delta,對應公式caffe_cpu_gemvtype>(cblastrans, m_, n_, (dtype)1., top_diff,
bias_multiplier_.cpu_data(), (dtype)0.,
this->blobs_[1]->mutable_cpu_diff());
這裡面可以忽略掉最後一項f』,因為在caffe實現中,這是由relu layer來實現的,這裡只需要實現括號裡面的累加就好了,這個累加其實可以等價於矩陣乘法
1234567
caffe_cpu_gemm(cblasnotrans, cblasnotrans, m_, k_, n_, (dtype)1.,top_diff, this->blobs_[0]->cpu_data(), (dtype)0.,
(*bottom)[0]->mutable_cpu_diff());
# top_diff為\delta^(l+1)_j 維度 mxn
# this->blobs_[0]->cpu_data()為w^(l)_ji 維度 nxk
# (*bottom)[0]->mutable_cpu_diff()是要計算的結果,也就是\delta^(l)_i 維度是mxk
caffe原始碼 卷積層
input 3 5 5 c h w pading 1 步長 2 卷積核 2 3 3 3 n c k k output 2 3 3 c h w 如下圖所示 首先需要理解caffe裡面的im2col和col2im 然後 卷積層 其實和 全連線層 差不多了 input 3 4 4 c h w 卷積核 1 ...
caffe原始碼 之 Relu層
本文主要實現caffe框架中 src caffe layers relu layer.cpp檔案,該檔案實現的是啟用函式relu。relu是近些年非常流行的啟用函式。相比於sigmoid與tanh,它具有一定的優越性,這三者對比可見它的函式公式是f x max 0,x 換句話說,這個啟用函式就是乙個...
Roi Pooling層caffe原始碼解讀
在看fasterrcnn以及和maskrcnn的時候,發現自己對fasterrcnn的roi pooling層的原理還是不是很明白,之前只是知道roi pooling是將rpn輸出的乙個roi的區域對映成乙個固定大小的map,再送入後面的分類層進行分類。最近看了下roi pooling層的原始碼,頓...