Caffe框架初步理解

当前最火无非就是深度学习了。搞了大半年的机器人相关视觉东西,用的最多的也是Caffe。看网上有形形色色的Deeplearning的net,但是他们背后到底是什么样子的?

这么说吧!这里我们把Caffe比作一个汽车。

汽车怎么组成的?各种零件先组装成轮胎、发动机、车座、车外部框。。。然后这些组成的部件组成一个完成的车。那么有的人要问了这和深度学习框架Caffe有个毛的联系啊???!!!(ps:黑人问号脸)

caffe的零件是啥呢?Caffe的零件叫做一个叫Blob的东西,它是caffe所有数据的表示形式。可以看作是一个四维的数组,这四维怎么理解呢?可以类比图像视频流,由width、height、channelnum、framenumber。具体的意思就是图像的长、宽、像素通道数、第几帧。可以看看下面代码对于Blob的理解:

#include
#include
#include
#include

using namespace caffe;
using namespace std;
void print_blob(Blob<float> *a)
  {
          for(int u = 0;unum();u++)
          {
                  for(int v = 0;vchannels();v++)
                  {
                          for(int w=0;wheight();w++)
                          {
                                  for(int x = 0;xwidth();x++)
                                  {
                                          cout<<"a["<"]["<"]["<"]["<"]="<data_at(u,v,w,x)<int main(void)
  {
          Blob<float> a;
          BlobProto bp;
          cout<<"size:"<1,2,3,4);
          cout<<"after:"<float *p=a.mutable_cpu_data();
          float *q=a.mutable_cpu_diff();
          for(int i = 0;i1 - i;
          }
          a.Update();//diff data combine
          print_blob(&a);
          cout<<"ASUM="<cout<<"SUMSQ="<true);
          WriteProtoToBinaryFile(bp,"a.blob");
          BlobProto bp2;
          ReadProtoFromBinaryFileOrDie("a.blob",&bp2);
          Blob<float> b;
          b.FromProto(bp2,true);
          print_blob(&b);
          return 0;
  }

上述代码实现了caffe的基本数据结构的创建以及存储到本地文件并读取。

caffe的基本零件结束了。下面看部件。部件主要是在caffe中一个叫做Layer的东西。主要由Blob组成。

下面看一个Mobilenet中一个层,这里需要注意的是Caffe中都是使用google的protobuffer的形式实现:

layer {
  name: "conv1"  //层的名字
  type: "Convolution"//本层类型,卷积层
  bottom: "data"//输入类型定义
  top: "conv1"//输出类型定义
  param {
    lr_mult: 1//滤波的学习率
    decay_mult: 1//滤波的衰减率
  }
  convolution_param {//卷积参数
    num_output: 32 //滤波数目,卷积后的图像的通道数  
    bias_term: false //是否使用bias
    pad: 1 //边界处补1个行和1个列
    kernel_size: 3 //卷积核大小,3*3
    stride: 2  //卷积步长
    weight_filler {
      type: "msra" //滤波类型
    }    
  }
}

通过上面文件定义的参数,定义caffe本层的作用,输入输出,以及本层使用到的参数。然后再调用caffe的接口函数即可完成本层的构建,对于其他定义的层也可以同理实现。
有时候对于源代码有些层的实现不满意,众口难调嘛~哈哈~这时候就需要自己自定义层,并且编写相关层的实现,可以参考源代码对于一些层怎么写,里面用到的有些算法可以自己进行替换。
可以参考这位仁兄实现一个类似于全通滤波器的过程的caffe层代码
总结一下,一般就是要经过这么几步:
1、参考目录caffe/include/caffe/layers下,定义相关函数。比如链接的仁兄的可以定义为allpass_layer.hpp
2、参考caffe/src/caffe/layers目录下相关层实现的函数。这里可以看到,有定义前向传播与反向传播相关函数。
3、编辑caffe/src/caffe/proto/caffe.proto,找到LayerParameter,在最后增加一项,里面的编号不要与别的冲突,如果Layer有参数,还需要再定义一个关于自定义层的protobuffer。
4、然后在src/caffe/layer_factory.cpp中添加响应代码。
5、src/caffe/test中写一个test_allpass_layer.cpp,用include/caffe/test/test_gradient_check_util.hpp来检查前向后向传播是否正确。
一共上面的几步,就可以实现自己的一个layer。

到现在为止,已经完成了caffe的零件和部件的工作,下面就是整体组装,把弄好的Layer组成一个Net,是一个完整的CNN,各种layer的设计都会在一个*.prototxt的文件里,查看其内容其实都是google的protobuffer形式定义。

查看网络结构与各层类型的代码如下:

#include
#include
#include

using namespace std;
using namespace caffe;

void shutdown_log(){
        google::InitGoogleLogging("Net");
        FLAGS_stderrthreshold = google::ERROR;
}
void clean_log()
{
        google::ShutdownGoogleLogging();            
}
int main(int argc,char** argv)
{
   shutdown_log();
        string proto("deploy.prototxt");
#if 1
        Net<float> Net_test(proto,caffe::TEST);
        vector<string> bn=Net_test.blob_names();
        vector<string> ln=Net_test.layer_names();
        string netname=Net_test.name();
        cout << "network_name:"<for(int i = 0;icout<<"Blob #"<" : "<for(int i = 0;icout<<"Layers #"<" : "<#endif
    clean_log();
    return 0;
}

至此大致对caffe的整体框架做了一个梳理。后续再继续添加~

你可能感兴趣的:(深度学习相关)