#include #include #include "caffe/filler.hpp" #include "caffe/layer.hpp" #include "caffe/vision_layers.hpp" namespace caffe { template void PReLULayer::LayerSetUp(const vector*>& bottom, const vector*>& top) { CHECK_GE(bottom[0]->num_axes(), 2) << "Number of axes of bottom blob must be >=2."; PReLUParameter prelu_param = this->layer_param().prelu_param(); int channels = bottom[0]->channels(); channel_shared_ = prelu_param.channel_shared(); if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { this->blobs_.resize(1); if (channel_shared_) { this->blobs_[0].reset(new Blob(vector(0))); } else { this->blobs_[0].reset(new Blob(vector(1, channels))); } shared_ptr > filler; if (prelu_param.has_filler()) { filler.reset(GetFiller(prelu_param.filler())); } else { FillerParameter filler_param; filler_param.set_type("constant"); filler_param.set_value(0.25); filler.reset(GetFiller(filler_param)); } filler->Fill(this->blobs_[0].get()); } if (channel_shared_) { CHECK_EQ(this->blobs_[0]->count(), 1) << "Negative slope size is inconsistent with prototxt config"; } else { CHECK_EQ(this->blobs_[0]->count(), channels) << "Negative slope size is inconsistent with prototxt config"; } // Propagate gradients to the parameters (as directed by backward pass). this->param_propagate_down_.resize(this->blobs_.size(), true); multiplier_.Reshape(vector(1, bottom[0]->count(1))); backward_buff_.Reshape(vector(1, bottom[0]->count(1))); caffe_set(multiplier_.count(), Dtype(1), multiplier_.mutable_cpu_data()); } template void PReLULayer::Reshape(const vector*>& bottom, const vector*>& top) { CHECK_GE(bottom[0]->num_axes(), 2) << "Number of axes of bottom blob must be >=2."; top[0]->ReshapeLike(*bottom[0]); if (bottom[0] == top[0]) { // For in-place computation bottom_memory_.ReshapeLike(*bottom[0]); } } template void PReLULayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); Dtype* top_data = top[0]->mutable_cpu_data(); const int count = bottom[0]->count(); const int dim = bottom[0]->count(2); const int channels = bottom[0]->channels(); const Dtype* slope_data = this->blobs_[0]->cpu_data(); // For in-place computation if (bottom[0] == top[0]) { caffe_copy(count, bottom_data, bottom_memory_.mutable_cpu_data()); } // if channel_shared, channel index in the following computation becomes // always zero. const int div_factor = channel_shared_ ? channels : 1; for (int i = 0; i < count; ++i) { int c = (i / dim) % channels / div_factor; top_data[i] = std::max(bottom_data[i], Dtype(0)) + slope_data[c] * std::min(bottom_data[i], Dtype(0)); } } template void PReLULayer::Backward_cpu(const vector*>& top, const vector& propagate_down, const vector*>& bottom) { const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* slope_data = this->blobs_[0]->cpu_data(); const Dtype* top_diff = top[0]->cpu_diff(); const int count = bottom[0]->count(); const int dim = bottom[0]->count(2); const int channels = bottom[0]->channels(); // For in-place computation if (top[0] == bottom[0]) { bottom_data = bottom_memory_.cpu_data(); } // if channel_shared, channel index in the following computation becomes // always zero. const int div_factor = channel_shared_ ? channels : 1; // Propagte to param // Since to write bottom diff will affect top diff if top and bottom blobs // are identical (in-place computaion), we first compute param backward to // keep top_diff unchanged. if (this->param_propagate_down_[0]) { Dtype* slope_diff = this->blobs_[0]->mutable_cpu_diff(); for (int i = 0; i < count; ++i) { int c = (i / dim) % channels / div_factor; slope_diff[c] += top_diff[i] * bottom_data[i] * (bottom_data[i] <= 0); } } // Propagate to bottom if (propagate_down[0]) { Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); for (int i = 0; i < count; ++i) { int c = (i / dim) % channels / div_factor; bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0) + slope_data[c] * (bottom_data[i] <= 0)); } } } #ifdef CPU_ONLY STUB_GPU(PReLULayer); #endif INSTANTIATE_CLASS(PReLULayer); REGISTER_LAYER_CLASS(PReLU); } // namespace caffe