Caffe原始碼閱讀 1 全連線層

2022-07-13 11:03:11 字數 4060 閱讀 2112

發表於 2014-09-15 |  

今天看全連線層的實現。

主要看的是

主要是三個方法,setup,forward,backward

主體的思路,作者的注釋給的很清晰。

主要是要弄清楚一些變數對應的含義

123

m_ 表示的樣本數

k_ 表示單個樣本的特徵長度

n_ 表示輸出神經元的個數

為了打字方便,以下省略下劃線,縮寫為m,k,n

實現的功能就是 y=wx+b

123

4

x為輸入,維度 mxk

y為輸出,維度 nx1

w為權重,維度 nxk

b為偏置,維度 nx1

具體到**實現,用的是這個函式caffe_cpu_gemm,具體的函式頭為

123

4

void caffe_cpu_gemm(const cblas_transpose transa,

const 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)

略長,整理它的功能其實很直觀,即c←αa×b+βc

123

4567

891011

1213

14

const cblas_transpose transa  # a是否轉置

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

從實際**來算,全連線層的forward包括了兩步:

123

4567

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,對應**是:

1

2

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

公式中的a^(l)_j對應的是bottom_data,維度是kxm

公式中的\delta_(l+1)_i對應的是top_diff,維度是nxm

然後是第二步,更新b,對應**是:

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)。函式頭:

123

4567

891011

1213

1415

1617

1819

void caffe_cpu_gemv(constcblas_transpose transa, const int m,

const 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

繞回到具體的**實現。。如何更新b?根據公式b的梯度直接就是delta

123

4

# 所以對應的**其實就是將top_diff轉置後就可以了(忽略乘上bias_multiplier這步)

caffe_cpu_gemvtype>(cblastrans, m_, n_, (dtype)1., top_diff,

bias_multiplier_.cpu_data(), (dtype)0.,

this->blobs_[1]->mutable_cpu_diff());

第三步是計算delta,對應公式

這裡面可以忽略掉最後一項f』,因為在caffe實現中,這是由relu layer來實現的,這裡只需要實現括號裡面的累加就好了,這個累加其實可以等價於矩陣乘法

123

4567

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層的原始碼,頓...