caffe source interpretation (13)-blob.hpp

caffe uses a four-dimensional array called blobs to store and exchange data. Blob provides a unified memory interface, holding a batch of images or other data, weights, weight update values. Blob represents a four-dimensional array in memory. The dimensions from low to high are [width, height, channels, num]; where width and height represent the width and height of the image, channels represent the RGB color channel, num represents the frame number, which is used to store data or weight (data) and weight increment (diff). In network computing, the input and output of each layer need to be buffered by blob objects. Blob is the basic storage unit of caffe. Here is a brief introduction of blob, mainly referring to the detailed introduction of blob in Zhao Yongke's deep learning. 21 day practical caffe.
Data structure description
Open src/caffe/proto/caffe.proto, the first thing that comes into view is the description related to Blob. It can be seen that the importance of this data structure is the dependency of most other data structures.

//This structure describes the shape information of Blob
message BlobShape {
  repeated int64 dim = 1 [packed = true];
  //Only several int64 type values are included, representing the size of each dimension of Blob,
  //packed indicates that these values are closely arranged in memory without any holes
}
//This structure describes the status of Blob after serialization in disk
message BlobProto {
 //Optional, including a BlobShape object
  optional BlobShape shape = 7;
  //Include floating-point elements to store data or weights
  //The number of elements is determined by shape or (num,channel,height,width)
  //These elements are tightly arranged in memory
  repeated float data = 5 [packed = true];
  repeated float diff = 6 [packed = true];
  repeated double double_data = 8 [packed = true];//Side by side with data, but double
  repeated double double_diff = 9 [packed = true];//Side by side with diff, but double

  // 4D dimensions -- deprecated.  Use "shape" instead.
  //The following is optional dimension information. In the new version of caffe, shape is recommended instead of the following values
  optional int32 num = 1 [default = 0];
  optional int32 channels = 2 [default = 0];
  optional int32 height = 3 [default = 0];
  optional int32 width = 4 [default = 0];
}

How does Blob work
Blob is a template class, which is declared in include/caffe/blob.hpp and encapsulates SynceMemory.

#ifndef CAFFE_BLOB_HPP_
#define CAFFE_BLOB_HPP_
#include <algorithm>
#include <string>
#include <vector>
#include "caffe/common.hpp"
//Header file generated by protoc
#include "caffe/proto/caffe.pb.h"
//CPU/GPU shared memory class for data synchronization
#include "caffe/syncedmem.hpp"
//Blob maximum dimension order
const int kMaxBlobAxes = 32;
namespace caffe {
template <typename Dtype>
class Blob {//Class declaration
 public:
 //Default constructor 
  Blob()
       : data_(), diff_(), count_(0), capacity_(0) {}

  explicit Blob(const int num, const int channels, const int height,
  //Explicit constructor, avoid implicit data type conversion
      const int width);
  explicit Blob(const vector<int>& shape);

  void Reshape(const int num, const int channels, const int height,
      const int width);
  //Deform function, reset the current blob shape according to the input parameters, and reallocate the memory if necessary
  void Reshape(const vector<int>& shape);
  void Reshape(const BlobShape& shape);
  void ReshapeLike(const Blob& other);
  //Get Blob shape string, which is used to print log. See caffe running log,
  //Similar to Top shape: 100 1 28 28 (78400)
  inline string shape_string() const {
    ostringstream stream;
    for (int i = 0; i < shape_.size(); ++i) {
      stream << shape_[i] << " ";
    }
    stream << "(" << count_ << ")";
    return stream.str();
  }
  //Return to Blob shape
  inline const vector<int>& shape() const { return shape_; }
  //Returns the dimension of a dimension
  inline int shape(int index) const {
    return shape_[CanonicalAxisIndex(index)];
  }
  //Number of return dimensions
  inline int num_axes() const { return shape_.size(); }
  //Return the total number of elements in Blob
  inline int count() const { return count_; }
 //Returns the total number of elements in a certain dimension subset of Blob
  inline int count(int start_axis, int end_axis) const {
    CHECK_LE(start_axis, end_axis);//Make sure start axis < = end axis
    CHECK_GE(start_axis, 0);//Make sure start? Axis > = 0
    CHECK_GE(end_axis, 0);//Guarantee end? Axis > = 0
    CHECK_LE(start_axis, num_axes());//Ensure that start axis < = the total number of dimensions
    CHECK_LE(end_axis, num_axes());//Guarantee end ﹐ axis < = total number of dimensions
    int count = 1;
    for (int i = start_axis; i < end_axis; ++i) {
      count *= shape(i);
    }
    return count;
  }
  //Calculate the total number of elements starting from a dimension
  inline int count(int start_axis) const {
    return count(start_axis, num_axes());
  }
//Convert axis index [- N,N] to normal index [0,N]
  inline int CanonicalAxisIndex(int axis_index) const {
    CHECK_GE(axis_index, -num_axes())//Ensure axis? Index > = - num? Axes ()
        << "axis " << axis_index << " out of range for " << num_axes()
        << "-D Blob with shape " << shape_string();
    CHECK_LT(axis_index, num_axes())//Make sure axis? Index < num? Axes ()
        << "axis " << axis_index << " out of range for " << num_axes()
        << "-D Blob with shape " << shape_string();
    if (axis_index < 0) {
      return axis_index + num_axes();
    }
    return axis_index;
  }
  //Get a dimension of a shape
  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 {
    CHECK_LE(num_axes(), 4)
        << "Cannot use legacy accessors on Blobs with > 4 axes.";
    CHECK_LT(index, 4);
    CHECK_GE(index, -4);
    if (index >= num_axes() || index < -num_axes()) {
      return 1;
    }
    return shape(index);
  }
//The following functions calculate the offset
  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;
  }

  inline int offset(const vector<int>& indices) const {
    CHECK_LE(indices.size(), num_axes());
    int offset = 0;
    for (int i = 0; i < num_axes(); ++i) {
      offset *= shape(i);
      if (indices.size() > i) {
        CHECK_GE(indices[i], 0);
        CHECK_LT(indices[i], shape(i));
        offset += indices[i];
      }
    }
    return offset;
  }
  //Copy Blob by value to current Blob
  void CopyFrom(const Blob<Dtype>& source, bool copy_diff = false,
      bool reshape = false);

  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 Dtype data_at(const vector<int>& index) const {
    return cpu_data()[offset(index)];
  }

  inline Dtype diff_at(const vector<int>& index) const {
    return cpu_diff()[offset(index)];
  }

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

  inline const shared_ptr<SyncedMemory>& diff() const {
    CHECK(diff_);
    return diff_;
  }
  //Read only access to cpu data
  const Dtype* cpu_data() const;
  //Set cpu data
  void set_cpu_data(Dtype* data);
  //Read only access to gpu data
  const int* gpu_shape() const;
  const Dtype* gpu_data() const;
  //Set gpu data
  void set_gpu_data(Dtype* data);
  //Read only access to cpu diff
  const Dtype* cpu_diff() const;
  //Read only access gpu diff
  const Dtype* gpu_diff() const;
  //Read write access to cpu data, gpu data, cpu diff, gpu diff
  Dtype* mutable_cpu_data();
  Dtype* mutable_gpu_data();
  Dtype* mutable_cpu_diff();
  Dtype* mutable_gpu_diff();
  void Update();//Blob update operation, simply understood as the merge process of data and diff
  //Deserialization function, reply a Blob object from BlobProto
  void FromProto(const BlobProto& proto, bool reshape = true);
  //Serialize function to save Blob object in memory to BlobProto
  void ToProto(BlobProto* proto, bool write_diff = false) const;
 //Calculating L1 norm of data
  Dtype asum_data() const;
  //Calculate the L1 norm of diff
  Dtype asum_diff() const;
 //Calculating L2 norm of data
  Dtype sumsq_data() const;
 //Calculating L2 norm of diff
  Dtype sumsq_diff() const;

  void scale_data(Dtype scale_factor);
  void scale_diff(Dtype scale_factor);
  void ShareData(const Blob& other);
  void ShareDiff(const Blob& other);
  bool ShapeEquals(const BlobProto& other);

 protected:
  shared_ptr<SyncedMemory> data_;//Store pointer to data
  shared_ptr<SyncedMemory> diff_;//Store pointer to diff
  shared_ptr<SyncedMemory> shape_data_;
  vector<int> shape_;//Shape information
  int count_;//Store the number of valid elements
  int capacity_;//Capacity information of Blob container
  DISABLE_COPY_AND_ASSIGN(Blob);
};  // class Blob

}  // namespace caffe

#endif  // CAFFE_BLOB_HPP_

Tags: network

Posted on Wed, 01 Apr 2020 11:49:22 -0700 by fezzik