添加caffe layers

caffe 的C++ 接口对于train 非常的方便,但是对于perdict 而言就不太友好,我们只能看到loss 。但是对于multilabel 问题,比如输出的perdict 和label 是一副图片的话,用c++ 就不太方便,所以我们要在caffe layers 中 添加一些自己的layer 来实现可视化。

在一开始添加的时候,会遇到各种各样的bug,这个mark 下以备不时之需。

比如说,我要添加一个visual layer,把perdict 的图片输出出来。
在caffe/include/caffe/layers/ 下添加visual_layer.hpp
在 caffe/src/caffe/layers/ 下添加visual_layer.cpp
修改 caffe/src/proto 的caffe.proto 下修改相应的属性。

message LayerParameter {
...
optional VisualParameter visual_param = 1000; 这里添加的是caffe 的type,数字在message 上有题型下一个可用的数字是多少,这个因人而异
}

....
添加多一个message
message VisualParameter {
  optional string save_folder = 1;
  optional uint32 save_interval = 2 [default = 2];
  optional float scale = 3 [default = 1];
}

visual_layer.hpp

#ifndef CAFFE_VISUAL_LAYER_HPP_
#define CAFFE_VISUAL_LAYER_HPP_

#include <stdio.h>
#include <vector>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc.hpp>

#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"

#include "caffe/layers/loss_layer.hpp"

namespace caffe {


template <typename Dtype>
class VisualLayer : public Layer<Dtype> {
 public:

  explicit VisualLayer(const LayerParameter& param)
      : Layer<Dtype>(param) {}
  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
      //vector<int> top_shape(0); 
      //top[0]->Reshape(top_shape);
  };

  virtual inline const char* type() const { return "Visual"; }
  virtual inline int ExactNumBottomBlobs() const { return 3; }

  virtual inline int MinTopBlobs() const { return 0; }
  virtual inline int MaxTopBlos() const { return 0; }

 protected:

  virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

  /// @brief Not implemented -- VisualLayer 不需要回传梯度.
  virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
    for (int i = 0; i < propagate_down.size(); ++i) {
      if (propagate_down[i]) { NOT_IMPLEMENTED; }
    }
  }

 private:
  cv::Mat BlobToColorImage(const Blob<Dtype>* blob, const int n, const int height, const int width, const Dtype img_scale);
  cv::Mat BlobToGreyImage(const Blob<Dtype>* blob, const int n, const int height, const int width, const Dtype img_scale);
  void BlobToFourChannelImage(const Blob<Dtype>* blob, const int n, const int height, const int width, const Dtype img_scale);

  int iteration_num;
  int save_interval;
  string save_path;
  float scale;
};

}  // namespace caffe

#endif  // CAFFE_VISUAL_LAYER_HPP_

visual_layer.cpp

#include <functional>
#include <utility>
#include <vector>

#include "caffe/layers/visual_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void VisualLayer<Dtype>::LayerSetUp(
  const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {

  iteration_num = 0;
  save_interval = this->layer_param_.visual_param().save_interval();
  save_path = this->layer_param_.visual_param().save_folder();
  scale = this->layer_param_.visual_param().scale();

  CHECK_GT(save_interval, 0);
}



template <typename Dtype>
void VisualLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  ++iteration_num;
  if(iteration_num % save_interval != 0)
    return;

  char name_buffer[100];
  cv::Mat rgb_img;
  cv::Mat label_img;
  cv::Mat prediction_img;
  vector<cv::Mat> data_img;
  for(int img_id = 0; img_id < bottom[0]->num(); ++img_id) {
    //BlobToFourChannelImage(bottom[0], img_id, bottom[0]->height(), bottom[0]->width(), scale);
    label_img      = BlobToGreyImage(bottom[1], img_id, bottom[1]->height(), bottom[1]->width(), scale);
    prediction_img = BlobToGreyImage(bottom[2], img_id, bottom[2]->height(), bottom[2]->width(), scale);
    //LOG(INFO) << "pred_rows: " << prediction_img.rows;
    //LOG(INFO) << "pred_cols: " << prediction_img.cols;
   //channel LOG(INFO) << "pred_chan: " << prediction_img.channels;
    //label_img = BlobToGreyImage(bottom[1], img_id, scale);
    //prediction_img = BlobToGreyImage(bottom[2], img_id, scale);


    sprintf(name_buffer, "%d_%d_label.jpg", iteration_num, img_id);
    cv::imwrite(save_path + string(name_buffer), label_img);

    sprintf(name_buffer, "%d_%d_prediction.jpg", iteration_num, img_id);
    cv::imwrite(save_path + string(name_buffer), prediction_img);
  }
}

template <typename Dtype>
void VisualLayer<Dtype>::BlobToFourChannelImage(const Blob<Dtype>* blob, const int n,
  const int height, const int width, const Dtype img_scale) {
  CHECK_GE(blob->channels(), 4) << "Only Support FourChannel Images";
  const Dtype* cpu_data = blob->cpu_data();
  int offset = n * blob->channels() * height * width;

  cv::Mat img1(height, width, CV_8UC3);
  cv::Mat img2(height, width, CV_8UC1);
  for (int c = 0; c < 4; ++c) {
    for (int h = 0; h < img1.rows; ++h) {
      for (int w = 0; w < img1.cols; ++w) {
        Dtype value = cpu_data[offset];
        //if(value < 0) value = 0;
        //if(value > 255) value = 255;
        if (c < 3) {
          img1.at<cv::Vec3b>(h, w)[c] = (int)cv::saturate_cast<uchar>(value);
          //LOG(INFO) << "cv::saturate_cast: " << (int)cv::saturate_cast<uchar>(value);
        }
        else img2.at<uchar>(h,w) = cv::saturate_cast<uchar>(value);

        ++offset;
      }
    }
  }
  //cv::imshow("color data", img1);
  //cv::waitKey(10000);
  //cv::imshow("gray data", img2);
  //cv::waitKey(10000);
}



template <typename Dtype>
cv::Mat VisualLayer<Dtype>::BlobToColorImage(const Blob<Dtype>* blob, const int n, 
  const int height, const int width, const Dtype img_scale) {
  CHECK_GE(blob->channels(), 3) << "Only Support Color images";

  const Dtype* cpu_data = blob->cpu_data();
  int offset = n * blob->channels() * height * width;

  cv::Mat img(height, width, CV_8UC3);
  for (int c = 0; c < 3; ++c) {
    for (int h = 0; h < img.rows; ++h) {
      for (int w = 0; w < img.cols; ++w) {
        Dtype value = cpu_data[offset] * img_scale;
        if(value < 0) value = 0;
        if(value > 255) value = 255;

        img.at<cv::Vec3b>(h, w)[c] = cv::saturate_cast<uchar>(value);

        ++offset;
      }
    }
  }

  return img;
}

template <typename Dtype>
cv::Mat VisualLayer<Dtype>::BlobToGreyImage(const Blob<Dtype>* blob, const int n, 
  const int height, const int width, const Dtype img_scale) {
  CHECK_GE(blob->channels(), 1) << "Only Support grey images";

 const Dtype* cpu_data = blob->cpu_data();
 int offset = n * height * width;

  cv::Mat img(height, width, CV_8UC1);
  for (int h = 0; h < img.rows; ++h) {
    for (int w = 0; w < img.cols; ++w) {
      //Dtype value = blob->data_at(n, 0, h, w) * img_scale;
      Dtype value = cpu_data[offset] * img_scale;
      if(value < 0) value = 0;
      if(value > 255) value = 255;

      img.at<uchar>(h, w) = cv::saturate_cast<uchar>(value);
      ++offset;
    }
  }
  /*cv::resize(img, img, cv::Size(128,128));
  cv::namedWindow( "Gray image", CV_WINDOW_NORMAL);
  cv::imshow("Gray image", img);
  cv::waitKey(1);*/
  //cv::destroyWindow("Gray image");
  return img;
}

INSTANTIATE_CLASS(VisualLayer);
REGISTER_LAYER_CLASS(Visual);

}  // namespace caffe

再写好之后,回到caffe 根目录,
make
要是编译通过了就说明添加成功了。然后就可以在train.prototxt 添加这个新的layer了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值