caffe-Blob.cpp文件

定义Blob类中每个成员函数,void Blob<Dtype>::Reshape(const vector<int>&)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
template <typename Dtype>
void Blob<Dtype>::Reshape(const vector<int>& shape) {
// 确保Shape中元素少于Blob允许的最大维度数
CHECK_LE(shape.size(), kMaxBlobAxes);
count_ = 1;
// 调用vector.resize(),
shape_.resize(shape.size());
// shape_data_为空指针,或这个指针多指向的内存小于变形后的大小,则:
if (!shape_data_ || shape_data_->size() < shape.size() * sizeof(int)) {
// 让shape_data_接管一个新的指针,它指向一块新的内存
shape_data_.reset(new SyncedMemory(shape.size() * sizeof(int)));
}

// 开辟临时空间向其传入当前CPU数据,返回一个指针shape_data
int* shape_data = static_cast<int*>(shape_data_->mutable_cpu_data());
// 遍历Shape中每一元素(每一维度)
for (int i = 0; i < shape.size(); ++i) {
CHECK_GE(shape[i], 0);
// 只要这个Blob中的count_(元素个数)不是0,即这个Blob存在元素,则???
// 若Blob中不存在元素,则???。
if (count_ != 0) {
CHECK_LE(shape[i], INT_MAX / count_) << "blob size exceeds INT_MAX";
}
// 更新count_, 记录变形后的这个Blob元素个数
count_ *= shape[i];
// 更新shape_,用新的这个维度值替换旧的
shape_[i] = shape[i];
// ????????
shape_data[i] = shape[i];
}

// 当数据个数超过Blob容量,怎更新容量大小
if (count_ > capacity_) {
capacity_ = count_;
// 让data_和diff_分别接管一块新的内存
data_.reset(new SyncedMemory(capacity_ * sizeof(Dtype)));
diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype)));
}
}

这个函数的功能,当新的reshape后所有维度元素个数N之和小于原来元素个数M,只取M的前N个元素;
当等于时,元素不变。当大于时,所有元素变为零。不过正常的使用是元素个数相同间的reshape。

有了上述的方法,下面的方法调用上面的方法:
void Blob<Dtype>::ReshapeLike(const Blob<Dtype>&)
void Blob<Dtype>::Reshape(int,int,int,int)

读取Blob中已有的cpu_data

1
2
3
4
5
6
template <typename Dtype>
const Dtype* Blob<Dtype>::cpu_data() const {
CHECK(data_);
// 成员data_为共享指针,其指向的存储空间含有cpu_data
return (const Dtype*)data_->cpu_data();
}

为Blob设置cpu_data

1
2
3
4
5
6
7
8
9
10
11
12
template <typename Dtype>
void Blob<Dtype>::set_cpu_data(Dtype* data) {
CHECK(data);
// Make sure CPU and GPU sizes remain equal
size_t size = count_ * sizeof(Dtype);
if (data_->size() != size) {
data_.reset(new SyncedMemory(size));
diff_.reset(new SyncedMemory(size));
}
// 用传入参数'data'设置data_成员变量
data_->set_cpu_data(data);
}

可写访问CPU_data

1
2
3
4
5
template <typename Dtype>
Dtype* Blob<Dtype>::mutable_cpu_data() {
CHECK(data_);
return static_cast<Dtype*>(data_->mutable_cpu_data());
}

其他关于访问,设置cpu,gpu的 data和diff都类似,略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// const只读访问
const Dtype* cpu_data() const;
const Dtype* cpu_diff() const;
// 只读访问GPU数据形状
const int* gpu_shape() const;
const Dtype* gpu_data() const;
const Dtype* gpu_diff() const;
// mutable读写访问
Dtype* mutable_cpu_data();
Dtype* mutable_gpu_data();
Dtype* mutable_cpu_diff();
Dtype* mutable_gpu_diff();
// 设置cpu和gpu数据
void set_cpu_data(Dtype* data);
void set_gpu_data(Dtype* data);

共享BLob数据data:共享diff与下面代码一样。

1
2
3
4
5
6
template <typename Dtype>
void Blob<Dtype>::ShareData(const Blob& other) {
CHECK_EQ(count_, other.count());
// 将这个BLob的data_设为与other一样的值,共享
data_ = other.data();
}

执行Updata():
其中:caffe_axpysrc/caffe/util/math_functions.cpp中,
caffe_gpu_axpysrc/caffe/util/math_functions.cu中。
这两个操作实际是:data_[i] = data_[i] - diff_[i], 其中i=0,1,2,3,4...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template <typename Dtype>
void Blob<Dtype>::Update() {
// 执行计算取决于数据在哪
switch (data_->head()) { // 获得当前SyncedMemory对象状态
case SyncedMemory::HEAD_AT_CPU: // 如果在cpu则
// 执行在CPU上的计算
caffe_axpy<Dtype>(count_,
Dtype(-1),
static_cast<const Dtype*>(diff_->cpu_data()),
static_cast<Dtype*>(data_->mutable_cpu_data()));
break;
case SyncedMemory::HEAD_AT_GPU:
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
// 若使用GPU,则执行在GPU上update()
caffe_gpu_axpy<Dtype>(count_,
Dtype(-1),
static_cast<const Dtype*>(diff_->gpu_data()),
static_cast<Dtype*>(data_->mutable_gpu_data()));
#else
NO_GPU;
#endif
break;
default:
LOG(FATAL) << "Syncedmem not initialized.";
}
}

其他类似的函数结构相同,只是核心操作不同,略

1
2
3
4
5
6
7
8
9
// 计算l1范数 元素和
Dtype asum_data() const;
Dtype asum_diff() const;
// 计算l2范数 元素平方和
Dtype sumsq_data() const;
Dtype sumsq_diff() const;
// 元素可以一个常数
void scale_data(Dtype scale_factor);
void scale_diff(Dtype scale_factor);

共享数据很直接,略

1
2
3
// 共享other这个Blob的data_和diff_
void ShareData(const Blob& other);
void ShareDiff(const Blob& other);

从其他blob拷贝数据到当前Blob:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
template <typename Dtype>
void Blob<Dtype>::CopyFrom(const Blob& source, bool copy_diff,
bool reshape) {
// 必要时reshape
if (source.count() != count_ || source.shape() != shape_) {
if (reshape) {
ReshapeLike(source);
} else {
LOG(FATAL) << "Trying to copy blobs of different sizes.";
}
}
switch (Caffe::mode()) {
// 如果是GPU模式就拷贝GPU数据
case Caffe::GPU:
if (copy_diff) {
caffe_copy(count_, source.gpu_diff(),
static_cast<Dtype*>(diff_->mutable_gpu_data()));
} else {
caffe_copy(count_, source.gpu_data(),
static_cast<Dtype*>(data_->mutable_gpu_data()));
}
break;
// 如果是CPU模式就拷贝CPU数据
case Caffe::CPU:
if (copy_diff) {
caffe_copy(count_, source.cpu_diff(),
static_cast<Dtype*>(diff_->mutable_cpu_data()));
} else {
caffe_copy(count_, source.cpu_data(),
static_cast<Dtype*>(data_->mutable_cpu_data()));
}
break;
default:
LOG(FATAL) << "Unknown caffe mode.";
}
}

反序列化数据,将磁盘数据读入protobuff:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
template <typename Dtype>
void Blob<Dtype>::FromProto(const BlobProto& proto, bool reshape) {
// 如果需要reshape,先reshape
if (reshape) {
vector<int> shape;
if (proto.has_num() || proto.has_channels() ||
proto.has_height() || proto.has_width()) {
// Using deprecated 4D Blob dimensions --
// shape is (num, channels, height, width).
shape.resize(4);
shape[0] = proto.num();
shape[1] = proto.channels();
shape[2] = proto.height();
shape[3] = proto.width();
} else {
shape.resize(proto.shape().dim_size());
for (int i = 0; i < proto.shape().dim_size(); ++i) {
shape[i] = proto.shape().dim(i);
}
}
Reshape(shape); // 按照维度信息变换
} else {
CHECK(ShapeEquals(proto)) << "shape mismatch (reshape not set)";
}
// 从protobuff拷贝数据到当前Blob:
// 获取当前Blob的mutable_cpu_data的地址data_vec,
// 将protobuff中double或float数据 data写入到地址data_vec
// diff 与data一样:
Dtype* data_vec = mutable_cpu_data();
if (proto.double_data_size() > 0) {
CHECK_EQ(count_, proto.double_data_size());
for (int i = 0; i < count_; ++i) {
data_vec[i] = proto.double_data(i);
}
} else {
CHECK_EQ(count_, proto.data_size());
for (int i = 0; i < count_; ++i) {
data_vec[i] = proto.data(i);
}
}
if (proto.double_diff_size() > 0) {
CHECK_EQ(count_, proto.double_diff_size());
Dtype* diff_vec = mutable_cpu_diff();
for (int i = 0; i < count_; ++i) {
diff_vec[i] = proto.double_diff(i);
}
} else if (proto.diff_size() > 0) {
CHECK_EQ(count_, proto.diff_size());
Dtype* diff_vec = mutable_cpu_diff();
for (int i = 0; i < count_; ++i) {
diff_vec[i] = proto.diff(i);
}
}
}

将数据序列化(写入磁盘):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <>
void Blob<double>::ToProto(BlobProto* proto, bool write_diff) const {
// 重置protobuff维度,清理原有的数据 并写入新的cpu_data数据
proto->clear_shape();
for (int i = 0; i < shape_.size(); ++i) {
proto->mutable_shape()->add_dim(shape_[i]);
}
proto->clear_double_data();
proto->clear_double_diff();
const double* data_vec = cpu_data();
for (int i = 0; i < count_; ++i) {
proto->add_double_data(data_vec[i]);
}
// 如果需要写入diff,也要写入cpu_diff数据
if (write_diff) {
const double* diff_vec = cpu_diff();
for (int i = 0; i < count_; ++i) {
proto->add_double_diff(diff_vec[i]);
}
}
}