Elementwise layer learns summation
authorEvan Shelhamer <shelhamer@imaginarynumber.net>
Thu, 22 May 2014 02:31:47 +0000 (19:31 -0700)
committerEvan Shelhamer <shelhamer@imaginarynumber.net>
Thu, 22 May 2014 02:48:29 +0000 (19:48 -0700)
src/caffe/layers/eltwise_layer.cpp
src/caffe/layers/eltwise_layer.cu
src/caffe/proto/caffe.proto
src/caffe/test/test_eltwise_layer.cpp

index dd46618..769d015 100644 (file)
@@ -41,6 +41,12 @@ Dtype EltwiseLayer<Dtype>::Forward_cpu(
       caffe_mul(count, top_data, bottom[i]->cpu_data(), top_data);
     }
     break;
+  case EltwiseParameter_EltwiseOp_SUM:
+    caffe_add(count, bottom[0]->cpu_data(), bottom[1]->cpu_data(), top_data);
+    for (int i = 2; i < bottom.size(); ++i) {
+      caffe_add(count, top_data, bottom[i]->cpu_data(), top_data);
+    }
+    break;
   default:
     LOG(FATAL) << "Unknown elementwise operation.";
   }
@@ -62,6 +68,9 @@ void EltwiseLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
         caffe_div(count, top_data, bottom_data, bottom_diff);
         caffe_mul(count, bottom_diff, top_diff, bottom_diff);
         break;
+      case EltwiseParameter_EltwiseOp_SUM:
+        caffe_copy(count, top_diff, bottom_diff);
+        break;
       default:
         LOG(FATAL) << "Unknown elementwise operation.";
       }
index 9072f88..8bdb6a3 100644 (file)
@@ -20,6 +20,12 @@ Dtype EltwiseLayer<Dtype>::Forward_gpu(
       caffe_gpu_mul(count, top_data, bottom[i]->gpu_data(), top_data);
     }
     break;
+  case EltwiseParameter_EltwiseOp_SUM:
+    caffe_gpu_add(count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), top_data);
+    for (int i = 2; i < bottom.size(); ++i) {
+      caffe_gpu_add(count, top_data, bottom[i]->gpu_data(), top_data);
+    }
+    break;
   default:
     LOG(FATAL) << "Unknown elementwise operation.";
   }
@@ -41,6 +47,9 @@ void EltwiseLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
         caffe_gpu_div(count, top_data, bottom_data, bottom_diff);
         caffe_gpu_mul(count, bottom_diff, top_diff, bottom_diff);
         break;
+      case EltwiseParameter_EltwiseOp_SUM:
+        caffe_gpu_copy(count, top_diff, bottom_diff);
+        break;
       default:
         LOG(FATAL) << "Unknown elementwise operation.";
       }
index a0a855e..a7fb37b 100644 (file)
@@ -255,6 +255,7 @@ message DropoutParameter {
 message EltwiseParameter {
   enum EltwiseOp {
     PROD = 0;
+    SUM = 1;
   }
   optional EltwiseOp operation = 1; // element-wise operation to compute
 }
index 86e4751..dbb77fc 100644 (file)
@@ -65,7 +65,7 @@ TYPED_TEST(EltwiseLayerTest, TestSetUp) {
   EXPECT_EQ(this->blob_top_->width(), 5);
 }
 
-TYPED_TEST(EltwiseLayerTest, TestCPU) {
+TYPED_TEST(EltwiseLayerTest, TestProdCPU) {
   Caffe::set_mode(Caffe::CPU);
   LayerParameter layer_param;
   EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
@@ -84,7 +84,26 @@ TYPED_TEST(EltwiseLayerTest, TestCPU) {
   }
 }
 
-TYPED_TEST(EltwiseLayerTest, TestGPU) {
+TYPED_TEST(EltwiseLayerTest, TestSumCPU) {
+  Caffe::set_mode(Caffe::CPU);
+  LayerParameter layer_param;
+  EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+  eltwise_param->set_operation(EltwiseParameter_EltwiseOp_SUM);
+  shared_ptr<EltwiseLayer<TypeParam> > layer(
+      new EltwiseLayer<TypeParam>(layer_param));
+  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
+  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
+  const TypeParam* data = this->blob_top_->cpu_data();
+  const int count = this->blob_top_->count();
+  const TypeParam* in_data_a = this->blob_bottom_a_->cpu_data();
+  const TypeParam* in_data_b = this->blob_bottom_b_->cpu_data();
+  const TypeParam* in_data_c = this->blob_bottom_c_->cpu_data();
+  for (int i = 0; i < count; ++i) {
+    EXPECT_EQ(data[i], in_data_a[i] + in_data_b[i] + in_data_c[i]);
+  }
+}
+
+TYPED_TEST(EltwiseLayerTest, TestProdGPU) {
   Caffe::set_mode(Caffe::GPU);
   LayerParameter layer_param;
   EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
@@ -103,7 +122,26 @@ TYPED_TEST(EltwiseLayerTest, TestGPU) {
   }
 }
 
-TYPED_TEST(EltwiseLayerTest, TestCPUGradient) {
+TYPED_TEST(EltwiseLayerTest, TestSumGPU) {
+  Caffe::set_mode(Caffe::GPU);
+  LayerParameter layer_param;
+  EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+  eltwise_param->set_operation(EltwiseParameter_EltwiseOp_SUM);
+  shared_ptr<EltwiseLayer<TypeParam> > layer(
+      new EltwiseLayer<TypeParam>(layer_param));
+  layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
+  layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
+  const TypeParam* data = this->blob_top_->cpu_data();
+  const int count = this->blob_top_->count();
+  const TypeParam* in_data_a = this->blob_bottom_a_->cpu_data();
+  const TypeParam* in_data_b = this->blob_bottom_b_->cpu_data();
+  const TypeParam* in_data_c = this->blob_bottom_c_->cpu_data();
+  for (int i = 0; i < count; ++i) {
+    EXPECT_EQ(data[i], in_data_a[i] + in_data_b[i] + in_data_c[i]);
+  }
+}
+
+TYPED_TEST(EltwiseLayerTest, TestProdCPUGradient) {
   Caffe::set_mode(Caffe::CPU);
   LayerParameter layer_param;
   EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
@@ -114,11 +152,22 @@ TYPED_TEST(EltwiseLayerTest, TestCPUGradient) {
       &(this->blob_top_vec_));
 }
 
-TYPED_TEST(EltwiseLayerTest, TestGPUGradient) {
+TYPED_TEST(EltwiseLayerTest, TestSumCPUGradient) {
+  Caffe::set_mode(Caffe::CPU);
+  LayerParameter layer_param;
+  EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+  eltwise_param->set_operation(EltwiseParameter_EltwiseOp_SUM);
+  EltwiseLayer<TypeParam> layer(layer_param);
+  GradientChecker<TypeParam> checker(1e-2, 1e-3);
+  checker.CheckGradientEltwise(&layer, &(this->blob_bottom_vec_),
+      &(this->blob_top_vec_));
+}
+
+TYPED_TEST(EltwiseLayerTest, TestSumGPUGradient) {
   Caffe::set_mode(Caffe::GPU);
   LayerParameter layer_param;
   EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
-  eltwise_param->set_operation(EltwiseParameter_EltwiseOp_PROD);
+  eltwise_param->set_operation(EltwiseParameter_EltwiseOp_SUM);
   EltwiseLayer<TypeParam> layer(layer_param);
   GradientChecker<TypeParam> checker(1e-2, 1e-2);
   checker.CheckGradientEltwise(&layer, &(this->blob_bottom_vec_),