新版的caffe更新之后,增加一个只要在在include/caffe/layers中添加相应的头文件,
在src/layers中添加相应cpp, cu文件。
举例:本次主要给caffe添加normalize_layer层,源码来自caffe_windows中。
(1) 在caffe/layers中新建normalize_layer.hpp
#ifndef CAFFE_NORMALIZE_LAYER_HPP_
#define CAFFE_NORMALIZE_LAYER_HPP_
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/blob.hpp"
namespace caffe{
template<typename Dtype>
class NormalizeLayer : public Layer<Dtype>
{
public:
explicit NormalizeLayer(const LayerParameter ¶m):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);
virtual inline const char* type() const{return "Normalize";}
virtual inline int ExactNumBottomBlobs() const{return 1;}
virtual inline int ExactNumTopBlobs()const{return 1;}
protected:
virtual void Forward_cpu(const vector<Blob<Dtype>*> &bottom,
const vector<Blob<Dtype>*>& top);
virtual void Forward_gpu(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);
virtual void Backward_gpu(const vector<Blob<Dtype>*> &top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*> &bottom);
Blob<Dtype> sum_multiplier_, norm_, squared_;
std::string normalize_type_;
bool rescale_;
};
}
#endif
(2) 在src/caffe/layers中新建normalize_layer.cpp,内容如下:
#include <algorithm>
#include <vector>
#include <cmath>
#include "caffe/layer.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/layers/normalize_layer.hpp"
namespace caffe {
template <typename Dtype>
void NormalizeLayer<Dtype>::LayerSetUp(
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
normalize_type_ =
this->layer_param_.normalize_param().normalize_type();
rescale_ =
this->layer_param_.normalize_param().rescale();
}
template <typename Dtype>
void NormalizeLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
top[0]->Reshape(bottom[0]->num(), bottom[0]->channels(),
bottom[0]->height(), bottom[0]->width());
squared_.Reshape(bottom[0]->num(), bottom[0]->channels(),
bottom[0]->height(), bottom[0]->width());
norm_.Reshape(bottom[0]->num(), 1,
bottom[0]->height(), bottom[0]->width());
}
template <typename Dtype>
void NormalizeLayer<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();
Dtype* square_data = squared_.mutable_cpu_data();
Dtype* norm_data = norm_.mutable_cpu_data();
int num = bottom[0]->num();
int channels = bottom[0]->channels();
int spatial_dim = bottom[0]->height() * bottom[0]->width();
if (normalize_type_ == "L2") {
caffe_sqr<Dtype>(num*channels*spatial_dim, bottom_data, square_data);
for (int n = 0; n < num; n++) {
for (int s = 0; s < spatial_dim; s++) {
norm_data[n*spatial_dim + s] = Dtype(0);
for (int c = 0; c < channels; c++) {
norm_data[n*spatial_dim + s] += square_data[(n * channels + c) * spatial_dim + s];
}
norm_data[n*spatial_dim + s] += 1e-6;
norm_data[n*spatial_dim + s] = Dtype(1) / sqrt(norm_data[n*spatial_dim + s]);
for (int c = 0; c < channels; c++) {
top_data[(n * channels + c) * spatial_dim + s] = bottom_data[(n * channels + c) * spatial_dim + s] * norm_data[n*spatial_dim + s];
}
}
}
}
else if (normalize_type_ == "L1") {
caffe_abs<Dtype>(num*channels*spatial_dim, bottom_data, square_data);
for (int n = 0; n < num; n++) {
for (int s = 0; s < spatial_dim; s++) {
norm_data[n*spatial_dim +s] = Dtype(0);
for (int c = 0; c < channels; c++) {
norm_data[n*spatial_dim + s] += square_data[(n * channels + c) * spatial_dim + s];
}
norm_data[n*spatial_dim + s] += 1e-6;
norm_data[n*spatial_dim + s] = Dtype(1) / norm_data[n*spatial_dim + s];
for (int c = 0; c < channels; c++) {
top_data[(n * channels + c) * spatial_dim + s] = bottom_data[(n * channels + c) * spatial_dim + s] * norm_data[n*spatial_dim + s];
}
}
}
}
else {
NOT_IMPLEMENTED;
}
}
template <typename Dtype>
void NormalizeLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
const Dtype* top_data = top[0]->cpu_data();
const Dtype* bottom_data = bottom[0]->cpu_data();
const Dtype* square_data = squared_.cpu_data();
const Dtype* norm_data = norm_.mutable_cpu_data();
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
int num = bottom[0]->num();
int channels = bottom[0]->channels();
int spatial_dim = bottom[0]->height() * bottom[0]->width();
if (normalize_type_ == "L2") {
for (int n = 0; n < num; ++n) {
for (int s = 0; s < spatial_dim; s++) {
Dtype a = caffe_cpu_strided_dot(channels, top_data + n*channels*spatial_dim + s, spatial_dim, top_diff + n*channels*spatial_dim + s, spatial_dim);
for (int c = 0; c < channels; c++) {
bottom_diff[(n * channels + c) * spatial_dim + s] =
(top_diff[(n * channels + c) * spatial_dim + s] - top_data[(n * channels + c) * spatial_dim + s] * a) * norm_data[n*spatial_dim + s];
}
}
}
}
else if(normalize_type_ == "L1") {
for (int n = 0; n < num; ++n) {
for (int s = 0; s < spatial_dim; s++) {
Dtype a = caffe_cpu_strided_dot(channels, top_data + n*channels*spatial_dim + s, spatial_dim, top_diff + n*channels*spatial_dim + s, spatial_dim);
for (int c = 0; c < channels; c++) {
bottom_diff[(n * channels + c) * spatial_dim + s] =
(top_diff[(n * channels + c) * spatial_dim + s] - square_data[(n * channels + c) * spatial_dim + s] * a) * norm_data[n*spatial_dim + s];
}
}
}
}
else {
NOT_IMPLEMENTED;
}
}
#ifdef CPU_ONLY
STUB_GPU(NormalizeLayer);
#endif
INSTANTIATE_CLASS(NormalizeLayer);
REGISTER_LAYER_CLASS(Normalize);
} // namespace caffe
(3) 同理如果有.cu文件的实现,则完成cu文件编写。
(4)修改src\caffe\proto\caffe.proto
首先我们看到LayerParameter中提示我们可以使用ID,于是可以添加下面147。
// NOTE
// Update the next available ID when you add a new LayerParameter field.
//
// LayerParameter next available layer-specific ID: 147 (last added: recurrent_param)
添加的ID,这里的normalize_para就是以后在训练文件中的参数名。
如:
pooling_param{
pool: AVE
global_pooling: true
}
optional PoolingParameter pooling_param = 121;
optional NormalizeParameter normalize_param = 147;
我们看到normalize_layer这个层有两个参数
normalize_type_ =
this->layer_param_.normalize_param().normalize_type();
rescale_ =
this->layer_param_.normalize_param().rescale();
于是我们需要添加下面的参数信息:
// add normalization param
message NormalizeParameter {
optional string normalize_type = 1 [default = "L2"];
optional bool rescale = 2 [default = false];
}
然后重先编译就可以使用。