caffe增加自己的layer實戰(上)--caffe學習(10)

github上如何增加自己的caffe layer:這裏寫鏈接內容
摘要如下:

Here's roughly the process I follow.
    Add a class declaration for your layer to the appropriate one of common_layers.hpp, data_layers.hpp, loss_layers.hpp, neuron_layers.hpp, or vision_layers.hpp. Include an inline implementation of type and the *Blobs() methods to specify blob number requirements. Omit the *_gpu declarations if you'll only be implementing CPU code.
    Implement your layer in layers/your_layer.cpp.
        SetUp for initialization: reading parameters, allocating buffers, etc.
        Forward_cpu for the function your layer computes
        Backward_cpu for its gradient
    (Optional) Implement the GPU versions Forward_gpu and Backward_gpu in layers/your_layer.cu.
    Add your layer to proto/caffe.proto, updating the next available ID. Also declare parameters, if needed, in this file.
    Make your layer createable by adding it to layer_factory.cpp.
    Write tests in test/test_your_layer.cpp. Use test/test_gradient_check_util.hpp to check that your Forward and Backward implementations are in numerical agreement.

Since this is a many step process, I thought it worth recording here. I would welcome improvements to Caffe that make the layer adding process less involved. BVLC folk All, if I've made an error or omitted something here, feel free to edit this post the wiki.

1:首先明確最新版caffe的目錄結構:
頭文件.hpp:/caffe/include/caffe
cpp文件:/caffe/src/caffe
2:首先明確自己需要增加的layer是屬於哪一種類別的layer:可參考:這裏寫鏈接內容
caffe在include裏分了四大類,vision\common\loss\data layer

———————-分割線————————-
下面以我們添加一個data layer爲例開始講解:
完善後的地址這裏寫鏈接內容(這是CVPR2016一篇論文中實現的,我是基於該版本做一個分析和學習,源代碼解釋權歸其所有)

1:目的:在caffe裏面增加一個一個datalayer,名字爲video_layer,就是允許caffe的輸入data層數據爲視頻,而不是侷限於imag
2:因爲它是屬於datalayer,而且我們的視頻和原來的image是最接近的,因爲視頻就是多幅圖片,所以找到/caffe/include/caffe/data_layers.hpp
或者目錄\caffe-master\include\caffe\layers\image_data_layers.hpp
可以看看裏面原來有什麼:

/**
 * @brief Provides data to the Net from image files.
 *
 * TODO(dox): thorough documentation for Forward and proto params.
 */
template <typename Dtype>
class ImageDataLayer : public BasePrefetchingDataLayer<Dtype> {
public:
    explicit ImageDataLayer(const LayerParameter& param)
    : BasePrefetchingDataLayer<Dtype>(param) {}
    virtual ~ImageDataLayer();
    virtual void DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
            const vector<Blob<Dtype>*>& top);

    virtual inline const char* type() const { return "ImageData"; }
    virtual inline int ExactNumBottomBlobs() const { return 0; }
    virtual inline int ExactNumTopBlobs() const { return 2; }

protected:
    shared_ptr<Caffe::RNG> prefetch_rng_;
    virtual void ShuffleImages();
    virtual void InternalThreadEntry();

#ifdef USE_MPI
    inline virtual void advance_cursor(){
        lines_id_++;
        if (lines_id_ >= lines_.size()) {
            // We have reached the end. Restart from the first.
            DLOG(INFO) << "Restarting data prefetching from start.";
            lines_id_ = 0;
            if (this->layer_param_.image_data_param().shuffle()) {
                ShuffleImages();
            }
        }
    }
#endif

    vector<std::pair<std::string, int> > lines_;
    int lines_id_;
};

可以看到原來的caffe中ImageDataLayer 是通過這句話繼承BasePrefetchingDataLayer類來的:

class ImageDataLayer : public BasePrefetchingDataLayer<Dtype> 

我們的video也是基於imag的,所以同樣依樣畫葫蘆繼承該類:

/**
 * Provides data to the Net from video files.
 */
template <typename Dtype>
class VideoDataLayer : public BasePrefetchingDataLayer<Dtype> {

視頻的初始化和image基本一致,首先將該類完全複製但是改名爲VideoDataLayer,如下:

template <typename Dtype>
class VideoDataLayer : public BasePrefetchingDataLayer<Dtype> {
public:
    explicit VideoDataLayer(const LayerParameter& param)
    : BasePrefetchingDataLayer<Dtype>(param) {}
    virtual ~VideoDataLayer();
    virtual void DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
            const vector<Blob<Dtype>*>& top);

    virtual inline const char* type() const { return "VideoData"; }
    virtual inline int ExactNumBottomBlobs() const { return 0; }
    virtual inline int ExactNumTopBlobs() const { return 2; }

protected:
    shared_ptr<Caffe::RNG> prefetch_rng_;
    shared_ptr<Caffe::RNG> prefetch_rng_2_;
    shared_ptr<Caffe::RNG> prefetch_rng_1_;
    shared_ptr<Caffe::RNG> frame_prefetch_rng_;
    virtual void ShuffleVideos();
    virtual void InternalThreadEntry();

#ifdef USE_MPI
    inline virtual void advance_cursor(){
        lines_id_++;
        if (lines_id_ >= lines_.size()) {
            // We have reached the end. Restart from the first.
            DLOG(INFO) << "Restarting data prefetching from start.";
            lines_id_ = 0;
            if (this->layer_param_.video_data_param().shuffle()) {
                ShuffleVideos();
            }
        }
    }
#endif

更新:
最好是在這裏新建一個hpp文件名:video_data_layer_.hpp
後面的video_data_layer_.cpp記得包含video_data_layer_.hpp文件。video_data_layer_.hpp文件內容:

#ifndef CAFFE_IMAGE_DATA_LAYER_HPP_
#define CAFFE_IMAGE_DATA_LAYER_HPP_

#include <string>
#include <utility>
#include <vector>

#include "caffe/blob.hpp"
#include "caffe/data_transformer.hpp"
#include "caffe/internal_thread.hpp"
#include "caffe/layer.hpp"
#include "caffe/layers/base_data_layer.hpp"
#include "caffe/proto/caffe.pb.h"

namespace caffe {

/**
 * @brief Provides data to the Net from video files.
 *
 * TODO(dox): thorough documentation for Forward and proto params.
 */
template <typename Dtype>
class VideoDataLayer : public BasePrefetchingDataLayer<Dtype> {
public:
  explicit VideoDataLayer(const LayerParameter& param)
  : BasePrefetchingDataLayer<Dtype>(param) {}
  virtual ~VideoDataLayer();
  virtual void DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

  virtual inline const char* type() const { return "VideoData"; }
  virtual inline int ExactNumBottomBlobs() const { return 0; }
  virtual inline int ExactNumTopBlobs() const { return 2; }

protected:
  shared_ptr<Caffe::RNG> prefetch_rng_;
  shared_ptr<Caffe::RNG> prefetch_rng_2_;
  shared_ptr<Caffe::RNG> prefetch_rng_1_;
  shared_ptr<Caffe::RNG> frame_prefetch_rng_;
  virtual void ShuffleVideos();
  virtual void InternalThreadEntry();

#ifdef USE_MPI
  inline virtual void advance_cursor(){
    lines_id_++;
    if (lines_id_ >= lines_.size()) {
      // We have reached the end. Restart from the first.
      DLOG(INFO) << "Restarting data prefetching from start.";
      lines_id_ = 0;
      if (this->layer_param_.video_data_param().shuffle()) {
        ShuffleVideos();
      }
    }
  }
#endif

  vector<std::pair<std::string, int> > lines_;
  vector<int> lines_duration_;
  int lines_id_;
  string name_pattern_;
};


}  // namespace caffe

#endif  // CAFFE_IMAGE_DATA_LAYER_HPP_

具體的操作在通過在cpp中實現:
virtual ~VideoDataLayer();
主要的不同除了名字以外還有:

protected:
    shared_ptr<Caffe::RNG> prefetch_rng_;
    shared_ptr<Caffe::RNG> prefetch_rng_2_;
    shared_ptr<Caffe::RNG> prefetch_rng_1_;
    shared_ptr<Caffe::RNG> frame_prefetch_rng_;

這裏我還沒太明白,看了半天github的討論這裏寫鏈接內容
歡迎各位探討,先放在這裏後面在弄清楚它。
接下篇:
caffe增加自己的layer實戰(中)–caffe學習(11)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章