本文自定义一个使图片颜色反转的网络层,主要帮助我们理解Layer的添加方式,以及caffe的工作方式。
在src/caffe/proto/caffe.proto中加入message:
*// Message that stores parameters used by ReverseLayer
message ReverseParameter {
optional bool visualize = 3 [default = false];
}*
讲该层的参数ID放入layerParameter 中:
// LayerParameter next available layer-specific ID: 147 (last added: recurrent_param)
下一层的有效ID号为147,最后一次添加的参数ID为 recurrent_param。
所以需要添加:
optional ReverseParameter reverse_param = 147;
同时修改注释为:
LayerParameter next available layer-specific ID: 148 (last added: ReverseParameter)
实现层头文件:
这里可以继承NeuronLayer或者Layer, 选择不同的基类的时候,要重写的虚函数不一样。
#ifndef CAFFE_IMAGE_REVERSE_LAYER_HPP_
#define CAFFE_IMAGE_REVERSE_LAYER_HPP_
#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/layers/neuron_layer.hpp"
namespace caffe {
/*
* @brief Reshapes the input Blob into an arbitrary-sized output Blob.
*
* Note: similarly to FlattenLayer, this layer does not change the input values
* (see FlattenLayer, Blob::ShareData and Blob::ShareDiff).
*/
template <typename Dtype>
class ReverseLayer : public NeuronLayer<Dtype> {
public:
explicit ReverseLayer(const LayerParameter& param)
: NeuronLayer<Dtype>(param) {}
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual inline const char* type() const { return "Reverse"; }
protected:
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {};
int num_images;
int height_;
int width_;
int num_channels_;
bool visualize_;
};
} // namespace caffe
#endif
实现C文件
#include <vector>
#include "caffe/layers/reverse_layer.hpp"
#include <opencv2/opencv.hpp>
#include <iostream>
namespace caffe {
template <typename Dtype>
void ReverseLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
// get parameters
const ReverseParameter& param = this->layer_param_.reverse_param();
// get the output size
visualize_ = param.visualize();
// get input size
num_images = bottom[0]->num();
height_ = bottom[0]->height();
width_ = bottom[0]->width();
num_channels_ = bottom[0]->channels();
std::cout << num_images <<height_ << width_ << num_channels_ ;
}
template <typename Dtype>
void ReverseLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
const Dtype* bottom_data = bottom[0]->cpu_data();
Dtype* top_data = top[0]->mutable_cpu_data();
const int image_size = height_ * width_;
const int storage_size = image_size * num_channels_;
cv::Mat dstimage;
int image_idx = 0;
for( int idx_img =0;idx_img < num_images; idx_img ++){
dstimage = cv::Mat::zeros(height_, width_, CV_32FC1);
for(int idx_ch =0; idx_ch < num_channels_; idx_ch ++){
for(int i =0; i<height_; i++){
for(int j=0; j<width_; j++){
top_data[image_idx] = 255 - (float)bottom_data[image_idx] ;
dstimage.at<float>(i,j) = (float)top_data[image_idx];
std::cout << dstimage.at<float>(i,j);
image_idx ++;// = idx_img * storage_size + image_size * idx_ch + height_ * i + j;
}
}
}
}
if(visualize_){
cv::namedWindow("dst image", CV_WINDOW_AUTOSIZE);
cv::imshow("dst image", dstimage);
cv::waitKey(0);
}
}
INSTANTIATE_CLASS(ReverseLayer);
REGISTER_LAYER_CLASS(Reverse);
} // namespace caffe
再次编译
make clean
make all
在deploy.prototxt文件中添加该层
layer {
name:"data"
type: "Input"
top: "data"
input_param { shape: { dim: 1 dim: 3 dim: 28 dim: 28 } }
}
layer {
name: "reversed"
type: "Reverse"
bottom: "data"
top: "reversed"
reverse_param{
visualize:true
}
}
layer {
name:"conv1"
type: "Convolution"
bottom: "reversed"
top: "conv1"
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
}
}
.......省略
执行测试函数
./build/examples/cpp_classification/classification.bin examples/Reverse/deploy.prototxt examples/mnist/lenet_iter_10000.caffemodel examples/mnist/mean.binaryproto /home/akuarius/data/mnist/test/labels.txt examples/mnist/5.png