先看读lob.hpp, 再读Blob.cpp。
若要调用caffe文件,可以使用g++命令,也可以使用cmake建立一个项目:
1 2 3 4 5
| . └── test_blob ├── build ├── CMakeLists.txt └── main.cpp
|
这个项目可以位于任何位置。接着编辑CMakeLists.tx,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| cmake_minimum_required(VERSION 3.5) project(test_blob) set(Caffe_INCLUDE_DIRS ~/caffe-master/include \ /usr/local/cuda/include ~/caffe-master/build/src)
set(Caffe_LIBRARIES caffe boost_system glog) set(CMAKE_CXX_STANDARD 11)
include_directories(${Caffe_INCLUDE_DIRS}) link_directories(~/caffe-master/build/lib) add_executable(test_blob main.cpp) target_link_libraries(test_blob ${Caffe_LIBRARIES}) install(TARGETS test_blob RUNTIME DESTINATION bin)
|
使用下面命令编译执行:
1 2 3 4 5
| $ rm -rf build/* $ cd build $ cmake .. $ make $ ./test_blob
|
在代码文件头部添加基本内容:
1 2 3 4 5 6
| #include <iostream> #include <vector> #include <caffe/blob.hpp>
using namespace caffe; using namespace std;
|
之后就可以在main函数中,进行探索测试了。
基本地,Blob在内存中是4为数组,维度从高到低为(num,channels,height,width)。并包含data(待学习参数)和diff(增量)。包含一些基本操作。
帮助函数
先在main.cpp外自定义了两个函数:向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
| void writeInto(caffe::Blob<float>& a){ float* ptr = a.mutable_cpu_data(); for(int i=0;i<a.count();i++){ ptr[i] = i; } }
void printBlob(const caffe::Blob<float>& blob){
cout<<"Size: "<<blob.shape_string()<<endl;
if (blob.shape_string() == "(0)") { cout<<"No data initialized"<<endl; return; } for(int u=0; u<blob.num(); u++){ for(int v=0; v<blob.channels(); v++){ for(int w=0; w<blob.height(); w++){ for(int x=0; x<blob.width(); x++){ cout<<"blob: "<<u<<v<<w<<x<<"->"<<blob.data_at(u,v,w,x)<<endl; } } } } cout<<"ASUM = "<<blob.asum_data()<<endl; cout<<"SUMQ = "<<blob.sumsq_data()<<endl; return; }
|
定义Blob
Blob.hpp中声明了构造函数,其用法见下例:
如果没有特殊指明,以下代码均在main.cpp中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| caffe::Blob<float> a;
caffe::Blob<float> b(1,2,3,4);
int shape_c[] = {1,3,2,4}; caffe::Blob<float> c(vector<int>(shape_c, shape_c+4));
writeInto(c);
c.Reshape(1,1,1,1); printBlob(c);
c.ReshapeLike(b); printBlob(c);
|
如果只打印最后一次数的c:
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
| Size: 1 2 3 4 (24) Position: 0000-> value: 0 Position: 0001-> value: 1 Position: 0002-> value: 2 Position: 0003-> value: 3 Position: 0010-> value: 4 Position: 0011-> value: 5 Position: 0012-> value: 6 Position: 0013-> value: 7 Position: 0020-> value: 8 Position: 0021-> value: 9 Position: 0022-> value: 10 Position: 0023-> value: 11 Position: 0100-> value: 12 Position: 0101-> value: 13 Position: 0102-> value: 14 Position: 0103-> value: 15 Position: 0110-> value: 16 Position: 0111-> value: 17 Position: 0112-> value: 18 Position: 0113-> value: 19 Position: 0120-> value: 20 Position: 0121-> value: 21 Position: 0122-> value: 22 Position: 0123-> value: 23 ASUM = 276 SUMQ = 4324
|
从上可以明显看出,(num,channels,height,width)最右端变化最快,逐渐向左。
更新参数data
更新参数由Blob的Update()
成员函数实现。具体是data=data-diff
。所以要测试Updata()
,首先就需要向data和diff分别读入数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| caffe::Blob<float> a; a.Reshape(1,2,3,4);
float* dataPtr = a.mutable_cpu_data(); float* diffPtr = a.mutable_cpu_diff();
for(int i=0;i<a.count();i++){ dataPtr[i] = i; diffPtr[i] = a.count()-1-i; }
a.Update();
printBlob(a);
|
更新后的data(待学习参数)。
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
| Size: 1 2 3 4 (24) Position: 0000-> value: -23 Position: 0001-> value: -21 Position: 0002-> value: -19 Position: 0003-> value: -17 Position: 0010-> value: -15 Position: 0011-> value: -13 Position: 0012-> value: -11 Position: 0013-> value: -9 Position: 0020-> value: -7 Position: 0021-> value: -5 Position: 0022-> value: -3 Position: 0023-> value: -1 Position: 0100-> value: 1 Position: 0101-> value: 3 Position: 0102-> value: 5 Position: 0103-> value: 7 Position: 0110-> value: 9 Position: 0111-> value: 11 Position: 0112-> value: 13 Position: 0113-> value: 15 Position: 0120-> value: 17 Position: 0121-> value: 19 Position: 0122-> value: 21 Position: 0123-> value: 23 ASUM = 288 SUMQ = 4600
|
由结果可看出,其实计算的是data=data-diff
,模型就是正向传播求diff,反向传播更新data。
保存Blob数据到磁盘,或从磁盘再如数据到Blob
从Blob写入protobuff:.ToProto()
;从protobuff写入Blob:.FromProto
。
需要添加头文件#include <caffe/util/io.hpp>
从而调用函数WriteProtoToBinaryFile()
和ReadProtoFromBinaryFileOrDie()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
caffe::BlobProto bp;
a.ToProto(&bp, true);
WriteProtoToBinaryFile(bp, "a.blob");
caffe::BlobProto bp2;
ReadProtoFromBinaryFileOrDie("a.blob", &bp2); caffe::Blob<float> b;
b.FromProto(bp2, true);
printBlob(b);
|
上述过程从读取Blob,写入磁盘,后从磁盘读取文件,写入里一个Blob。这对于加载,保存模型参数(权值)很实用。
接下来从caffe.proto文件,读关于Blob的描述。