gradient
authorYangqing Jia <jiayq84@gmail.com>
Thu, 19 Sep 2013 21:28:06 +0000 (14:28 -0700)
committerYangqing Jia <jiayq84@gmail.com>
Thu, 19 Sep 2013 21:28:06 +0000 (14:28 -0700)
src/caffeine/layers/lrn_layer.cu
src/caffeine/test/test_lrn_layer.cpp
src/caffeine/util/math_functions.cpp
src/caffeine/util/math_functions.hpp

index 38353a2..53e1ae7 100644 (file)
@@ -73,7 +73,53 @@ void LRNLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
 template <typename Dtype>
 Dtype LRNLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
     const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
-  NOT_IMPLEMENTED;
+  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* scale_data = scale_.cpu_data();
+  Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();
+  Blob<Dtype> padded_ratio(1, channels_ + size_ - 1, height_, width_);
+  Blob<Dtype> accum_ratio(1, 1, height_, width_);
+  Dtype* padded_ratio_data = padded_ratio.mutable_cpu_data();
+  Dtype* accum_ratio_data = accum_ratio.mutable_cpu_data();
+  // We hack a little bit by using the diff() to store an additional result
+  Dtype* accum_ratio_times_bottom = accum_ratio.mutable_cpu_diff();
+  memset(padded_ratio_data, 0, sizeof(Dtype) * padded_ratio.count());
+  Dtype cache_ratio_value = 2. * alpha_ * beta_ / size_;
+
+  caffeine_powx<Dtype>(scale_.count(), scale_data, -beta_, bottom_diff);
+  caffeine_mul<Dtype>(scale_.count(), top_diff, bottom_diff, bottom_diff);
+
+  // go through individual data
+  int inverse_pre_pad = size_ - (size_ + 1) / 2;
+  for (int n = 0; n < num_; ++n) {
+    // first, compute diff_i * y_i / s_i
+    caffeine_mul<Dtype>(scale_.count(), top_diff, top_data,
+        padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad));
+    caffeine_div<Dtype>(scale_.count(),
+        padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad),
+        scale_data,
+        padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad));
+    // Now, compute the accumulated ratios and the bottom diff
+    memset(accum_ratio_data, 0, sizeof(Dtype) * accum_ratio.count());
+    for (int c = 0; c < size_ - 1; ++c) {
+      caffeine_axpy<Dtype>(height_ * width_, 1.,
+          padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data);
+    }
+    for (int c = 0; c < channels_; ++c) {
+      caffeine_axpy<Dtype>(height_ * width_, 1.,
+          padded_ratio_data + padded_ratio.offset(0, c + size_ - 1),
+          accum_ratio_data);
+      // compute bottom diff
+      caffeine_mul<Dtype>(height_ * width_,
+          bottom_data + top[0]->offset(n, c),
+          accum_ratio_data, accum_ratio_times_bottom);
+      caffeine_axpy<Dtype>(height_ * width_, -cache_ratio_value,
+          accum_ratio_times_bottom, bottom_diff + top[0]->offset(n,c));
+      caffeine_axpy<Dtype>(height_ * width_, -1.,
+          padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data);
+    }
+  }
   return Dtype(0.);
 }
 
index af76cf3..b2c4c26 100644 (file)
@@ -21,8 +21,10 @@ template <typename Dtype>
 class LRNLayerTest : public ::testing::Test {
  protected:
   LRNLayerTest()
-      : blob_bottom_(new Blob<Dtype>(1, 10, 1, 1)),
-        blob_top_(new Blob<Dtype>()) {
+      : blob_bottom_(new Blob<Dtype>()),
+        blob_top_(new Blob<Dtype>()) {};
+  virtual void SetUp() {
+    blob_bottom_->Reshape(2,7,3,3);
     // fill the values
     FillerParameter filler_param;
     GaussianFiller<Dtype> filler(filler_param);
@@ -77,10 +79,10 @@ TYPED_TEST(LRNLayerTest, TestSetup) {
   LayerParameter layer_param;
   LRNLayer<TypeParam> layer(layer_param);
   layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
-  EXPECT_EQ(this->blob_top_->num(), 1);
-  EXPECT_EQ(this->blob_top_->channels(), 10);
-  EXPECT_EQ(this->blob_top_->height(), 1);
-  EXPECT_EQ(this->blob_top_->width(), 1);
+  EXPECT_EQ(this->blob_top_->num(), 2);
+  EXPECT_EQ(this->blob_top_->channels(), 7);
+  EXPECT_EQ(this->blob_top_->height(), 3);
+  EXPECT_EQ(this->blob_top_->width(), 3);
 }
 
 TYPED_TEST(LRNLayerTest, TestCPU) {
@@ -100,4 +102,17 @@ TYPED_TEST(LRNLayerTest, TestCPU) {
   }
 }
 
+TYPED_TEST(LRNLayerTest, TestCPUGradient) {
+  LayerParameter layer_param;
+  LRNLayer<TypeParam> layer(layer_param);
+  Caffeine::set_mode(Caffeine::CPU);
+  // when testing the GPU gradient, let's do a small shape.
+  this->blob_bottom_->Reshape(1, 7, 1, 1);
+  FillerParameter filler_param;
+  GaussianFiller<TypeParam> filler(filler_param);
+  filler.Fill(this->blob_bottom_);
+  GradientChecker<TypeParam> checker(1e-2, 1e-2);
+  checker.CheckGradient(layer, this->blob_bottom_vec_, this->blob_top_vec_);
+}
+
 }
index 1cdab67..e85825b 100644 (file)
@@ -130,6 +130,14 @@ void caffeine_mul<double>(const int n, const double* a, const double* b,
     double* y) { vdMul(n, a, b, y); }
 
 template <>
+void caffeine_div<float>(const int n, const float* a, const float* b,
+    float* y) { vsDiv(n, a, b, y); }
+
+template <>
+void caffeine_div<double>(const int n, const double* a, const double* b,
+    double* y) { vdDiv(n, a, b, y); }
+
+template <>
 void caffeine_powx<float>(const int n, const float* a, const float b,
     float* y) { vsPowx(n, a, b, y); }
 
index f07f0b0..257b61c 100644 (file)
@@ -47,6 +47,9 @@ template <typename Dtype>
 void caffeine_mul(const int N, const Dtype* a, const Dtype* b, Dtype* y);
 
 template <typename Dtype>
+void caffeine_div(const int N, const Dtype* a, const Dtype* b, Dtype* y);
+
+template <typename Dtype>
 void caffeine_powx(const int n, const Dtype* a, const Dtype b, Dtype* y);
 
 }  // namespace caffeine