Caffe中的Blob数据结构
Blob是caffe最基础的数据结构。它有4维[num_,channels_,height_,width_]
我们通过代码来看看
#include <vector>
#include <iostream>
#include <caffe/blob.hpp>
using namespace caffe;
using namespace std;
int main(void){
//声明一个Blob变量
Blob<float> a;
//打印形状,是0现在
cout<<"Size:"<<a.shape_string()<<endl;
//reshape成1,2,3,4
a.Reshape(1,2,3,4);
cout<<"Size:"<<a.shape_string()<<endl;
//创建Blob对象之后,可以通过mutable_cpu_data函数改变其值
float *p = a.mutable_cpu_data();
for (int i = 0; i < a.count(); ++i)
{
p[i]= i;
}
// int u = a.num();
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;
}
}
}
}
return 0;
}
Caffe使用Blob结构在CNN网络中存储、传递数据。对于批量2D图像数据,Blob的维度为
图像数量N × 通道数C × 图像高度H × 图像宽度W
显然,在此种场景下,Blob使用4维坐标定位数据,如(n, c, h, w),其中n为图像序号(0到N-1),c为通道序号(0到C-1),h为图像行序(0到H-1),w为图像列序(0到W-1)。那么我们如何根据这个坐标找到对应的数据呢?要想得到这个问题的答案,就得弄清楚Blob在内存中的数据组织形式,也就是这批量的2D图像在内存中是如何存储的。其实它的存储方式很简单,见下图:
图像数据依序存储,单张图像数据按通道序依次存储,组织形式简单明了。上图给了三张图像的存储例子,每张图像的通道数C为3,H为8,W为16。坐标(2, 1, 3, 9),代表这是第3张图像、第2个通道、第4行、第10列的像素值,实际存储位置为:
(((2 × C) + 1) × H + 3) × W + 9 = (((2 × 3) + 1) × 8 + 3) × 16 + 9 = 953
通俗地讲,在内存中,第一张图像的第0个像素值存储在内存的第0个位置,Blob按照从左到右,从上到下的顺序,逐列、逐行、逐通道、逐张图像,将每个像素值存入内存:
b. blob中数据的dimentions为Num N*channel K * Height H * Width W.内存是行优先的(row-major)。访问数据的时候按照如下的规则来访问index(n,k,h,w) 在物理上位于index((n*K + k) *H + h)*W + w. 这里要注意,index(n,k,h,w)实际上访问的是内存中(n+1,k+1,h+1,w+1)位置的数据,这是因为索引是从0开始的。
也就是说Blob的组织格式并无特别之处,顺序存储而已。坐标位置(n, c, h, w)与具体内存读取位置M的换算公式如下:
M = (((n × C) + c) × H + h) × W + w