Caffe框架初步理解

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

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

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

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

#include<vector>
#include<iostream>
#include<caffe/blob.hpp>
#include<caffe/util/io.hpp>

using namespace caffe;
using namespace std;
void print_blob(Blob<float> *a)
  {
          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;
                                  }
                          }
                  }
          }

  }

  int main(void)
  {
          Blob<float> a;
          BlobProto bp;
          cout<<"size:"<<a.shape_string()<<endl;
          a.Reshape(1,2,3,4);
          cout<<"after:"<<a.shape_string()<<endl;

          float *p=a.mutable_cpu_data();
          float *q=a.mutable_cpu_diff();
          for(int i = 0;i<a.count();i++){
                  p[i]=i;
                  q[i]=a.count() - 1 - i;
          }
          a.Update();//diff data combine
          print_blob(&a);
          cout<<"ASUM="<<a.asum_data()<<endl;
          cout<<"SUMSQ="<<a.sumsq_data()<<endl;
          a.ToProto(&bp,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<vector>
#include<iostream>
#include<caffe/net.hpp>

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:"<<netname<<endl;
        for(int i = 0;i<bn.size();i++)
        {   
                cout<<"Blob #"<<i<<" : "<<bn[i]<<endl;
        }   
        for(int i = 0;i<bn.size();i++)
        {   
                cout<<"Layers #"<<i<<" : "<<ln[i]<<endl;
        }   
#endif
    clean_log();
    return 0;
}

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

发布了199 篇原创文章 · 获赞 64 · 访问量 42万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览