首先,Blob使用的小例子(通过运行结果即可知道相关功能):

#include <vector>
#include <caffe/blob.hpp>
#include <caffe/util/io.hpp>//磁盘读写
#include <iostream> using namespace std;
using namespace caffe; int main()
{
Blob<float> a;
cout<<"Size: "<<a.shape_string()<<endl;
a.Reshape(,,,);
cout<<"Size: "<<a.shape_string()<<endl;
a.Reshape(,,,);
cout<<"Size: "<<a.shape_string()<<endl; float* p=a.mutable_cpu_data();
float* q=a.mutable_cpu_diff();
for(int i=;i<a.count();i++)
{
p[i]=i;
q[i]=a.count()--i;
}
cout<<"L1: "<<a.asum_data()<<endl;
cout<<"L2: "<<a.sumsq_data()<<endl;
//a.Update(); //磁盘读写
BlobProto bp;
a.ToProto(&bp,true);//a序列化,连带diff(默认不带)
WriteProtoToBinaryFile(bp,"a.blob");
BlobProto bp2;
ReadProtoFromBinaryFileOrDie("a.blob",&bp2);
Blob<float> b;
b.FromProto(bp2,true);//从序列化对象中克隆b(连同形状)
b.Update();
cout<<"L1: "<<b.asum_data()<<endl;
cout<<"L2: "<<b.sumsq_data()<<endl; return ;
}

编译:

export LD_LIBRARY_PATH=./build/lib/:$LD_LIBRARY_PATH

g++ -o app ./bambootry/try.cpp -I ./include/ -D CPU_ONLY \
-I ./.build_release/src/ \
-L ./.build_release/lib/ -lcaffe -lglog -lboost_system

运行结果:

进入正题,代码注释

src/caffe/proto/caffe.proto中Blob部分

// Specifies the shape (dimensions) of a Blob.表示Blob每个维度的大小
message BlobShape {
repeated int64 dim = [packed = true];//packed表示这些值在内存中紧密排布没有空洞
}
//该结构描述Blob在磁盘中序列化的形态
message BlobProto {
optional BlobShape shape = ; //可选,包括一个BlobShape对象
repeated float data = [packed = true]; //包括若干浮点元素,存储数据或权重,元素数目由shape或(num,channels,height,weight)决定
repeated float diff = [packed = true]; //包括若干浮点元素,用于存储增量信息,维度与data数组一致
repeated double double_data = [packed = true]; //data 类型double
repeated double double_diff = [packed = true]; //diff 类型double // 4D dimensions -- deprecated. Use "shape" instead.可选,维度信息。新版本推荐使用shape
optional int32 num = [default = ];
optional int32 channels = [default = ];
optional int32 height = [default = ];
optional int32 width = [default = ];
}

include/caffe/blob.hpp (其中使用了SyncedMemory类,具体有关该类的内容在其他文件中) 作为基本计算单元服务 Layer Net Solver等

 #ifndef CAFFE_BLOB_HPP_
#define CAFFE_BLOB_HPP_ #include <algorithm>
#include <string>
#include <vector> #include "caffe/common.hpp"
#include "caffe/proto/caffe.pb.h" //由protoc生成的头文件,声明了BlobProto、BlobShape等遵循caffe.proto协议的数据结构
#include "caffe/syncedmem.hpp" //CPU和GPU共享内存类,用于数据同步 const int kMaxBlobAxes = ; //Blob最大维数 namespace caffe { /**
* @brief A wrapper around SyncedMemory holders serving as the basic
* computational unit through which Layer%s, Net%s, and Solver%s
* interact.
*
* TODO(dox): more thorough description.
*/
template <typename Dtype>
class Blob {
public:
Blob()
: data_(), diff_(), count_(), capacity_() {} //默认构造函数 /// @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>.
// 变形函数,根据输入参数重新设置当前Blob形状,必要时重新分配内存
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.
*
* 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,见Caffe运行log
//例如: Top Shape: 100 1 28 28 (78400)
inline string shape_string() const {
ostringstream stream;
for (int i = ; 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.
*/
//返回某一维度尺寸
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.
*/
//返回Blob中某几个维度子集的元素总数
inline int count(int start_axis, int end_axis) const {
CHECK_LE(start_axis, end_axis);//保证start_sxis<=end_axis
CHECK_GE(start_axis, );//保证start_sxis>=0
CHECK_GE(end_axis, );//保证end_axis>=0
CHECK_LE(start_axis, num_axes());//保证start_sxis小于总维度数目
CHECK_LE(end_axis, num_axes());//保证end_axis小于总维度数目
int count = ;
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.
*/
//计算从某一个维度开始的元素总数
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.
*/
//转换坐标轴索引
inline int CanonicalAxisIndex(int axis_index) const {
CHECK_GE(axis_index, -num_axes())//保证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_index<=num_axes()
<< "axis " << axis_index << " out of range for " << num_axes()
<< "-D Blob with shape " << shape_string();
if (axis_index < ) {
return axis_index + num_axes();//负索引号表示从后向前索引,例如-1为最后一个,即正索引号的N-1
}
return axis_index;
} /// @brief Deprecated legacy shape accessor num: use shape(0) instead.
inline int num() const { return LegacyShape(); }
/// @brief Deprecated legacy shape accessor channels: use shape(1) instead.
inline int channels() const { return LegacyShape(); }
/// @brief Deprecated legacy shape accessor height: use shape(2) instead.
inline int height() const { return LegacyShape(); }
/// @brief Deprecated legacy shape accessor width: use shape(3) instead.
inline int width() const { return LegacyShape(); }
inline int LegacyShape(int index) const {
CHECK_LE(num_axes(), )
<< "Cannot use legacy accessors on Blobs with > 4 axes.";
CHECK_LT(index, );
CHECK_GE(index, -);
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 ;
}
return shape(index);
}
//offset函数用于计算偏移量
inline int offset(const int n, const int c = , const int h = ,
const int w = ) const {
CHECK_GE(n, );
CHECK_LE(n, num());
CHECK_GE(channels(), );
CHECK_LE(c, channels());
CHECK_GE(height(), );
CHECK_LE(h, height());
CHECK_GE(width(), );
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 = ;
for (int i = ; i < num_axes(); ++i) {
offset *= shape(i);
if (indices.size() > i) {
CHECK_GE(indices[i], );
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到当前Blob
void CopyFrom(const Blob<Dtype>& source, bool copy_diff = false,
bool reshape = false);
//下面为一系列存取器
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;//只读访问cpu data
void set_cpu_data(Dtype* data);//设置cpu data
const int* gpu_shape() const;
const Dtype* gpu_data() const;//只读访问gpu data
void set_gpu_data(Dtype* data);//设置gpu data
const Dtype* cpu_diff() const;//只读访问cpu diff
const Dtype* gpu_diff() const;//只读访问gpu diff
Dtype* mutable_cpu_data();//读写访问
Dtype* mutable_gpu_data();//读写访问
Dtype* mutable_cpu_diff();//读写访问
Dtype* mutable_gpu_diff();//读写访问
void Update();//Blob更新运算
void FromProto(const BlobProto& proto, bool reshape = true);//反序列化函数,从BlobProto中恢复一个Blob对象
void ToProto(BlobProto* proto, bool write_diff = false) const;//序列化函数,将内存中的Blob对象保存到BlobProto中 /// @brief Compute the sum of absolute values (L1 norm) of the data.
Dtype asum_data() const;//计算data的L1范数,即绝对值求和
/// @brief Compute the sum of absolute values (L1 norm) of the diff.
Dtype asum_diff() const;//计算diff的L1范数,即绝对值求和
/// @brief Compute the sum of squares (L2 norm squared) of the data.
Dtype sumsq_data() const;//计算data的平方和,用于L2范数
/// @brief Compute the sum of squares (L2 norm squared) of the diff.
Dtype sumsq_diff() const;//计算diff的平方和,用于L2范数 /// @brief Scale the blob data by a constant factor.
void scale_data(Dtype scale_factor);//data乘一个标量
/// @brief Scale the blob diff by a constant factor.
void scale_diff(Dtype scale_factor);//diff乘一个标量 /**
* @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.
*/
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.
*/
void ShareDiff(const Blob& other);//共享另一个Blob的diff_ 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_

include/caffe/syncedmem.hpp

 #ifndef CAFFE_SYNCEDMEM_HPP_
#define CAFFE_SYNCEDMEM_HPP_ #include <cstdlib> #ifdef USE_MKL
#include "mkl.h"
#endif #include "caffe/common.hpp" namespace caffe { // If CUDA is available and in GPU mode, host memory will be allocated pinned,
// using cudaMallocHost. It avoids dynamic pinning for transfers (DMA).
// The improvement in performance seems negligible in the single GPU case,
// but might be more significant for parallel training. Most importantly,
// it improved stability for large models on many GPUs.
// 如果是GPU模式且CUDA使能,则主机内存会以页锁定内存方式分配(使用cudaMallocHost()函数)
// 对单GPU提升并不明显,对多GPU提升非常明显
inline void CaffeMallocHost(void** ptr, size_t size, bool* use_cuda) {
#ifndef CPU_ONLY
if (Caffe::mode() == Caffe::GPU) {
CUDA_CHECK(cudaMallocHost(ptr, size));
*use_cuda = true;
return;
}
#endif
#ifdef USE_MKL
*ptr = mkl_malloc(size ? size:, );
#else
*ptr = malloc(size);
#endif
*use_cuda = false;
CHECK(*ptr) << "host allocation of size " << size << " failed";
}
// 与CaffeMallocHost对应
inline void CaffeFreeHost(void* ptr, bool use_cuda) {
#ifndef CPU_ONLY
if (use_cuda) {
CUDA_CHECK(cudaFreeHost(ptr));
return;
}
#endif
#ifdef USE_MKL
mkl_free(ptr);
#else
free(ptr);
#endif
} /**
* @brief Manages memory allocation and synchronization between the host (CPU)
* and device (GPU).
*
* TODO(dox): more thorough description.
*/
// 该类负责存储分配以及主机设备间同步
class SyncedMemory {
public:
SyncedMemory();
explicit SyncedMemory(size_t size);
~SyncedMemory();
const void* cpu_data(); //只读
void set_cpu_data(void* data);//设置
const void* gpu_data(); //只读
void set_gpu_data(void* data);//设置
void* mutable_cpu_data(); //读写
void* mutable_gpu_data(); //读写
//状态机变量,4种状态:未初始化 CPU数据有效 GPU数据有效 已同步
enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };
SyncedHead head() { return head_; }//获取当前状态机变量值
size_t size() { return size_; } //获取当前存储空间尺寸 #ifndef CPU_ONLY
void async_gpu_push(const cudaStream_t& stream);
#endif private:
void check_device(); void to_cpu(); //数据同步到CPU
void to_gpu(); //数据同步到GPU
void* cpu_ptr_; //位于CPU的数据指针
void* gpu_ptr_; //位于GPU的数据指针
size_t size_; //存储空间大小
SyncedHead head_; //状态机变量
bool own_cpu_data_;//标志是否拥有CPU数据权(否,即从别的对象共享)
bool cpu_malloc_use_cuda_;
bool own_gpu_data_;//标志是否拥有GPU数据权
int device_; DISABLE_COPY_AND_ASSIGN(SyncedMemory);
}; // class SyncedMemory } // namespace caffe #endif // CAFFE_SYNCEDMEM_HPP_

src/caffe/blob.cpp

 #include <climits>
#include <vector> #include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/syncedmem.hpp"
#include "caffe/util/math_functions.hpp" namespace caffe {
//变维函数,将(num,channels,height,width)转为vector<int>并调用重载函数
template <typename Dtype>
void Blob<Dtype>::Reshape(const int num, const int channels, const int height,
const int width) {
vector<int> shape();
shape[] = num;
shape[] = channels;
shape[] = height;
shape[] = width;
Reshape(shape);
}
//真正的变维函数
template <typename Dtype>
void Blob<Dtype>::Reshape(const vector<int>& shape) {
CHECK_LE(shape.size(), kMaxBlobAxes);//保证vector维度小于kMaxBlobAxes
count_ = ;//用于计算元素总数=num*channels*height*width
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 = ; i < shape.size(); ++i) {
CHECK_GE(shape[i], );
if (count_ != ) {//保证count不溢出
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_) {//如果新的count_大于当前分配的空间容量
capacity_ = count_; //扩容,重新分配data_和diff_空间
data_.reset(new SyncedMemory(capacity_ * sizeof(Dtype)));
diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype)));
}
} template <typename Dtype>
void Blob<Dtype>::Reshape(const BlobShape& shape) {
CHECK_LE(shape.dim_size(), kMaxBlobAxes);
vector<int> shape_vec(shape.dim_size());
for (int i = ; i < shape.dim_size(); ++i) {
shape_vec[i] = shape.dim(i);
}
Reshape(shape_vec);
} template <typename Dtype>
void Blob<Dtype>::ReshapeLike(const Blob<Dtype>& other) {
Reshape(other.shape());
}
//构造函数
template <typename Dtype>
Blob<Dtype>::Blob(const int num, const int channels, const int height,
const int width)
// capacity_ must be initialized before calling Reshape
: capacity_() {
//调用Reshape之前必须初始化capacity,否则会导致不可预期的后果
Reshape(num, channels, height, width);
} template <typename Dtype>
Blob<Dtype>::Blob(const vector<int>& shape)
// capacity_ must be initialized before calling Reshape
: capacity_() {
Reshape(shape);
} template <typename Dtype>
const int* Blob<Dtype>::gpu_shape() const {
CHECK(shape_data_);
return (const int*)shape_data_->gpu_data();
}
//只读获得cpu data指针
template <typename Dtype>
const Dtype* Blob<Dtype>::cpu_data() const {
CHECK(data_);//保证data_不为空
return (const Dtype*)data_->cpu_data();
}
//修改cpu data指针
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_->set_cpu_data(data);//设置成员变量值为传入参数值
}
//只读获得gpu data指针
template <typename Dtype>
const Dtype* Blob<Dtype>::gpu_data() const {
CHECK(data_);//保证不为空
return (const Dtype*)data_->gpu_data();
}
//修改gpu data指针
template <typename Dtype>
void Blob<Dtype>::set_gpu_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_->set_gpu_data(data);
}
//只读获得cpu diff指针
template <typename Dtype>
const Dtype* Blob<Dtype>::cpu_diff() const {
CHECK(diff_);
return (const Dtype*)diff_->cpu_data();
}
//只读获得gpu diff指针
template <typename Dtype>
const Dtype* Blob<Dtype>::gpu_diff() const {
CHECK(diff_);
return (const Dtype*)diff_->gpu_data();
}
//读写访问cpu_data
template <typename Dtype>
Dtype* Blob<Dtype>::mutable_cpu_data() {
CHECK(data_);
return static_cast<Dtype*>(data_->mutable_cpu_data());
}
//读写访问gpu_data
template <typename Dtype>
Dtype* Blob<Dtype>::mutable_gpu_data() {
CHECK(data_);
return static_cast<Dtype*>(data_->mutable_gpu_data());
}
//读写访问cpu_diff
template <typename Dtype>
Dtype* Blob<Dtype>::mutable_cpu_diff() {
CHECK(diff_);
return static_cast<Dtype*>(diff_->mutable_cpu_data());
}
//读写访问gpu_diff
template <typename Dtype>
Dtype* Blob<Dtype>::mutable_gpu_diff() {
CHECK(diff_);
return static_cast<Dtype*>(diff_->mutable_gpu_data());
}
//共享另一个Blob的data指针
template <typename Dtype>
void Blob<Dtype>::ShareData(const Blob& other) {
CHECK_EQ(count_, other.count());
data_ = other.data();
}
//共享另一个Blob的diff指针
template <typename Dtype>
void Blob<Dtype>::ShareDiff(const Blob& other) {
CHECK_EQ(count_, other.count());
diff_ = other.diff();
} // The "update" method is used for parameter blobs in a Net, which are stored
// as Blob<float> or Blob<double> -- hence we do not define it for
// Blob<int> or Blob<unsigned int>.
//更新函数用于网络参数Blob的更新。其中int和unsigned int类型的处理并未实现
//实现的类型为Blob<float>和Blob<double>
template <> void Blob<unsigned int>::Update() { NOT_IMPLEMENTED; }
template <> void Blob<int>::Update() { NOT_IMPLEMENTED; } template <typename Dtype>
void Blob<Dtype>::Update() {
// We will perform update based on where the data is located.
//data在哪儿就在哪儿更新
switch (data_->head()) {
case SyncedMemory::HEAD_AT_CPU:
// perform computation on CPU
//执行CPU运算,data[i]=data[i]-diff[i],i=0~count-1
caffe_axpy<Dtype>(count_, Dtype(-),
static_cast<const Dtype*>(diff_->cpu_data()),
static_cast<Dtype*>(data_->mutable_cpu_data()));
break;
case SyncedMemory::HEAD_AT_GPU://data位于GPU或CPU/GPU已同步
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
// perform computation on GPU
//执行GPU运算,data[i]=data[i]-diff[i],i=0~count-1
caffe_gpu_axpy<Dtype>(count_, Dtype(-),
static_cast<const Dtype*>(diff_->gpu_data()),
static_cast<Dtype*>(data_->mutable_gpu_data()));
#else
NO_GPU;//编译时如果打开CPU_ONLY,则GPU禁用
#endif
break;
default:
LOG(FATAL) << "Syncedmem not initialized.";
}
} template <> unsigned int Blob<unsigned int>::asum_data() const {
NOT_IMPLEMENTED;
return ;
} template <> int Blob<int>::asum_data() const {
NOT_IMPLEMENTED;
return ;
}
//计算L1范数,即绝对值和
template <typename Dtype>
Dtype Blob<Dtype>::asum_data() const {
if (!data_) { return ; }
switch (data_->head()) {
case SyncedMemory::HEAD_AT_CPU:
return caffe_cpu_asum(count_, cpu_data());//执行CPU上的asum计算
case SyncedMemory::HEAD_AT_GPU:
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
{
Dtype asum;
caffe_gpu_asum(count_, gpu_data(), &asum);//执行GPU上的asum计算
return asum;
}
#else
NO_GPU;
#endif
case SyncedMemory::UNINITIALIZED:
return ;
default:
LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head();
}
return ;
} template <> unsigned int Blob<unsigned int>::asum_diff() const {
NOT_IMPLEMENTED;
return ;
} template <> int Blob<int>::asum_diff() const {
NOT_IMPLEMENTED;
return ;
} template <typename Dtype>
Dtype Blob<Dtype>::asum_diff() const {
if (!diff_) { return ; }
switch (diff_->head()) {
case SyncedMemory::HEAD_AT_CPU:
return caffe_cpu_asum(count_, cpu_diff());
case SyncedMemory::HEAD_AT_GPU:
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
{
Dtype asum;
caffe_gpu_asum(count_, gpu_diff(), &asum);
return asum;
}
#else
NO_GPU;
#endif
case SyncedMemory::UNINITIALIZED:
return ;
default:
LOG(FATAL) << "Unknown SyncedMemory head state: " << diff_->head();
}
return ;
} template <> unsigned int Blob<unsigned int>::sumsq_data() const {
NOT_IMPLEMENTED;
return ;
} template <> int Blob<int>::sumsq_data() const {
NOT_IMPLEMENTED;
return ;
}
//用于L2范数,平方和
template <typename Dtype>
Dtype Blob<Dtype>::sumsq_data() const {
Dtype sumsq;
const Dtype* data;
if (!data_) { return ; }
switch (data_->head()) {
case SyncedMemory::HEAD_AT_CPU:
data = cpu_data();
sumsq = caffe_cpu_dot(count_, data, data);
break;
case SyncedMemory::HEAD_AT_GPU:
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
data = gpu_data();
caffe_gpu_dot(count_, data, data, &sumsq);
#else
NO_GPU;
#endif
break;
case SyncedMemory::UNINITIALIZED:
return ;
default:
LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head();
}
return sumsq;
} template <> unsigned int Blob<unsigned int>::sumsq_diff() const {
NOT_IMPLEMENTED;
return ;
} template <> int Blob<int>::sumsq_diff() const {
NOT_IMPLEMENTED;
return ;
} template <typename Dtype>
Dtype Blob<Dtype>::sumsq_diff() const {
Dtype sumsq;
const Dtype* diff;
if (!diff_) { return ; }
switch (diff_->head()) {
case SyncedMemory::HEAD_AT_CPU:
diff = cpu_diff();
sumsq = caffe_cpu_dot(count_, diff, diff);
break;
case SyncedMemory::HEAD_AT_GPU:
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
diff = gpu_diff();
caffe_gpu_dot(count_, diff, diff, &sumsq);
break;
#else
NO_GPU;
#endif
case SyncedMemory::UNINITIALIZED:
return ;
default:
LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head();
}
return sumsq;
} template <> void Blob<unsigned int>::scale_data(unsigned int scale_factor) {
NOT_IMPLEMENTED;
} template <> void Blob<int>::scale_data(int scale_factor) {
NOT_IMPLEMENTED;
}
//对data_进行幅度缩放
template <typename Dtype>
void Blob<Dtype>::scale_data(Dtype scale_factor) {
Dtype* data;
if (!data_) { return; }
switch (data_->head()) {
case SyncedMemory::HEAD_AT_CPU:
data = mutable_cpu_data();
caffe_scal(count_, scale_factor, data);
return;
case SyncedMemory::HEAD_AT_GPU:
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
data = mutable_gpu_data();
caffe_gpu_scal(count_, scale_factor, data);
return;
#else
NO_GPU;
#endif
case SyncedMemory::UNINITIALIZED:
return;
default:
LOG(FATAL) << "Unknown SyncedMemory head state: " << data_->head();
}
} template <> void Blob<unsigned int>::scale_diff(unsigned int scale_factor) {
NOT_IMPLEMENTED;
} template <> void Blob<int>::scale_diff(int scale_factor) {
NOT_IMPLEMENTED;
} template <typename Dtype>
void Blob<Dtype>::scale_diff(Dtype scale_factor) {
Dtype* diff;
if (!diff_) { return; }
switch (diff_->head()) {
case SyncedMemory::HEAD_AT_CPU:
diff = mutable_cpu_diff();
caffe_scal(count_, scale_factor, diff);
return;
case SyncedMemory::HEAD_AT_GPU:
case SyncedMemory::SYNCED:
#ifndef CPU_ONLY
diff = mutable_gpu_diff();
caffe_gpu_scal(count_, scale_factor, diff);
return;
#else
NO_GPU;
#endif
case SyncedMemory::UNINITIALIZED:
return;
default:
LOG(FATAL) << "Unknown SyncedMemory head state: " << diff_->head();
}
}
//判断形状是否相同
template <typename Dtype>
bool Blob<Dtype>::ShapeEquals(const BlobProto& other) {
if (other.has_num() || other.has_channels() ||
other.has_height() || other.has_width()) {
// Using deprecated 4D Blob dimensions --每个维度对比
// shape is (num, channels, height, width).
// Note: we do not use the normal Blob::num(), Blob::channels(), etc.
// methods as these index from the beginning of the blob shape, where legacy
// parameter blobs were indexed from the end of the blob shape (e.g., bias
// Blob shape (1 x 1 x 1 x N), IP layer weight Blob shape (1 x 1 x M x N)).
return shape_.size() <= &&
LegacyShape(-) == other.num() &&
LegacyShape(-) == other.channels() &&
LegacyShape(-) == other.height() &&
LegacyShape(-) == other.width();
}
//直接对比
vector<int> other_shape(other.shape().dim_size());
for (int i = ; i < other.shape().dim_size(); ++i) {
other_shape[i] = other.shape().dim(i);
}
return shape_ == other_shape;
}
//从另一个Blob拷贝data(可选diff),必要时进行变维
template <typename Dtype>
void Blob<Dtype>::CopyFrom(const Blob& source, bool copy_diff, bool 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()) {
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;
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.";
}
}
//从BlobProto中加载一个Blob
template <typename Dtype>
void Blob<Dtype>::FromProto(const BlobProto& proto, bool 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();
shape[] = proto.num();
shape[] = proto.channels();
shape[] = proto.height();
shape[] = proto.width();
} else {
shape.resize(proto.shape().dim_size());
for (int i = ; i < proto.shape().dim_size(); ++i) {
shape[i] = proto.shape().dim(i);
}
}
Reshape(shape);//变维
} else {
CHECK(ShapeEquals(proto)) << "shape mismatch (reshape not set)";
}
// copy data 加载数据
Dtype* data_vec = mutable_cpu_data();
if (proto.double_data_size() > ) {//若之前保存的是double类型的data
CHECK_EQ(count_, proto.double_data_size());
for (int i = ; i < count_; ++i) {
data_vec[i] = proto.double_data(i);//加载double data
}
} else {
CHECK_EQ(count_, proto.data_size());
for (int i = ; i < count_; ++i) {
data_vec[i] = proto.data(i);//否则加载float data
}
}
if (proto.double_diff_size() > ) {//若之前保存的是double类型的diff
CHECK_EQ(count_, proto.double_diff_size());
Dtype* diff_vec = mutable_cpu_diff();
for (int i = ; i < count_; ++i) {
diff_vec[i] = proto.double_diff(i);//加载double diff
}
} else if (proto.diff_size() > ) {
CHECK_EQ(count_, proto.diff_size());
Dtype* diff_vec = mutable_cpu_diff();
for (int i = ; i < count_; ++i) {
diff_vec[i] = proto.diff(i);//否则加载float diff
}
}
} template <>
void Blob<double>::ToProto(BlobProto* proto, bool write_diff) const {
proto->clear_shape();
for (int i = ; 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 = ; i < count_; ++i) {
proto->add_double_data(data_vec[i]);
}
if (write_diff) {
const double* diff_vec = cpu_diff();
for (int i = ; i < count_; ++i) {
proto->add_double_diff(diff_vec[i]);
}
}
}
//将Blob中的data(可选diff)导出到BlobProto结构体,便于存储到磁盘文件中
template <>
void Blob<float>::ToProto(BlobProto* proto, bool write_diff) const {
proto->clear_shape();//重置proto维度,保证与Blob相同
for (int i = ; i < shape_.size(); ++i) {
proto->mutable_shape()->add_dim(shape_[i]);
}
proto->clear_data();//清楚data
proto->clear_diff();//清楚diff
const float* data_vec = cpu_data();//将data导出到proto
for (int i = ; i < count_; ++i) {
proto->add_data(data_vec[i]);
}
if (write_diff) {//如果要求导出diff
const float* diff_vec = cpu_diff();//导出diff到proto
for (int i = ; i < count_; ++i) {
proto->add_diff(diff_vec[i]);
}
}
} INSTANTIATE_CLASS(Blob);//实例化Blob类模板(float,double )
template class Blob<int>;
template class Blob<unsigned int>; } // namespace caffe

初学者,慢慢看,待更新……

摘抄参考赵永科《深度学习 21天实战caffe》

【caffe Blob】caffe中与Blob相关的代码注释、使用举例的更多相关文章

  1. 关于BAPI_GOODSMVT_CREATE中货物移动相关事务代码说明

    BAPI_GOODSMVT_CREATE参数 goodsmvt_code中的GM_CODE是为 BAPI 货物移动分配事务代码 其取值为下面对应的事务代码: 01 MB0102 MB3103 MB1A ...

  2. Express4.10.2开发框架中默认app.js的代码注释

    //通过require()加载了express.path等模块var express = require('express');var path = require('path');var favic ...

  3. caffe中的Blob块

    首先说明:Blob定义了一个类模板. 让我们看一下Blob的头文件里有什么哈: 定义了一个全局变量: const ; 看看它的构造函数: Blob() : data_(), diff_(), coun ...

  4. caffe/blob.hpp:9:34: fatal error: caffe/proto/caffe.pb.h: 没有那个文件或目录

    You need to generate caffe.pb.h manually using protoc as follows. # In the directory you installed C ...

  5. Caffe源码中common文件分析

    Caffe源码(caffe version:09868ac , date: 2015.08.15)中的一些重要头文件如caffe.hpp.blob.hpp等或者外部调用Caffe库使用时,一般都会in ...

  6. HTML5中的Blob对象的使用

    HTML5中的Blob对象和MYSQL中的BLOB类型在概念上是有点区别的.MYSQL中的BLOB类型就只是个二进制数据容器.而HTML5中的Blob对象除了存放二进制数据外还可以设置这个数据的MIN ...

  7. js中从blob提取二进制

    文章结构: 一.所遇到的问题 二.解决方法 一. 服务器端通过websocket向浏览器端传输图片(二进制),需要根据不同的图片把图片显示在不同的位置,可行的一个方法是先把图片转化成二进制数组,再把二 ...

  8. caffe实际运行中遇到的问题

    https://blog.csdn.net/u010417185/article/details/52649178 1.均值计算是否需要统一图像的尺寸? 在图像计算均值时,应该先统一图像的尺寸,否则会 ...

  9. caffe 的docker安装过程及相关linux操作总结

    一.caffe 和 docker的安装编译 docker pull caffe镜像(注意使用docker安装省去安装CUDA和cudnn的安装.) 安装相关依赖包 安装opencv3(使用源码安装) ...

随机推荐

  1. Chrome谷歌浏览器插件-小结

    1.小插件库: Tampermonkey https://chrome.google.com/webstore/detail/tampermonkey-beta/gcalenpjmijncebpfij ...

  2. 隐藏Apache版本号及版本敏感信息

    在安装软件前,我们需要隐藏软件的版本号及版本其他信息,这样就大大提高了安全指数. 只隐藏版本号: 我们在主配置文件里:httpd.conf [root@bqh- ~]# curl -i bbs.bqh ...

  3. Centos部属前后端项目

    一.安装python3 # 下载并解压 cd /opt wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tgz tar -zxf P ...

  4. [ipsec][strongswan] strongswan源码分析--(五)plugin的配置文件的添加方法与管理架构解析

    前言 我们知道,strongswan是基于插件式管理的.不同的插件有不同的配置文件,在这下面, 我们以netlink的插件为例:etc/strongswan.d/charon/kernel-netli ...

  5. Elasticsearch 术语介绍和CRUD实际操作入门

    一.Elastic Stack 核心Elasticsearch Elasticsearch 是一个分布式.RESTful 风格的搜索和数据分析引擎.Elasticsearch 是面向文档的,这就意味着 ...

  6. WSDL知识点

    WSDL 是基于 XML 的用于描述 Web Services 以及如何访问 Web Services 的语言. WSDL简介 1.什么是 WSDL? WSDL 指网络服务描述语言 WSDL 使用 X ...

  7. Yum下载rpm包、不分析依赖关系强制安装

    在安装包后面加两个参数 --nodeps --force 如下: [root@sh158-xen data]#rpm -ivh MySQL-server-5.5.24-1.linux2.6.x86_6 ...

  8. MySQL批量修改相同后缀表名

    执行步骤 1.用concat批量生成修改表名的语句 SELECT CONCAT( 'ALTER TABLE ', table_name, ' RENAME TO ', ,locate('_postfi ...

  9. P4315 月下“毛景树”[树剖]

    题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬毛毛虫爬到了一颗小小的"毛景树&quo ...

  10. UVA1660 电视网络 Cable TV Network[拆点+最小割]

    题意翻译 题目大意: 给定一个n(n <= 50)个点的无向图,求它的点联通度.即最少删除多少个点,使得图不连通. 解析 网络瘤拆点最小割. 定理 最大流\(=\)最小割 感性地理解(口胡)一下 ...