Blob数据结构
现有一段简单的代码(具体见《21天实战Caffe》)
#include <vector>
#include <iostream>
#include <caffe/blob.hpp>
using namespace caffe;
using namespace std;
int main(void)
{
Blob<float> a;
cout << "Size : " << a.shape_string() << endl;
a.Reshape(1, 2, 3, 4);
cout << "Size: " << a.shape_string() << endl;
cout << "I am jiangcheng" <<endl;
return 0;
}
在编译这段代码的时候,遇到了以下的问题, 具体解决方法如下
/home/laojiang/jiangcheng/caffe/anzhuangbao/caffe/include/caffe/util/device_alternate.hpp:34:23: fatal error: cublas_v2.h: 没有那个文件或目录
g++ Blob.cpp -I /home/laojiang/jiangcheng/caffe/anzhuangbao/caffe/include/ -I /home/laojiang/jiangcheng/caffe/anzhuangbao/caffe/.build_release/src/ -L /home/laojiang/jiangcheng/caffe/anzhuangbao/caffe/build/lib/ -lcaffe -I /usr/local/cuda-8.0/include/ -L /usr/local/cuda-8.0/lib64/
//home/laojiang/anaconda3/lib/libpng16.so.16:对‘inflateValidate@ZLIB_1.2.9’未定义的引用
首先到https://sourceforge.net/projects/libpng/?source=directory下载libpng-1.6.35.tar.xz
然后利用tar -xvf libpng-1.6.35.tar.xz来进行解压.
之后依次进行以下操作:
1. cd libpng-1.6.35
2. ./configure
3. make check
4. sudo make install
5. sudo ldconfig
至此, libpng16.so.16安装成功!
Blob数据结构
该数据结构的地址:
your_path/caffe/src/caffe/blob.cpp
template <typename Dtype>
void Blob<Dtype>::Reshape(const int num, const int channels, const int height,
const int width) {
vector<int> shape(4);
shape[0] = num;
shape[1] = channels;
shape[2] = height;
shape[3] = width;
Reshape(shape);
}
template <typename Dtype>
void Blob<Dtype>::Reshape(const vector<int>& shape) {
CHECK_LE(shape.size(), kMaxBlobAxes);
count_ = 1;
shape_.resize(shape.size());
if (!shape_data_ || shape_data_->size() < shape.size() * sizeof(int)) {
shape_data_.reset(new SyncedMemory(shape.size() * sizeof(int)));
}
int* shape_data = static_cast<int*>(shape_data_->mutable_cpu_data());
for (int i = 0; i < shape.size(); ++i) {
CHECK_GE(shape[i], 0);
if (count_ != 0) {
CHECK_LE(shape[i], INT_MAX / count_) << "blob size exceeds INT_MAX";
}
count_ *= shape[i];
shape_[i] = shape[i];
shape_data[i] = shape[i];
}
if (count_ > capacity_) {
capacity_ = count_;
data_.reset(new SyncedMemory(capacity_ * sizeof(Dtype)));
diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype)));
}
}
源码注释
1. Dtype* mutable\_cpu\_data();
由函数声明可以看出,mutable_cpu_data()函数返回的实际上是一个Dtype指针.
mutable_cpu_data函数定义如下:
template <typename Dtype>
Dtype* Blob<Dtype>::mutable_cpu_data() {
CHECK(data_);
return static_cast<Dtype*>(data_->mutable_cpu_data());
}
其核心代码如下
return static_cast<Dtype*>(data_->mutable_cpu_data());
shared_ptr<SyncedMemory> data_;
这说明data_是智能指针,指向SyncedMemory类型. 所以在SyncedMemory类中应当有成员函数mutable_cpu_data().
查阅caffe/include/caffe/syncedmem.hpp以及caffe/src/caffe/syncedmem.cpp,可发现该函数定义如下:
void* SyncedMemory::mutable_cpu_data() {
check_device();
to_cpu(); //首先同步一下cpu和gpu的数据
head_ = HEAD_AT_CPU; //将head_重置为HEAD_AT_CPU
return cpu_ptr_;
}
check_device()
函数的定义如下:
void SyncedMemory::check_device() {
#ifndef CPU_ONLY
#ifdef DEBUG
......
#endif
#endif
}
}
这说明check_device()
只会用于debug以及使用GPU的情况. 从逻辑上来看,可以暂时不用管他.
to_cpu()
函数的定义如下:
inline void SyncedMemory::to_cpu() {
check_device();
switch (head_) {
case UNINITIALIZED:
......
case HEAD_AT_GPU:
#ifndef CPU_ONLY
if (cpu_ptr_ == NULL) {
CaffeMallocHost(&cpu_ptr_, size_, &cpu_malloc_use_cuda_);
own_cpu_data_ = true;
}
caffe_gpu_memcpy(size_, gpu_ptr_, cpu_ptr_);
head_ = SYNCED;
#else
NO_GPU;
#endif
break;
case HEAD_AT_CPU:
case SYNCED:
break;
}
}
其中head_如下:
enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };
SyncedHead head_;
至此可以看出to_cpu()
函数的主要目的是同步cpu和gpu的数据.具体可见相关文章.
cpu_ptr_
指向cpu上分配的内存,如果cpu_ptr = NULL
, 说明没有分配内存;
下面来分析一下blob中定义的三个智能指针:
1. shape_data_
指针;
2. data_
指针;
3. diff_
指针;
shape_data_指针
shape_data_
是指向SyncedMemory类型对象的智能指针.
shape_data_
所指向的空间里存放着num, channels, height, width.
data_指针
data_
也是指向SyncedMemory类型对象的智能指针. 访问其的接口是public成员函数data().
data_
所指空间存放着的是每次Forward时会用到的数据
diff_指针
diff_
是指向SyncedMemory类型对象的智能指针,访问其的接口是public成员函数diff().
其他
SyncedMemory类中size()函数的定义如下:
size_t size() const { return size_; }
那么size_是指啥?分配的内存大小,单位为字节.