首先看到的是Blob這個類,Blob是做爲Caffe中數據流通的一個基本類,網絡各層之間的數據是經過Blob來傳遞的。這裏整個代碼是很是規範的,基本上條件編譯,命名空間,模板類,各類不太常常看到的關鍵字如exlicit,inline等等。
首先提一下explicit關鍵字的做用是禁止單參數構造函數的隱式轉換,具體含義谷歌便可。還有inline的做用,iniline主要是將代碼進行復制,擴充,會使代碼總量上升,好處就是能夠節省調用的開銷,能提升執行效率。網絡
一、數據結構
shared_ptr<SyncedMemory> data_; shared_ptr<SyncedMemory> diff_; shared_ptr<SyncedMemory> shape_data_; vector<int> shape_; int count_; int capacity_;
BLob只是一個基本的數據結構,所以內部的變量相對較少,首先是data_指針,指針類型是shared_ptr,屬於boost庫的一個智能指針,這一部分主要用來申請內存存儲data,data主要是正向傳播的時候用的。同理, diff_ 主要用來存儲誤差,update data, shape_data 和 shape_ 都是存儲Blob的形狀,一個是老版本一個是新版本。 count 表示Blob中的元素個數,也就是 個數*通道數*高度*寬度, capacity 表示當前的元素個數,由於Blob可能輝reshape。函數
二、主要函數spa
template <typename Dtype> class Blob { public: Blob() : data_(), diff_(), count_(0), capacity_(0) {} /// @brief Deprecated; use <code>Blob(const vector<int>& shape)</code>. explicit Blob(const int num, const int channels, const int height, const int width); explicit Blob(const vector<int>& shape); /// @brief Deprecated; use <code>Reshape(const vector<int>& shape)</code>. void Reshape(const int num, const int channels, const int height, const int width);
其中Blob做爲一個最基礎的類,其中構造函數開闢一個內存空間來存儲數據,reshape函數在Layer中的reshape或者forward操做中來adjust dimension。同時在改變Blob大小時,內存將會被從新分配若是內存大小不夠了,而且額外的內存將不會被釋放。對input的blob進行reshape,若是立馬調用 Net::Backward 是會出錯的,由於reshape以後,要麼Net::forward
或者Net::Reshape
就會被調用來將新的input shape 傳播到高層。指針
Blob類裏面有重載不少個count()
函數,主要仍是爲了統計Blob的容量(volume),或者是某一片(slice),從某個axis到具體某個axis的shape乘積。code
inline int count(int start_axis, int end_axis)
而且Blob的Index是能夠從負座標開始讀的,這一點跟Python好像blog
inline int CanonicalAxisIndex(int axis_index)
對於Blob中的4個基本變量num
,channel
,height
,width
能夠直接經過:內存
shape(0),shape(1),shape(2),shape(3
來訪問。ci
計算offset:get
inline int offset(const int n, const int c = 0, const int h = 0, const int w = 0) inline int offset(const vector<int>& indices)
offset計算的方式也支持兩種方式,一種直接指定n,c,h,w或者放到一個vector中進行計算,誤差是根據對應的n,c,h,w,返回的offset是((n * channels() + c) * height() + h) * width() + w
從一個blob中copy數據 ,經過開關控制是否copy_diff,若是是False則copy data。reshape控制是否須要reshape。好咱們接着往下看
inline Dtype data_at(const int n, const int c, const int h, const int w) inline Dtype diff_at(const int n, const int c, const int h, const int w) inline Dtype data_at(const vector<int>& index) inline Dtype diff_at(const vector<int>& index) inline const shared_ptr<SyncedMemory>& data() inline const shared_ptr<SyncedMemory>& diff()
這一部分函數主要經過給定的位置訪問數據,根據位置計算與數據起始的誤差offset,在經過cpu_data*指針得到地址。下面幾個函數都是得到
const Dtype* cpu_data() const; void set_cpu_data(Dtype* data); const int* gpu_shape() const; const Dtype* gpu_data() const; const Dtype* cpu_diff() const; const Dtype* gpu_diff() const; Dtype* mutable_cpu_data(); Dtype* mutable_gpu_data(); Dtype* mutable_cpu_diff(); Dtype* mutable_gpu_diff();
能夠看到這裏有data和diff兩類數據,而這個diff就是咱們所熟知的誤差,前者主要存儲前向傳遞的數據,然後者存儲的是反向傳播中的梯度
void Update();
看到update裏面面調用了
caffe_axpy<float>(const int N, const float alpha, const float* X,float* Y) { cblas_saxpy(N, alpha, X, 1, Y, 1); }
這個函數在caffe的util下面的match-functions.cpp裏面,主要是負責了線性代數庫的調用,實現的功能是
也就是blob裏面的data部分減去diff部分
void FromProto(const BlobProto& proto, bool reshape = true); void ToProto(BlobProto* proto, bool write_diff = false) const;
這兩個函數主要是將數據序列化,存儲到BlobProto,這裏說到Proto是谷歌的一個數據序列化的存儲格式,能夠實現語言、平臺無關、可擴展的序列化結構數據格式。
Dtype asum_data() const;//計算data的L1範數 Dtype asum_diff() const;//計算diff的L1範數 Dtype sumsq_data() const;//計算data的L2範數 Dtype sumsq_diff() const;//計算diff的L2範數 void scale_data(Dtype scale_factor);//將data部分乘以一個因子 void scale_diff(Dtype scale_factor);//將diff部分乘一個因子
這幾個函數是一些零散的功能,一看就懂。