作者:wjmishuai
出處:http://blog.csdn.net/wjmishuai/article/details/50961471
關於Blob就這麼多內容,畢竟就是一個統一的數據存取接口,學到了一些封裝的手法,可以看看CPU和GPU一些接口的封裝;另一方面是對於Protocol Buffer有了一些瞭解。
<span style="font-size:24px;">#ifndef CAFFE_BLOB_HPP_//防止頭文件重複引用
#define CAFFE_BLOB_HPP_
#include <algorithm>
#include <string>
#include <vector>
/*common.hpp主要用來單例化Caffe類,
*並封裝了boost和CUDA隨機數生成的函數,
*提供了統一的接口
*/
#include "common.hpp"
/*caffe.pb.h是google protocol buffer根據caffe.proto自動生成的。
*使用protocol buffer有這些好處,一方面可以用文本文件定義結構化的數據類型,
*另一方面可以生成查詢效率更高、佔空間更小的二進制文件
*/
#include "caffe.pb.h"
//syncedmem主要用於分配內存和釋放內存
#include "syncedmem.hpp"
//math_functions裏面封裝了很多cblas矩陣運算
#include "util/math_functions.hpp"
const int kMaxBlobAxes = INT_MAX;
namespace caffe {//命名空間爲caffe
/*
*主要數據有兩個data和diff,用num、channels、height和width
*這四個維度來確定數據的具體位置,做一些數據查詢和Blobreshape的操作
*/
template <typename Dtype>
class Blob {
public:
Blob()//blob的構造函數
: data_(), diff_(), count_(0), capacity_(0) {}//data_(), diff_()是用於存放數據的指針,
/*num_, channel_, height_, width_主要用來做定位offset和reshape處理。
*對於輸入(n, c, h, w)位置的數據位置爲((n*channels_+c)*height_+h)*width_+w,
*可以依據位置取data_()或diff_()中的數據。
*/
explicit Blob(const int num, const int channels, const int height,
const int width);
explicit Blob(const vector<int>& shape);
/*Reshape函數的作用是改變一個blob的大小
*1.讀入num_,channels_,height_,width_的大小
*2.計算count_:count_ = num_ * channels_ * height_ * width_;
*3.如果count_不爲0,則重新爲data_和diff_分配一塊空間
*如果count爲0,則都初始化爲NULL
*/
void Reshape(const int num, const int channels, const int height,
const int width);
void Reshape(const vector<int>& shape);
void Reshape(const BlobShape& shape);
//ReshapeLike的作用是爲data_和diff_ 重新分配一塊空間,大小和另一個blob的一樣
void ReshapeLike(const Blob& other);
inline string shape_string() const {
ostringstream stream;
for (int i = 0; i < shape_.size(); ++i) {
stream << shape_[i] << " ";
}
stream << "(" << count_ << ")";
return stream.str();
}
inline const vector<int>& shape() const { return shape_; }//返回shape
//返回第i個索引的shape,index可以是負數,
inline int shape(int index) const {
return shape_[CanonicalAxisIndex(index)];
}
inline int num_axes() const { return shape_.size(); }//返回shape的大小
inline int count() const { return count_; }//返回參數count
//計算一個slice的體積
inline int count(int start_axis, int end_axis) const {
int count = 1;
for (int i = start_axis; i < end_axis; ++i) {
count *= shape(i);
}
return count;
}
//計算從從一個特定的axis到最後一個axis的slice的體積。
inline int count(int start_axis) const {
return count(start_axis, num_axes());
}
//對負數(index可能是負數)規範化的一個函數
inline int CanonicalAxisIndex(int axis_index) const {
if (axis_index < 0) {
return axis_index + num_axes();
}
return axis_index;
}
/// 功能是返回一些成員變量,比如,num,channels,height,width等
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 {
if (index >= num_axes() || index < -num_axes()) {
/*如果index超出索引範圍,但是在範圍 [0, 3] 或[-4, -1]內,
*這種特殊的情況下,模擬一個填充值,用來填補axes 。
*/
return 1;
}
return shape(index);
}
//計算偏移量,因爲數據在內存是以一維數組形式的,所以需要計算偏移量來訪問
inline int offset(const int n, const int c = 0, const int h = 0,
const int w = 0) const {
return ((n * channels() + c) * height() + h) * width() + w;
}
inline int offset(const vector<int>& indices) const {
int offset = 0;
for (int i = 0; i < num_axes(); ++i) {
offset *= shape(i);
if (indices.size() > i) {
offset += indices[i];
}
}
return offset;
}
/**
*從source拷貝數據。copy_diff作爲標誌來區分是拷貝data還是拷貝diff
*1.如果是GPU: 如果是拷貝diff:調用cudaMemcpy函數將source的diff拷貝過來,否則拷貝data
*2.如果是CPU: 如果是拷貝diff:調用memcpy函數將source的diff拷貝過來 否則拷貝data
*/
void CopyFrom(const Blob<Dtype>& source, bool copy_diff = false,
bool reshape = false);
//從cpu訪問數據data
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)];
}
//從cpu訪問數據diff
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)];
}
//從cpu訪問數據data
inline Dtype data_at(const vector<int>& index) const {
return cpu_data()[offset(index)];
}
//從cpu訪問數據diff
inline Dtype diff_at(const vector<int>& index) const {
return cpu_diff()[offset(index)];
}
//從cpu訪問數據data
inline const shared_ptr<SyncedMemory>& data() const {
return data_;
}
//從cpu訪問數據diff
inline const shared_ptr<SyncedMemory>& diff() const {
return diff_;
}
/**調用SyncedMemory的函數,來返回數據的指針;前兩個調用to_cpu(),返回cpu_ptr;
*第一個對於data對象,第二個對於diff對象
*後兩個調用to_gpu(),返回gpu_ptr;第一個對於data對象,第二個對於diff對象
*/
void set_cpu_data(Dtype* data);
const Dtype* cpu_data() 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();
/**更新data_的數據,就是減去diff_的數據。
*1.判斷blob的位置
*2.調用caffe_axpy:在math_functions.cpp可以找到該函數的實現,其實這函數也是封裝了mkl的函數。這裏調用是爲了實現了兩個向量的減法。
*3.調用caffe_gpu_axpy:在math_functions.cpp可以找到該函數的實現,其實這函數也是封裝了cublas的函數。這裏調用是爲了實現了兩個向量的減法。
*/
void Update();
/**功能:從proto讀數據進來,其實就是反序列化
*1.先把blob的大小改變一下
*2.得到cpu中數據的地址
*3.用proto中的data覆蓋blob中的data
*4.用proto中的diff覆蓋blob中的diff
*/
void FromProto(const BlobProto& proto, bool reshape = true);
//把blob數據保存到proto中
void ToProto(BlobProto* proto, bool write_diff = false) const;
//計算絕對值的data總和(L1範數)。
Dtype asum_data() const;
//計算絕對值的diff總和(L1範數)。
Dtype asum_diff() const;
//計算絕對值的data總和(L2範數)。
Dtype sumsq_data() const;
//計算絕對值的diff總和(L2範數)。
Dtype sumsq_diff() const;
//通過常量因子測量blob data
void scale_data(Dtype scale_factor);
////通過常量因子測量blob diff
void scale_diff(Dtype scale_factor);
//從other的blob複製data和diff的值
void ShareData(const Blob& other);
void ShareDiff(const Blob& other);
bool ShapeEquals(const BlobProto& other);
protected:
shared_ptr<SyncedMemory> data_;// 存放數據
shared_ptr<SyncedMemory> diff_;//存放梯度
vector<int> shape_;//存放形狀
int count_;//數據個數
int capacity_;//數據容量
DISABLE_COPY_AND_ASSIGN(Blob);
}; // class Blob
} // namespace caffe
#endif // CAFFE_BLOB_HPP_</span>