您的位置:首页 > Web前端

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

2016-09-21 15:12 483 查看
作者: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有了一些了解。

[cpp] view
plain copy

 





#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_  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: