Caffe数据结构
一、基本概念
二、Blob:Caffe的基本存储单元
blob:
- 四维数组,维度从低到高(width_,height_,channels_,num_);
- 用于存储和交换数据;存储数据或者权值(data)和权值增量(diff);
- 提供统一的存储器接口,持有一批图像或其他数据、权值、权值更新值;
- 进行网络计算时,每层的输入、输出都需要通过Blob对象缓冲。
(1)基本用法
可自动同步CPU/GPU上的数据;
#include <vector>
#include <iostream>
//将Blob内部值保存到磁盘,或者从磁盘载入内存,可以分别通过ToProto()、FromProto()实现
#include <caffe/util/io.hpp> //存需要包含这个文件
#include <caffe/blob.hpp> #包含头文件
using namespace caffe; #命名空间
using namespace std;
int main(void)
{
Blob<float> a; #创建Blob对象a
cout<<"Size :"<<a.shape_string()<<endl; #打印维度信息 Size :(0)
a.Reshape(1,2,3,4);
cout<<"Size :"<<a.shape_string()<<endl; #打印维度信息 Size:1 2 3 4 (24)
float *p = a.mutable_cpu_data(); #修改内部数值 mutable_cpu[gpu]_data[diff]
float *q = a.mutable_cpu_diff(); #修改内部数值 mutable_cpu[gpu]_data[diff]
for(int i = 0; i < a.count(); i ++)
{
p[i] = i; #将data初始化为1,2,3...
q[i] =a.count()-1-i ; #将diff初始化为23,22,21...
}
a.update(); #执行Update操作,将diff与data融合(这也是CNN权值更新步骤的追踪实施者) # Update()实现 data=data-diff
BlobProto bp; #构造一个BlobProto对象
a.ToProto(&bp,true); #将a序列化,连通diff(默认不带)
WriteProtoToBinaryFile(bp,"a.blob"); #写入磁盘文件a.blob"
ReadProtoFromBinaryFileOrDie("a.blob",&bp2)
Blob<float> b; #新建一个Blob对象b
b.FromProto(bp2,true); #从序列化对象bp2总克隆b(连通形状)
for(int u = 0; u < a.num(); u ++)
{
for(int v = 0; v < a.channels(); v ++)
{
for(int w = 0; w < a.height(); w ++)
{
for(int x = 0; x < a.width(); x ++)
{
cout<<"a["<<u<<"]["<< v << "][" << w << "][" << x << "] =" << a.data_at(u,v,w,x)<< endl;
#下标访问 a[][][][]=-23、-21......21、23
}
}
}
}
cout<<"ASUM = " << a.asum_data()<< endl; #所有元素绝对值之和(L1-范数) ASUM = 288 cout<<"SUMSQ = " << a.sumsq_data()<< endl; # 平方和 (L2-范数)SUMSQ = 4600
return 0;
}
Blobproto对象实现了磁盘、内存之间的数据通信,这对于保存、载入训练好的模型非常实用。
(2)数据结构描述
不用BlobShape和BlobProto二实用ProtoBuffer的原因:
1>、结构体的序列化/反序列化操作需要额外的编程思想,难以做到接口标准化;
2>、结构体中包含变长数据时,需要更加细致的工作保证数据完整性。ProtoBuffer将变成最容易出现问题的地方加以隐藏,让机器自动处理,提高了出的健壮性。
| |
该结构描述了Blob的形状信息 | message BlobShape |
只包括若干int64类型值,分别表示Blob 每个维度的大小,packed表示这些值在内存 中紧密排布,没有空洞 | repeated int64 dim = 1 [packed = true]; |
| } |
| |
该结构描述Blob在磁盘中序列化后的形态 | message BlobProto |
可选,包括一个BlobShape对象 | optional BlobShape shape = 7; |
包括若干护垫元素, 用于存储增量信息,元素数目由shape或 (num,channels,height,width)确定 ,这些元素在内存总紧密排布 | repeated float data = 5 [packed = true]; |
包括若干护垫元素, 用于存储增量信息,维度与data粗细一致 | repeated float diff = 6 [packed = true]; |
与data并列,知识类型为double | repeated double double_data = 8 [packed = true]; |
与diff并列,只是内心为double | repeated double double_diff = 9 [packed = true]; |
| |
可选的维度信息,新版本caffe 推荐使用shape,而不再后面的值 | // 4D dimensions -- deprecated. Use "shape" instead. |
| optional int32 num = 1 [default = 0]; |
| optional int32 channels = 2 [default = 0]; |
| optional int32 height = 3 [default = 0]; |
| optional int32 width = 4 [default = 0]; |
| } |
(3)Blob炼成法
Blob是一个模板类,声明在include/caffe/blob.hpp中,封装类SyncedMemory类,作为基本计算单元服务Layer、Net、Solver等。
注意:caffe类中成员变量名都带有后缀“_”,这样再返俗世相中容易区分临时变量和类变量。
三、Layer:Caffe的基本计算单元
Layer至少有一个输入Blob(Bottom Blob)和一个输出Blob(Top Blob),部分Layer带有权值和偏置项;
两个运算方法:
前向传播:对输入Blob进行某种处理(有权值和骗至西安的Layer会利用这些对输入进行处理),得到输出Blob
反向传播:对输出Blob的diff进行某种处理,得到输入Blob的diff(有权值和偏置项的Layer可能也会计算Blob、偏置项Blob的 diff)
(1)数据结构描述
(2)Layer炼成法
- Layer头文件位于include/caffe/layer.hpp中;
- Layer源文件位于src/caffe/layer.cpp中(大部分函数并没有实现 ,只有虚函数);
- Layer的相关函数的实现在派生类,具体代码在src/caffe/layers/*.cpp ;Layer类是一个虚基类,不能直接创建对象。
四、Net:Caffe中网站的CNN模型,包含若干Layer实例
(1)基本用法
- 描述文件 *.prototxt (models/bvlc_reference_caffenet/deploy.prototxt );
- Net中既包括Layer对象,又包括Blob对象。Blob对象用于存放每个Layer输入/输出中间结果,Layer根据Net描述对指定的输入Blob进行某些处理(卷积、下采样、全连接、非线性变换、计算代价函数等),输出结果放到指定的输出Blob中。输入Blob与输出Blob可能为同一个。
- 所有的Layer和Blob对象都用名字区分,同名的Blob表示同一个Blob对象。同名的Layer表示同一个Layer对象,Blob和Layer同名不代表他们有任何直接关系。
(2)数据结构描述
(3)Net绘成法
下面有两类Blob:
1>、以param开头的权值Blob:随着Blob会随着学习过程而更新,归属于“模型”;
2>、以blob开头的Layer输入/输出Blob:只会随网络输入变化,归属于“数据”;
深度学习的目的就是不断从“数据”中获取知识,存储到“模型”中,应用于后来的“数据”。
五、机制和策略:能干什么?怎么干?
- Blob提供数据容器的机制;
- Layer通过不同的策略使用该数据容器,实现多元化的计算处理过程,同时又提供了深度学习各种基本算法(卷积、下采样、损失函数计算等)的机制;
- Net则利用Layer这些机制,组合为更完整的深度学习模型,提供了更加丰富的学习策略。