copyright message
[platform/upstream/caffeonacl.git] / src / caffe / layers / lrn_layer.cpp
1 // Copyright 2013 Yangqing Jia
2
3 #include "caffe/layer.hpp"
4 #include "caffe/vision_layers.hpp"
5 #include "caffe/util/math_functions.hpp"
6
7 namespace caffe {
8
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();
26 };
27
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) {
36     scale_data[i] = 1.;
37   }
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));
53     }
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));
59       // add head
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));
63       // subtract tail
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));
67     }
68   }
69
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);
73 }
74
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_;
91
92   caffe_powx<Dtype>(scale_.count(), scale_data, -beta_, bottom_diff);
93   caffe_mul<Dtype>(scale_.count(), top_diff, bottom_diff, bottom_diff);
94
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);
112     }
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),
116           accum_ratio_data);
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);
125     }
126   }
127   return Dtype(0.);
128 }
129
130 INSTANTIATE_CLASS(LRNLayer);
131
132
133 }  // namespace caffe