caffe源碼解析之blob.hpp或blob.cpp

作者:wjmishuai

出處:http://blog.csdn.net/wjmishuai/article/details/50961471

聲明:版權所有,轉載請註明出處

caffe可以分爲三層:Blob、Layer、Net
Blob是一個四維的數組,用於存儲數據,包括輸入數據、輸出數據、權值;
Layer層則是神經網絡中具體的各層結構,主要用於計算,在根據配置文件初始化網絡結構後,前向計算結果,反向更新參數,而它的輸入和輸出都是Blob數據;
Net的層就是多個Layer組合而成的有向無環圖結構,也就是具體的網絡了。
Layer和Net的代碼有待深入,尤其是Layer的代碼,caffe實現了差不多40種不同的Layer層,裏面有不同的激活函數,這個要好好研究下。

關於Blob就這麼多內容,畢竟就是一個統一的數據存取接口,學到了一些封裝的手法,可以看看CPU和GPU一些接口的封裝;另一方面是對於Protocol Buffer有了一些瞭解。


<span style="font-size:24px;">#ifndef CAFFE_BLOB_HPP_//防止頭文件重複引用  
#define CAFFE_BLOB_HPP_  
  
#include <algorithm>  
#include <string>  
#include <vector>  
  
/*common.hpp主要用來單例化Caffe類, 
*並封裝了boost和CUDA隨機數生成的函數, 
*提供了統一的接口 
*/  
#include "common.hpp"  
/*caffe.pb.h是google protocol buffer根據caffe.proto自動生成的。 
*使用protocol buffer有這些好處,一方面可以用文本文件定義結構化的數據類型, 
*另一方面可以生成查詢效率更高、佔空間更小的二進制文件 
*/  
#include "caffe.pb.h"  
//syncedmem主要用於分配內存和釋放內存  
#include "syncedmem.hpp"  
//math_functions裏面封裝了很多cblas矩陣運算  
#include "util/math_functions.hpp"  
  
const int kMaxBlobAxes = INT_MAX;  
  
namespace caffe {//命名空間爲caffe  
  
    /* 
    *主要數據有兩個data和diff,用num、channels、height和width 
    *這四個維度來確定數據的具體位置,做一些數據查詢和Blobreshape的操作 
    */  
    template <typename Dtype>  
    class Blob {  
    public:  
        Blob()//blob的構造函數  
            : data_(), diff_(), count_(0), capacity_(0) {}//data_(), diff_()是用於存放數據的指針,  
  
        /*num_, channel_, height_, width_主要用來做定位offset和reshape處理。 
        *對於輸入(n, c, h, w)位置的數據位置爲((n*channels_+c)*height_+h)*width_+w, 
        *可以依據位置取data_()或diff_()中的數據。 
        */  
        explicit Blob(const int num, const int channels, const int height,  
            const int width);  
        explicit Blob(const vector<int>& shape);  
  
        /*Reshape函數的作用是改變一個blob的大小 
        *1.讀入num_,channels_,height_,width_的大小  
        *2.計算count_:count_ = num_ * channels_ * height_ * width_;  
        *3.如果count_不爲0,則重新爲data_和diff_分配一塊空間  
        *如果count爲0,則都初始化爲NULL 
        */  
        void Reshape(const int num, const int channels, const int height,  
            const int width);  
        void Reshape(const vector<int>& shape);  
        void Reshape(const BlobShape& shape);  
        //ReshapeLike的作用是爲data_和diff_ 重新分配一塊空間,大小和另一個blob的一樣   
        void ReshapeLike(const Blob& other);  
  
        inline string shape_string() const {  
            ostringstream stream;  
            for (int i = 0; i < shape_.size(); ++i) {  
                stream << shape_[i] << " ";  
            }  
            stream << "(" << count_ << ")";  
            return stream.str();  
        }  
        inline const vector<int>& shape() const { return shape_; }//返回shape  
  
        //返回第i個索引的shape,index可以是負數,  
        inline int shape(int index) const {  
            return shape_[CanonicalAxisIndex(index)];  
        }  
        inline int num_axes() const { return shape_.size(); }//返回shape的大小  
        inline int count() const { return count_; }//返回參數count  
  
        //計算一個slice的體積  
        inline int count(int start_axis, int end_axis) const {  
  
            int count = 1;  
            for (int i = start_axis; i < end_axis; ++i) {  
                count *= shape(i);  
            }  
            return count;  
        }  
        //計算從從一個特定的axis到最後一個axis的slice的體積。  
        inline int count(int start_axis) const {  
            return count(start_axis, num_axes());  
        }  
  
        //對負數(index可能是負數)規範化的一個函數  
        inline int CanonicalAxisIndex(int axis_index) const {  
  
            if (axis_index < 0) {  
                return axis_index + num_axes();  
            }  
            return axis_index;  
        }  
  
        /// 功能是返回一些成員變量,比如,num,channels,height,width等  
        inline int num() const { return LegacyShape(0); }  
        inline int channels() const { return LegacyShape(1); }  
        inline int height() const { return LegacyShape(2); }  
        inline int width() const { return LegacyShape(3); }  
        inline int LegacyShape(int index) const {  
  
            if (index >= num_axes() || index < -num_axes()) {  
                /*如果index超出索引範圍,但是在範圍 [0, 3] 或[-4, -1]內, 
                *這種特殊的情況下,模擬一個填充值,用來填補axes 。 
                */  
                return 1;  
            }  
            return shape(index);  
        }  
        //計算偏移量,因爲數據在內存是以一維數組形式的,所以需要計算偏移量來訪問  
        inline int offset(const int n, const int c = 0, const int h = 0,  
            const int w = 0) const {  
  
            return ((n * channels() + c) * height() + h) * width() + w;  
        }  
  
        inline int offset(const vector<int>& indices) const {  
  
            int offset = 0;  
            for (int i = 0; i < num_axes(); ++i) {  
                offset *= shape(i);  
                if (indices.size() > i) {  
  
                    offset += indices[i];  
                }  
            }  
            return offset;  
        }  
        /** 
        *從source拷貝數據。copy_diff作爲標誌來區分是拷貝data還是拷貝diff 
        *1.如果是GPU: 如果是拷貝diff:調用cudaMemcpy函數將source的diff拷貝過來,否則拷貝data  
        *2.如果是CPU: 如果是拷貝diff:調用memcpy函數將source的diff拷貝過來 否則拷貝data 
        */  
        void CopyFrom(const Blob<Dtype>& source, bool copy_diff = false,  
            bool reshape = false);  
        //從cpu訪問數據data  
        inline Dtype data_at(const int n, const int c, const int h,  
            const int w) const {  
            return cpu_data()[offset(n, c, h, w)];  
        }  
        //從cpu訪問數據diff  
        inline Dtype diff_at(const int n, const int c, const int h,  
            const int w) const {  
            return cpu_diff()[offset(n, c, h, w)];  
        }  
        //從cpu訪問數據data  
        inline Dtype data_at(const vector<int>& index) const {  
            return cpu_data()[offset(index)];  
        }  
        //從cpu訪問數據diff  
        inline Dtype diff_at(const vector<int>& index) const {  
            return cpu_diff()[offset(index)];  
        }  
        //從cpu訪問數據data  
        inline const shared_ptr<SyncedMemory>& data() const {  
            return data_;  
        }  
        //從cpu訪問數據diff  
        inline const shared_ptr<SyncedMemory>& diff() const {  
            return diff_;  
        }  
        /**調用SyncedMemory的函數,來返回數據的指針;前兩個調用to_cpu(),返回cpu_ptr; 
        *第一個對於data對象,第二個對於diff對象 
        *後兩個調用to_gpu(),返回gpu_ptr;第一個對於data對象,第二個對於diff對象 
        */  
        void set_cpu_data(Dtype* data);  
        const Dtype* cpu_data() 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_的數據。  
        *1.判斷blob的位置 
        *2.調用caffe_axpy:在math_functions.cpp可以找到該函數的實現,其實這函數也是封裝了mkl的函數。這裏調用是爲了實現了兩個向量的減法。  
        *3.調用caffe_gpu_axpy:在math_functions.cpp可以找到該函數的實現,其實這函數也是封裝了cublas的函數。這裏調用是爲了實現了兩個向量的減法。 
        */  
        void Update();  
        /**功能:從proto讀數據進來,其實就是反序列化  
        *1.先把blob的大小改變一下  
        *2.得到cpu中數據的地址  
        *3.用proto中的data覆蓋blob中的data  
        *4.用proto中的diff覆蓋blob中的diff 
        */  
        void FromProto(const BlobProto& proto, bool reshape = true);  
        //把blob數據保存到proto中  
        void ToProto(BlobProto* proto, bool write_diff = false) const;  
  
        //計算絕對值的data總和(L1範數)。  
        Dtype asum_data() const;  
        //計算絕對值的diff總和(L1範數)。  
        Dtype asum_diff() const;  
        //計算絕對值的data總和(L2範數)。  
        Dtype sumsq_data() const;  
        //計算絕對值的diff總和(L2範數)。  
        Dtype sumsq_diff() const;  
        //通過常量因子測量blob data  
        void scale_data(Dtype scale_factor);  
        ////通過常量因子測量blob diff  
        void scale_diff(Dtype scale_factor);  
  
        //從other的blob複製data和diff的值  
        void ShareData(const Blob& other);  
        void ShareDiff(const Blob& other);  
        bool ShapeEquals(const BlobProto& other);  
  
    protected:  
        shared_ptr<SyncedMemory> data_;// 存放數據  
        shared_ptr<SyncedMemory> diff_;//存放梯度  
        vector<int> shape_;//存放形狀  
        int count_;//數據個數  
        int capacity_;//數據容量  
  
        DISABLE_COPY_AND_ASSIGN(Blob);  
    };  // class Blob  
  
}  // namespace caffe  
  
#endif  // CAFFE_BLOB_HPP_</span>


發佈了61 篇原創文章 · 獲贊 138 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章