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有了一些了解。


[cpp]  view plain  copy
  1. #ifndef CAFFE_BLOB_HPP_//防止头文件重复引用  
  2. #define CAFFE_BLOB_HPP_  
  3.   
  4. #include <algorithm>  
  5. #include <string>  
  6. #include <vector>  
  7.   
  8. /*common.hpp主要用来单例化Caffe类, 
  9. *并封装了boost和CUDA随机数生成的函数, 
  10. *提供了统一的接口 
  11. */  
  12. #include "common.hpp"  
  13. /*caffe.pb.h是google protocol buffer根据caffe.proto自动生成的。 
  14. *使用protocol buffer有这些好处,一方面可以用文本文件定义结构化的数据类型, 
  15. *另一方面可以生成查询效率更高、占空间更小的二进制文件 
  16. */  
  17. #include "caffe.pb.h"  
  18. //syncedmem主要用于分配内存和释放内存  
  19. #include "syncedmem.hpp"  
  20. //math_functions里面封装了很多cblas矩阵运算  
  21. #include "util/math_functions.hpp"  
  22.   
  23. const int kMaxBlobAxes = INT_MAX;  
  24.   
  25. namespace caffe {//命名空间为caffe  
  26.   
  27.     /* 
  28.     *主要数据有两个data和diff,用num、channels、height和width 
  29.     *这四个维度来确定数据的具体位置,做一些数据查询和Blobreshape的操作 
  30.     */  
  31.     template <typename Dtype>  
  32.     class Blob {  
  33.     public:  
  34.         Blob()//blob的构造函数  
  35.             : data_(), diff_(), count_(0), capacity_(0) {}//data_(), diff_()是用于存放数据的指针,  
  36.   
  37.         /*num_, channel_, height_, width_主要用来做定位offset和reshape处理。 
  38.         *对于输入(n, c, h, w)位置的数据位置为((n*channels_+c)*height_+h)*width_+w, 
  39.         *可以依据位置取data_()或diff_()中的数据。 
  40.         */  
  41.         explicit Blob(const int num, const int channels, const int height,  
  42.             const int width);  
  43.         explicit Blob(const vector<int>& shape);  
  44.   
  45.         /*Reshape函数的作用是改变一个blob的大小 
  46.         *1.读入num_,channels_,height_,width_的大小  
  47.         *2.计算count_:count_ = num_ * channels_ * height_ * width_;  
  48.         *3.如果count_不为0,则重新为data_和diff_分配一块空间  
  49.         *如果count为0,则都初始化为NULL 
  50.         */  
  51.         void Reshape(const int num, const int channels, const int height,  
  52.             const int width);  
  53.         void Reshape(const vector<int>& shape);  
  54.         void Reshape(const BlobShape& shape);  
  55.         //ReshapeLike的作用是为data_和diff_ 重新分配一块空间,大小和另一个blob的一样   
  56.         void ReshapeLike(const Blob& other);  
  57.   
  58.         inline string shape_string() const {  
  59.             ostringstream stream;  
  60.             for (int i = 0; i < shape_.size(); ++i) {  
  61.                 stream << shape_[i] << " ";  
  62.             }  
  63.             stream << "(" << count_ << ")";  
  64.             return stream.str();  
  65.         }  
  66.         inline const vector<int>& shape() const { return shape_; }//返回shape  
  67.   
  68.         //返回第i个索引的shape,index可以是负数,  
  69.         inline int shape(int index) const {  
  70.             return shape_[CanonicalAxisIndex(index)];  
  71.         }  
  72.         inline int num_axes() const { return shape_.size(); }//返回shape的大小  
  73.         inline int count() const { return count_; }//返回参数count  
  74.   
  75.         //计算一个slice的体积  
  76.         inline int count(int start_axis, int end_axis) const {  
  77.   
  78.             int count = 1;  
  79.             for (int i = start_axis; i < end_axis; ++i) {  
  80.                 count *= shape(i);  
  81.             }  
  82.             return count;  
  83.         }  
  84.         //计算从从一个特定的axis到最后一个axis的slice的体积。  
  85.         inline int count(int start_axis) const {  
  86.             return count(start_axis, num_axes());  
  87.         }  
  88.   
  89.         //对负数(index可能是负数)规范化的一个函数  
  90.         inline int CanonicalAxisIndex(int axis_index) const {  
  91.   
  92.             if (axis_index < 0) {  
  93.                 return axis_index + num_axes();  
  94.             }  
  95.             return axis_index;  
  96.         }  
  97.   
  98.         /// 功能是返回一些成员变量,比如,num,channels,height,width等  
  99.         inline int num() const { return LegacyShape(0); }  
  100.         inline int channels() const { return LegacyShape(1); }  
  101.         inline int height() const { return LegacyShape(2); }  
  102.         inline int width() const { return LegacyShape(3); }  
  103.         inline int LegacyShape(int index) const {  
  104.   
  105.             if (index >= num_axes() || index < -num_axes()) {  
  106.                 /*如果index超出索引范围,但是在范围 [0, 3] 或[-4, -1]内, 
  107.                 *这种特殊的情况下,模拟一个填充值,用来填补axes 。 
  108.                 */  
  109.                 return 1;  
  110.             }  
  111.             return shape(index);  
  112.         }  
  113.         //计算偏移量,因为数据在内存是以一维数组形式的,所以需要计算偏移量来访问  
  114.         inline int offset(const int n, const int c = 0, const int h = 0,  
  115.             const int w = 0) const {  
  116.   
  117.             return ((n * channels() + c) * height() + h) * width() + w;  
  118.         }  
  119.   
  120.         inline int offset(const vector<int>& indices) const {  
  121.   
  122.             int offset = 0;  
  123.             for (int i = 0; i < num_axes(); ++i) {  
  124.                 offset *= shape(i);  
  125.                 if (indices.size() > i) {  
  126.   
  127.                     offset += indices[i];  
  128.                 }  
  129.             }  
  130.             return offset;  
  131.         }  
  132.         /** 
  133.         *从source拷贝数据。copy_diff作为标志来区分是拷贝data还是拷贝diff 
  134.         *1.如果是GPU: 如果是拷贝diff:调用cudaMemcpy函数将source的diff拷贝过来,否则拷贝data  
  135.         *2.如果是CPU: 如果是拷贝diff:调用memcpy函数将source的diff拷贝过来 否则拷贝data 
  136.         */  
  137.         void CopyFrom(const Blob<Dtype>& source, bool copy_diff = false,  
  138.             bool reshape = false);  
  139.         //从cpu访问数据data  
  140.         inline Dtype data_at(const int n, const int c, const int h,  
  141.             const int w) const {  
  142.             return cpu_data()[offset(n, c, h, w)];  
  143.         }  
  144.         //从cpu访问数据diff  
  145.         inline Dtype diff_at(const int n, const int c, const int h,  
  146.             const int w) const {  
  147.             return cpu_diff()[offset(n, c, h, w)];  
  148.         }  
  149.         //从cpu访问数据data  
  150.         inline Dtype data_at(const vector<int>& index) const {  
  151.             return cpu_data()[offset(index)];  
  152.         }  
  153.         //从cpu访问数据diff  
  154.         inline Dtype diff_at(const vector<int>& index) const {  
  155.             return cpu_diff()[offset(index)];  
  156.         }  
  157.         //从cpu访问数据data  
  158.         inline const shared_ptr<SyncedMemory>& data() const {  
  159.             return data_;  
  160.         }  
  161.         //从cpu访问数据diff  
  162.         inline const shared_ptr<SyncedMemory>& diff() const {  
  163.             return diff_;  
  164.         }  
  165.         /**调用SyncedMemory的函数,来返回数据的指针;前两个调用to_cpu(),返回cpu_ptr; 
  166.         *第一个对于data对象,第二个对于diff对象 
  167.         *后两个调用to_gpu(),返回gpu_ptr;第一个对于data对象,第二个对于diff对象 
  168.         */  
  169.         void set_cpu_data(Dtype* data);  
  170.         const Dtype* cpu_data() const;  
  171.         const Dtype* gpu_data() const;  
  172.         const Dtype* cpu_diff() const;  
  173.         const Dtype* gpu_diff() const;  
  174.   
  175.         Dtype* mutable_cpu_data();  
  176.         Dtype* mutable_gpu_data();  
  177.         Dtype* mutable_cpu_diff();  
  178.         Dtype* mutable_gpu_diff();  
  179.         /**更新data_的数据,就是减去diff_的数据。  
  180.         *1.判断blob的位置 
  181.         *2.调用caffe_axpy:在math_functions.cpp可以找到该函数的实现,其实这函数也是封装了mkl的函数。这里调用是为了实现了两个向量的减法。  
  182.         *3.调用caffe_gpu_axpy:在math_functions.cpp可以找到该函数的实现,其实这函数也是封装了cublas的函数。这里调用是为了实现了两个向量的减法。 
  183.         */  
  184.         void Update();  
  185.         /**功能:从proto读数据进来,其实就是反序列化  
  186.         *1.先把blob的大小改变一下  
  187.         *2.得到cpu中数据的地址  
  188.         *3.用proto中的data覆盖blob中的data  
  189.         *4.用proto中的diff覆盖blob中的diff 
  190.         */  
  191.         void FromProto(const BlobProto& proto, bool reshape = true);  
  192.         //把blob数据保存到proto中  
  193.         void ToProto(BlobProto* proto, bool write_diff = falseconst;  
  194.   
  195.         //计算绝对值的data总和(L1范数)。  
  196.         Dtype asum_data() const;  
  197.         //计算绝对值的diff总和(L1范数)。  
  198.         Dtype asum_diff() const;  
  199.         //计算绝对值的data总和(L2范数)。  
  200.         Dtype sumsq_data() const;  
  201.         //计算绝对值的diff总和(L2范数)。  
  202.         Dtype sumsq_diff() const;  
  203.         //通过常量因子测量blob data  
  204.         void scale_data(Dtype scale_factor);  
  205.         通过常量因子测量blob diff  
  206.         void scale_diff(Dtype scale_factor);  
  207.   
  208.         //从other的blob复制data和diff的值  
  209.         void ShareData(const Blob& other);  
  210.         void ShareDiff(const Blob& other);  
  211.         bool ShapeEquals(const BlobProto& other);  
  212.   
  213.     protected:  
  214.         shared_ptr<SyncedMemory> data_;// 存放数据  
  215.         shared_ptr<SyncedMemory> diff_;//存放梯度  
  216.         vector<int> shape_;//存放形状  
  217.         int count_;//数据个数  
  218.         int capacity_;//数据容量  
  219.   
  220.         DISABLE_COPY_AND_ASSIGN(Blob);  
  221.     };  // class Blob  
  222.   
  223. }  // namespace caffe  
  224.   
  225. #endif  // CAFFE_BLOB_HPP_  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值