blob.hpp & blob.cpp
- 定义全局变量
1
const int kMaxBlobAxes = 32;
就是说caffe最多支持32维,一般四维(num, channel, width, height)
- 定义 Blob 类
- 其中private数据
- shared_ptr
类型的 data_、diff_、shape_data_ - vector
shape_ - int count_, capacity_;
- shared_ptr
- 一个blob的要素,数据、梯度、数据shape(因为是c++,需要寻址);count_为各维度乘积,即所需要的空间;capacity_为当前分配的空间,如果count_超过capacity_,需要重新分配资源。
- DISABLE_COPY_AND_ASSIGN(Blob); 禁止拷贝构造和赋值构造Blob,有可能很大,用指针传递。
- Blob构造函数两种形式,一种4维(num, channel, width, height)(Deprecated), 一种一个vector作为shape
- 其中private数据
- Blob成员函数
- 多个重载Reshape(构造函数会调用Reshape)。Reshape作用是根据输入shape改变当前这个blob对象的维度(只是改变shape_里面的值,没有动data_),然后如果有必要(count_>capacity_)重新分配空间(若已有空间大于所需空间,永远不会释放)。Reshape可以用于初始化分配空间,也可以用于Layer::Reshape或者Layer::Forward需要改变blob维度的时候。其中最终实现的用的是这个版本的重载
1
void Blob<Dtype>::Reshape(const vector<int>& shape)
- 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. 就是Reshape后,应该先forward或者网络整体reshape以下,才可以调backward。
- count()的多个重载,计算[start_axis, end_axis)对应维度的乘积
- offset根据给定的num, channel, width, height)计算偏移量,用于定位数据
- CopyFrom 即Copy from a source Blob. 从source拷贝到当前blob中(拷贝data或者diff)
- data() 返回data_(指针)
-
diff() 返回diff_(指针)
-
set_cpu_data,似乎是设定cpu数据的指针指向 HEAD_AT_CPU
- asum_data、asum_diff、sumsq_data、sumsq_diff、scale_data、scale_diff 均是调用cblas计算。MKL是intel针对其GPU优化的线性代数库,blas是另外一个线性代数库。
- ShareData 让data_指向SyncedMemory holding the data_ of Blob
- Update():更新Net中Blob的参数,由于是浮点型且用模板实现,故用 NOT_IMPLEMENTED 标志声明 int和unsigned int版本不定义。 也即实现的的是 y = y - gradien
- (TODO)enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };
- (TODO)BlobProto 类
- 多个重载Reshape(构造函数会调用Reshape)。Reshape作用是根据输入shape改变当前这个blob对象的维度(只是改变shape_里面的值,没有动data_),然后如果有必要(count_>capacity_)重新分配空间(若已有空间大于所需空间,永远不会释放)。Reshape可以用于初始化分配空间,也可以用于Layer::Reshape或者Layer::Forward需要改变blob维度的时候。其中最终实现的用的是这个版本的重载
- c++新知识
- 原则上应该在所有的构造函数前加explicit关键字,当你有心利用隐式转换的时候再去解除explicit,这样可以大大减少错误的发生。
- 关键字inline必须与函数定义放在一起才能使函数成为内联,仅仅将inline放在函数声明前面不起任何作用。建议把inline函数的定义放到头文件中。在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情。引入内联函数的目的是为了解决程序中函数调用的效率问题。
- vector.resize(): 更改这个vector容器的size,小于当前vector.size()直接截断,大于则用val填补
1 2
void resize (size_type n); void resize (size_type n, const value_type& val);
-
static_cast(TODO):简单的说就是转换数据类型。static_cast不仅可以用在指针和引用上,还可以用在基础数据和对象上;前面提到过reinterpret_cast可以用在”没有关系”的类型之间,而用static_cast来处理的转换就需要两者具有”一定的关系”了。
- #define INSTANTIATE_CLASS(classname);非常非常非常重要的宏,重要的事说三遍。由于Caffe采用分离式模板编程方法(据说也是Google倡导的),模板未类型实例化的定义空间和实例化的定义空间是不同的。实际上,编译器并不会理睬分离在cpp里的未实例化的定义代码,而是将它放置在一个虚拟的空间。一旦一段明确类型的代码,访问这段虚拟代码空间,就会被编译器拦截。如果你想要让模板的声明和定义分离编写,就需要在cpp定义文件里,将定义指定明确的类型,实例化。这个宏的作用正是如此。(Google编程习惯的宏吧)。