Caffe源码阅读笔记(1):Blob
2016-11-15 16:38
453 查看
blob是caffe基础的数据结构,是用来保存学习到的参数以及网络传输过程中产生数据的类,数据的交换和存储都依赖于blob。
blob具有CPU和GPU之间同步的能力,它是4维的数组(Num, Channels, Height, Width)。
设Blob数据维度为 number N x channel K x height H x width W,Blob是row-major保存的,因此在(n, k, h, w)位置的值物理位置为((n * K + k) * H + h) * W + w,其中Number/N是batch size。
行主序和列主序 Row Major and Column Major
向量写为[1x3]矩阵形式:V=|xyz| , 被称为行主序(Row Major)。
向量写为[3x1]矩阵形式:V=∣∣∣∣xyz∣∣∣∣ , 被称为列主序(Column Major)。
先来看看头文件
Caffe类中成员变量名都带有后缀“_”,这样就容易区分临时变量和类成员变量。
[参考]:
caffe官方文档
《二十一天实战caffe》
Caffe的三级结构(Blobs,Layers,Nets)
caffe 中 BLOB的实现
blob具有CPU和GPU之间同步的能力,它是4维的数组(Num, Channels, Height, Width)。
设Blob数据维度为 number N x channel K x height H x width W,Blob是row-major保存的,因此在(n, k, h, w)位置的值物理位置为((n * K + k) * H + h) * W + w,其中Number/N是batch size。
行主序和列主序 Row Major and Column Major
向量写为[1x3]矩阵形式:V=|xyz| , 被称为行主序(Row Major)。
向量写为[3x1]矩阵形式:V=∣∣∣∣xyz∣∣∣∣ , 被称为列主序(Column Major)。
先来看看头文件
caffe/include/caffe/blob.hpp
Caffe类中成员变量名都带有后缀“_”,这样就容易区分临时变量和类成员变量。
#ifndef CAFFE_BLOB_HPP_ #define CAFFE_BLOB_HPP_ #include <algorithm> #include <string> #include <vector> #include "caffe/common.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/syncedmem.hpp" const int kMaxBlobAxes = 32; namespace caffe { /** * @brief A wrapper around SyncedMemory holders serving as the basic * computational unit through which Layer%s, Net%s, and Solver%s * interact. * 封装了SyncedMemory类,作为基本的计算单元使用于Layer,Net,Solver等 * TODO(dox): more thorough description. */ template <typename Dtype> class Blob { public: //构造函数 Blob() : data_(), diff_(), count_(0), capacity_(0) {} /// @brief Deprecated; use <code>Blob(const vector<int>& shape)</code>. //显式构造函数 explicit Blob(const int num, const int channels, const int height, const int width); explicit Blob(const vector<int>& shape); /// @brief Deprecated; use <code>Reshape(const vector<int>& shape)</code>. void Reshape(const int num, const int channels, const int height, const int width); /** * @brief Change the dimensions of the blob, allocating new memory if * necessary. * 改变blob当前的尺寸,必要时从新分配内存 * This function can be called both to create an initial allocation * of memory, and to adjust the dimensions of a top blob during Layer::Reshape * or Layer::Forward. When changing the size of blob, memory will only be * reallocated if sufficient memory does not already exist, and excess memory * will never be freed. * * Note that reshaping an input blob and immediately calling Net::Backward is * an error; either Net::Forward or Net::Reshape need to be called to * propagate the new input shape to higher layers. */ void Reshape(const vector<int>& shape); void Reshape(const BlobShape& shape); void ReshapeLike(const Blob& other); //得到Blob形状字符串用于打印log inline string shape_string() const { ostringstream stream; for (int i = 0; i < shape_.size(); ++i) { stream << shape_[i] << " "; } stream << "(" << count_ << ")"; return stream.str(); } //返回Blob形状 inline const vector<int>& shape() const { return shape_; } /** * @brief Returns the dimension of the index-th axis (or the negative index-th * axis from the end, if index is negative). * * @param index the axis index, which may be negative as it will be * "canonicalized" using CanonicalAxisIndex. * Dies on out of range index. */ //返回第index维度的尺寸 inline int shape(int index) const { return shape_[CanonicalAxisIndex(index)]; } //返回维度的数目 inline int num_axes() const { return shape_.size(); } //返回Blob中元素的总数 inline int count() const { return count_; } /** * @brief Compute the volume of a slice; i.e., the product of dimensions * among a range of axes. * * @param start_axis The first axis to include in the slice. * * @param end_axis The first axis to exclude from the slice. */ //返回从start_axis到end_axis的元素总数 inline int count(int start_axis, int end_axis) const { CHECK_LE(start_axis, end_axis); CHECK_GE(start_axis, 0); CHECK_GE(end_axis, 0); CHECK_LE(start_axis, num_axes()); CHECK_LE(end_axis, num_axes()); int count = 1; for (int i = start_axis; i < end_axis; ++i) { count *= shape(i); } return count; } /** * @brief Compute the volume of a slice spanning from a particular first * axis to the final axis. * * @param start_axis The first axis to include in the slice. */ //返回从start_axis开始的元素总数 inline int count(int start_axis) const { return count(start_axis, num_axes()); } /** * @brief Returns the 'canonical' version of a (usually) user-specified axis, * allowing for negative indexing (e.g., -1 for the last axis). * * @param axis_index the axis index. * If 0 <= index < num_axes(), return index. * If -num_axes <= index <= -1, return (num_axes() - (-index)), * e.g., the last axis index (num_axes() - 1) if index == -1, * the second to last if index == -2, etc. * Dies on out of range index. */ //转换坐标轴索引,将[-N,N]转换为[0,N),负索引表示从后往前访问,-1表示最后一个元素,-2表示第N-2个元素,以此类推 inline int CanonicalAxisIndex(int axis_index) const { CHECK_GE(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()) << "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; } //获取某一维的尺寸,Blob是一个4维数组,维度从低到高分别为:num,channels,height,weight /// @brief Deprecated legacy shape accessor num: use shape(0) instead. inline int num() const { return LegacyShape(0); } /// @brief Deprecated legacy shape accessor channels: use shape(1) instead. inline int channels() const { return LegacyShape(1); } /// @brief Deprecated legacy shape accessor height: use shape(2) instead. inline int height() const { return LegacyShape(2); } /// @brief Deprecated legacy shape accessor width: use shape(3) instead. 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()) { // Axis is out of range, but still in [0, 3] (or [-4, -1] for reverse // indexing) -- this special case simulates the one-padding used to fill // extraneous axes of legacy blobs. return 1; } return shape(index); } //计算偏移量 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; } /** * @brief Copy from a source Blob. * * @param source the Blob to copy from * @param copy_diff if false, copy the data; if true, copy the diff * @param reshape if false, require this Blob to be pre-shaped to the shape * of other (and die otherwise); if true, Reshape this Blob to other's * shape if necessary */ //拷贝Blob void CopyFrom(const Blob<Dtype>& source, bool copy_diff = false, bool reshape = false); //存取器(getter/setter) 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_; } const Dtype* cpu_data() const; void set_cpu_data(Dtype* data); const int* gpu_shape() 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(); void Update(); //反序列化,从BlobProto中恢复一个Blob对象 void FromProto(const BlobProto& proto, bool reshape = true); //序列化函数,将内存中Blob对象保存到BlobProto中 void ToProto(BlobProto* proto, bool write_diff = false) const; /// @brief Compute the sum of absolute values (L1 norm) of the data. //计算data的L1范数 Dtype asum_data() const; /// @brief Compute the sum of absolute values (L1 norm) of the diff. //计算diff的L1范数 Dtype asum_diff() const; /// @brief Compute the sum of squares (L2 norm squared) of the data. //计算data的L2范数 Dtype sumsq_data() const; /// @brief Compute the sum of squares (L2 norm squared) of the diff. //计算diff的L2范数 Dtype sumsq_diff() const; /// @brief Scale the blob data by a constant factor. //data乘以一个标量 void scale_data(Dtype scale_factor); /// @brief Scale the blob diff by a constant factor. //diff乘以一个标量 void scale_diff(Dtype scale_factor); /** * @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. */ //共享另一个Blob的data 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. */ //共享另一个Blob的diff void ShareDiff(const Blob& other); bool ShapeEquals(const BlobProto& other); protected: shared_ptr<SyncedMemory> data_; //存放指向data的指针 shared_ptr<SyncedMemory> diff_; //存放指向diff的指针 shared_ptr<SyncedMemory> shape_data_; vector<int> shape_; //形状信息 int count_; //存放有效元素数目信息 int capacity_; //存放Blob容器的容量信息 DISABLE_COPY_AND_ASSIGN(Blob); //禁用拷贝构造函数,赋值运算符重载 }; // class Blob } // namespace caffe #endif // CAFFE_BLOB_HPP_
[参考]:
caffe官方文档
《二十一天实战caffe》
Caffe的三级结构(Blobs,Layers,Nets)
caffe 中 BLOB的实现
相关文章推荐
- Caffe 源码阅读笔记 [DB] 存储Caffe数据的LevelDB类
- caffe源码阅读之Blob
- Caffe 源码阅读笔记 [基本模块] Layer和LayerFactory
- NVcaffe源码阅读——Blob的重新构建
- caffe源码阅读3-blob.cpp
- caffe 源码阅读笔记(0):基本概述
- Caffe 源码阅读1-blob的实现细节
- Caffe 源码阅读笔记 [数据读入和处理] DataReader和DataTransformer
- Caffe 源码阅读笔记 [基本模块] Caffe.cpp
- caffe源码阅读笔记(1):路线图
- 基于mfc的pc客户端源码阅读笔记
- FastDFS源码阅读笔记(二)
- Boa 源码阅读笔记
- winvnc源码阅读笔记(三)---------vncClient::SendUpdate线程
- 非典型2D游戏引擎 Orx 源码阅读笔记(3) 内存管理
- apache1.3.39源码alloc.c阅读笔记
- 非典型2D游戏引擎 Orx 源码阅读笔记(6) C语言实现的面向对象
- 非典型2D游戏引擎 Orx 源码阅读笔记(5) core部分(config,event)
- apache1.3.39源码alloc.c阅读笔记
- SDL源码阅读笔记(2) video dirver的初始化及选择