天天看點

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

繼續閱讀