天天看点

caffe源码阅读1-blob.hpp

A wrapper around SyncedMemory holders serving as the basic computational unit through which Layer's, Net's, and Solver's interact.

其实网上已经有很多源码解读了,但我还是想自己看一遍。

呃,不得不承认,我连C语言的代码都写得不好,C++也从来没有怎么学过。

所以可能我看的方式和大家不太一样,当作自己的学习记录吧。

水平有限,如果您看到了有说得不对的地方,请大方的指出来,相互交流学习,:)。

应该基本可以公认的一点:基本每个类里面所有方法都是对自己的数据进行操作,而自己的数据通常也是私有类型的。

鉴于以上这一点,所以我先直接把代码拉到最后,看blob的数据有哪些:

protected:
  shared_ptr<SyncedMemory> data_;
  shared_ptr<SyncedMemory> diff_;
  int num_;
  int channels_;
  int height_;
  int width_;
  int count_;
  int capacity_;
           

看起来Blob最重要的工作也就在于data, diff的操作了。

猜也能够猜到,data应该是前馈时候的数据,diff是反馈时候的数据。channels_, height_, width_这三个数据,如果理解成图像的3个通道应该也是可以的。不过由于在整过网络的传递过程中,可能最开始的1个图片到了例如conv5已经变成了几百个小图片,但是存储的时候应该是全部放在一起的,也就是全部都放在一个Blob里面,为了区分到底这个Blob有多少个图片(或者说成feature_map)也就定义了num_吧。但我们通常做模型训练的时候,都是好多个图片做批量处理的,所以这里又多了变量count_估计也就是在于这个目的吧。最后的capacity_是做什么的呢?这个还真猜不出来(可能是在进行批量处理的过程中检测是否这一批处理完没有,瞎说的哈)。

另外,其实我们可以把一个Blob理解成高维数组,不要局限于图像,那么还可以将这里的Blob用在别的地方吧。

再来看看Blob里面提供了哪些方法呢?既然操作数据的重点是data, diff,那么先来看看与这两个数据直接相关的函数:

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));
  }

  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));
  }

  inline const shared_ptr<SyncedMemory>& data() const {
    CHECK(data_);
    return data_;
  }

  inline const shared_ptr<SyncedMemory>& diff() const {
    CHECK(diff_);
    return diff_;
  }

  const Dtype* cpu_data() const;
  void set_cpu_data(Dtype* data);
  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();
           

因为其中涉及到offset()函数,它也定义在Blob中的:

inline int offset(const int n, const int c = 0, const int h = 0,
      const int w = 0) const {
    CHECK_GE(n, 0);
    CHECK_LE(n, num_);
    CHECK_GE(channels_, 0);
    CHECK_LE(c, channels_);
    CHECK_GE(height_, 0);
    CHECK_LE(h, height_);
    CHECK_GE(width_, 0);
    CHECK_LE(w, width_);
    return ((n * channels_ + c) * height_ + h) * width_ + w;
  }
           

offset()也就相当于是计算一个偏置(我这里说的偏置与神经网络里面的权重, 偏置不一个概念哈,你懂的)。

有了offset,前面的函数理解起来就轻松多了,data_at(n, c, h, w)也就是访问在cpu_data的第offset(n, c, h, w)的数据,diff_at类似。

很奇怪,为什么访问的是cpu_data? 不是gpu_data,也不是data!暂时我也不理解。

接着的两个函数shared_ptr开头的,大概也就是分享data和diff数据吧。注意,这里是直接返回data和diff数据的,没有cpu, gpu之分。

再接下来的几个函数,得去看看Blob.cpp了。

关于Blob里面其它的函数,感觉对后面的阅读没有太大用的样子,例如:

Blob()
       : data_(), diff_(), num_(0), channels_(0), height_(0), width_(0),
       count_(0), capacity_(0) {}
  explicit Blob(const int num, const int channels, const int height,
    const int width);

  void Reshape(const int num, const int channels, const int height,
    const int width);
  void ReshapeLike(const Blob& other);
  inline int num() const { return num_; }
  inline int channels() const { return channels_; }
  inline int height() const { return height_; }
  inline int width() const { return width_; }
  inline int count() const { return count_; }
           

构造函数,改变尺寸的函数,返回通道数,高宽等等。

void CopyFrom(const Blob<Dtype>& source, bool copy_diff = false,
      bool reshape = false);
  void Update();
  void FromProto(const BlobProto& proto);
  void ToProto(BlobProto* proto, bool write_diff = false) const;

  /// @brief Compute the sum of absolute values (L1 norm) of the data.
  Dtype asum_data() const;
  /// @brief Compute the sum of absolute values (L1 norm) of the diff.
  Dtype asum_diff() const;

  /**
   * @brief Set the data_ shared_ptr to point to the SyncedMemory holding the
   *        data_ of Blob other -- useful in Layer&s which simply perform a copy
   *        in their Forward pass.
   *
   * This deallocates the SyncedMemory holding this Blob's data_, as
   * shared_ptr calls its destructor when reset with the "=" operator.
   */
  void ShareData(const Blob& other);
  /**
   * @brief Set the diff_ shared_ptr to point to the SyncedMemory holding the
   *        diff_ of Blob other -- useful in Layer&s which simply perform a copy
   *        in their Forward pass.
   *
   * This deallocates the SyncedMemory holding this Blob's diff_, as
   * shared_ptr calls its destructor when reset with the "=" operator.
   */
  void ShareDiff(const Blob& other);
           

这几个函数,Copy的好理解,Update()?得看看Blob.cpp,FromProto,ToProto可以不用太关心,与google的protobuffer有关系,对阅读整个caffe应该不会有什么影响吧,就理解成一个拿数据出来,一个将数据放进去。

再后面的4个函数,注释得很详细。

asum_data()计算数据的一介范数,asum_diff()计算误差的一介范数。

Share_Data()的实现也只是简单的将参数中的数据指针赋值给自己而已,Share_Diff()一样。

template <typename Dtype>
void Blob<Dtype>::ShareData(const Blob& other) {
  CHECK_EQ(count_, other.count());
  data_ = other.data();
}

template <typename Dtype>
void Blob<Dtype>::ShareDiff(const Blob& other) {
  CHECK_EQ(count_, other.count());
  diff_ = other.diff();
}
           

继续阅读