From d9555adf7861a8227315608a39d9bedba226c9c7 Mon Sep 17 00:00:00 2001 From: Yangqing Jia Date: Thu, 19 Sep 2013 14:28:06 -0700 Subject: [PATCH] gradient --- src/caffeine/layers/lrn_layer.cu | 48 +++++++++++++++++++++++++++++++++++- src/caffeine/test/test_lrn_layer.cpp | 27 +++++++++++++++----- src/caffeine/util/math_functions.cpp | 8 ++++++ src/caffeine/util/math_functions.hpp | 3 +++ 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/caffeine/layers/lrn_layer.cu b/src/caffeine/layers/lrn_layer.cu index 38353a2..53e1ae7 100644 --- a/src/caffeine/layers/lrn_layer.cu +++ b/src/caffeine/layers/lrn_layer.cu @@ -73,7 +73,53 @@ void LRNLayer::Forward_cpu(const vector*>& bottom, template Dtype LRNLayer::Backward_cpu(const vector*>& top, const bool propagate_down, vector*>* 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 padded_ratio(1, channels_ + size_ - 1, height_, width_); + Blob 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(scale_.count(), scale_data, -beta_, bottom_diff); + caffeine_mul(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(scale_.count(), top_diff, top_data, + padded_ratio_data + padded_ratio.offset(0, inverse_pre_pad)); + caffeine_div(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(height_ * width_, 1., + padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data); + } + for (int c = 0; c < channels_; ++c) { + caffeine_axpy(height_ * width_, 1., + padded_ratio_data + padded_ratio.offset(0, c + size_ - 1), + accum_ratio_data); + // compute bottom diff + caffeine_mul(height_ * width_, + bottom_data + top[0]->offset(n, c), + accum_ratio_data, accum_ratio_times_bottom); + caffeine_axpy(height_ * width_, -cache_ratio_value, + accum_ratio_times_bottom, bottom_diff + top[0]->offset(n,c)); + caffeine_axpy(height_ * width_, -1., + padded_ratio_data + padded_ratio.offset(0, c), accum_ratio_data); + } + } return Dtype(0.); } diff --git a/src/caffeine/test/test_lrn_layer.cpp b/src/caffeine/test/test_lrn_layer.cpp index af76cf3..b2c4c26 100644 --- a/src/caffeine/test/test_lrn_layer.cpp +++ b/src/caffeine/test/test_lrn_layer.cpp @@ -21,8 +21,10 @@ template class LRNLayerTest : public ::testing::Test { protected: LRNLayerTest() - : blob_bottom_(new Blob(1, 10, 1, 1)), - blob_top_(new Blob()) { + : blob_bottom_(new Blob()), + blob_top_(new Blob()) {}; + virtual void SetUp() { + blob_bottom_->Reshape(2,7,3,3); // fill the values FillerParameter filler_param; GaussianFiller filler(filler_param); @@ -77,10 +79,10 @@ TYPED_TEST(LRNLayerTest, TestSetup) { LayerParameter layer_param; LRNLayer 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 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 filler(filler_param); + filler.Fill(this->blob_bottom_); + GradientChecker checker(1e-2, 1e-2); + checker.CheckGradient(layer, this->blob_bottom_vec_, this->blob_top_vec_); +} + } diff --git a/src/caffeine/util/math_functions.cpp b/src/caffeine/util/math_functions.cpp index 1cdab67..e85825b 100644 --- a/src/caffeine/util/math_functions.cpp +++ b/src/caffeine/util/math_functions.cpp @@ -130,6 +130,14 @@ void caffeine_mul(const int n, const double* a, const double* b, double* y) { vdMul(n, a, b, y); } template <> +void caffeine_div(const int n, const float* a, const float* b, + float* y) { vsDiv(n, a, b, y); } + +template <> +void caffeine_div(const int n, const double* a, const double* b, + double* y) { vdDiv(n, a, b, y); } + +template <> void caffeine_powx(const int n, const float* a, const float b, float* y) { vsPowx(n, a, b, y); } diff --git a/src/caffeine/util/math_functions.hpp b/src/caffeine/util/math_functions.hpp index f07f0b0..257b61c 100644 --- a/src/caffeine/util/math_functions.hpp +++ b/src/caffeine/util/math_functions.hpp @@ -47,6 +47,9 @@ template void caffeine_mul(const int N, const Dtype* a, const Dtype* b, Dtype* y); template +void caffeine_div(const int N, const Dtype* a, const Dtype* b, Dtype* y); + +template void caffeine_powx(const int n, const Dtype* a, const Dtype b, Dtype* y); } // namespace caffeine -- 2.7.4