1 // Copyright 2013 Yangqing Jia
3 #include "caffe/layer.hpp"
4 #include "caffe/vision_layers.hpp"
5 #include "caffe/util/math_functions.hpp"
9 template <typename Dtype>
10 void LRNLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
11 vector<Blob<Dtype>*>* top) {
12 CHECK_EQ(bottom.size(), 1) <<
13 "Local Response Normalization Layer takes a single blob as input.";
14 CHECK_EQ(top->size(), 1) <<
15 "Local Response Normalization Layer takes a single blob as output.";
16 num_ = bottom[0]->num();
17 channels_ = bottom[0]->channels();
18 height_ = bottom[0]->height();
19 width_ = bottom[0]->width();
20 (*top)[0]->Reshape(num_, channels_, height_, width_);
21 scale_.Reshape(num_, channels_, height_, width_);
22 size_ = this->layer_param_.local_size();
23 pre_pad_ = (size_ - 1) / 2;
24 alpha_ = this->layer_param_.alpha();
25 beta_ = this->layer_param_.beta();
28 template <typename Dtype>
29 void LRNLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
30 vector<Blob<Dtype>*>* top) {
31 const Dtype* bottom_data = bottom[0]->cpu_data();
32 Dtype* top_data = (*top)[0]->mutable_cpu_data();
33 Dtype* scale_data = scale_.mutable_cpu_data();
34 // start with the constant value
35 for (int i = 0; i < scale_.count(); ++i) {
38 Blob<Dtype> padded_square(1, channels_ + size_ - 1, height_, width_);
39 Dtype* padded_square_data = padded_square.mutable_cpu_data();
40 memset(padded_square_data, 0, sizeof(Dtype) * padded_square.count());
41 Dtype alpha_over_size = alpha_ / size_;
42 // go through the images
43 for (int n = 0; n < num_; ++n) {
44 // compute the padded square
45 caffe_sqr(channels_ * height_ * width_,
46 bottom_data + bottom[0]->offset(n),
47 padded_square_data + padded_square.offset(0, pre_pad_));
48 // Create the first channel scale
49 for (int c = 0; c < size_; ++c) {
50 caffe_axpy<Dtype>(height_ * width_, alpha_over_size,
51 padded_square_data + padded_square.offset(0, c),
52 scale_data + scale_.offset(n, 0));
54 for (int c = 1; c < channels_; ++c) {
55 // copy previous scale
56 caffe_copy<Dtype>(height_ * width_,
57 scale_data + scale_.offset(n, c - 1),
58 scale_data + scale_.offset(n, c));
60 caffe_axpy<Dtype>(height_ * width_, alpha_over_size,
61 padded_square_data + padded_square.offset(0, c + size_ - 1),
62 scale_data + scale_.offset(n, c));
64 caffe_axpy<Dtype>(height_ * width_, -alpha_over_size,
65 padded_square_data + padded_square.offset(0, c - 1),
66 scale_data + scale_.offset(n, c));
70 // In the end, compute output
71 caffe_powx<Dtype>(scale_.count(), scale_data, -beta_, top_data);
72 caffe_mul<Dtype>(scale_.count(), top_data, bottom_data, top_data);
75 template <typename Dtype>
76 Dtype LRNLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
77 const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
78 const Dtype* top_diff = top[0]->cpu_diff();
79 const Dtype* top_data = top[0]->cpu_data();
80 const Dtype* bottom_data = (*bottom)[0]->cpu_data();
81 const Dtype* scale_data = scale_.cpu_data();
82 Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
83 Blob<Dtype> padded_ratio(1, channels_ + size_ - 1, height_, width_);
84 Blob<Dtype> accum_ratio(1, 1, height_, width_);
85 Dtype* padded_ratio_data = padded_ratio.mutable_cpu_data();
86 Dtype* accum_ratio_data = accum_ratio.mutable_cpu_data();
87 // We hack a little bit by using the diff() to store an additional result
88 Dtype* accum_ratio_times_bottom = accum_ratio.mutable_cpu_diff();
89 memset(padded_ratio_data, 0, sizeof(Dtype) * padded_ratio.count());
90 Dtype cache_ratio_value = 2. * alpha_ * beta_ / size_;
92 caffe_powx<Dtype>(scale_.count(), scale_data, -beta_, bottom_diff);
93 caffe_mul<Dtype>(scale_.count(), top_diff, bottom_diff, bottom_diff);
95 // go through individual data
96 int inverse_pre_pad = size_ - (size_ + 1) / 2;
97 for (int n = 0; n < num_; ++n) {
98 int block_offset = scale_.offset(n);
99 // first, compute diff_i * y_i / s_i
100 caffe_mul<Dtype>(channels_ * height_ * width_,
101 top_diff + block_offset, top_data + block_offset,
102 padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad));
103 caffe_div<Dtype>(channels_ * height_ * width_,
104 padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad),
105 scale_data + block_offset,
106 padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad));
107 // Now, compute the accumulated ratios and the bottom diff
108 memset(accum_ratio_data, 0, sizeof(Dtype) * accum_ratio.count());
109 for (int c = 0; c < size_ - 1; ++c) {
110 caffe_axpy<Dtype>(height_ * width_, 1.,
111 padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data);
113 for (int c = 0; c < channels_; ++c) {
114 caffe_axpy<Dtype>(height_ * width_, 1.,
115 padded_ratio_data + padded_ratio.offset(0, c + size_ - 1),
117 // compute bottom diff
118 caffe_mul<Dtype>(height_ * width_,
119 bottom_data + top[0]->offset(n, c),
120 accum_ratio_data, accum_ratio_times_bottom);
121 caffe_axpy<Dtype>(height_ * width_, -cache_ratio_value,
122 accum_ratio_times_bottom, bottom_diff + top[0]->offset(n,c));
123 caffe_axpy<Dtype>(height_ * width_, -1.,
124 padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data);
130 INSTANTIATE_CLASS(LRNLayer);