From e64d4f0580112df81b6d5d7f09e26c8a71efdeda Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 17:38:03 -0700 Subject: [PATCH 01/10] Added ArgMax Layer Conflicts: src/caffe/proto/caffe.proto --- include/caffe/vision_layers.hpp | 19 ++++++++++ src/caffe/layer_factory.cpp | 2 ++ src/caffe/layers/argmax_layer.cpp | 59 +++++++++++++++++++++++++++++++ src/caffe/proto/caffe.proto | 7 ++++ 4 files changed, 87 insertions(+) create mode 100644 src/caffe/layers/argmax_layer.cpp diff --git a/include/caffe/vision_layers.hpp b/include/caffe/vision_layers.hpp index 4765398aa7b..091fc0f65c5 100644 --- a/include/caffe/vision_layers.hpp +++ b/include/caffe/vision_layers.hpp @@ -198,6 +198,25 @@ class AccuracyLayer : public Layer { } }; +template +class ArgMaxLayer : public Layer { + public: + explicit ArgMaxLayer(const LayerParameter& param) + : Layer(param) {} + virtual void SetUp(const vector*>& bottom, + vector*>* top); + + protected: + virtual Dtype Forward_cpu(const vector*>& bottom, + vector*>* top); + // For now ArgMax layer should not be used to compute backward operations. + virtual void Backward_cpu(const vector*>& top, + const bool propagate_down, vector*>* bottom) { + NOT_IMPLEMENTED; + } + bool out_max_val_; +}; + template class ConcatLayer : public Layer { public: diff --git a/src/caffe/layer_factory.cpp b/src/caffe/layer_factory.cpp index 2991c81f559..ae15ba5bb44 100644 --- a/src/caffe/layer_factory.cpp +++ b/src/caffe/layer_factory.cpp @@ -24,6 +24,8 @@ Layer* GetLayer(const LayerParameter& param) { switch (type) { case LayerParameter_LayerType_ACCURACY: return new AccuracyLayer(param); + case LayerParameter_LayerType_ARGMAX: + return new ArgMaxLayer(param); case LayerParameter_LayerType_BNLL: return new BNLLLayer(param); case LayerParameter_LayerType_CONCAT: diff --git a/src/caffe/layers/argmax_layer.cpp b/src/caffe/layers/argmax_layer.cpp new file mode 100644 index 00000000000..b09fd7883e2 --- /dev/null +++ b/src/caffe/layers/argmax_layer.cpp @@ -0,0 +1,59 @@ +// Copyright 2014 BVLC and contributors. + +#include +#include + +#include "caffe/layer.hpp" +#include "caffe/vision_layers.hpp" + +using std::max; + +namespace caffe { + +template +void ArgMaxLayer::SetUp(const vector*>& bottom, + vector*>* top) { + CHECK_EQ(bottom.size(), 1) << "ArgMaxLayer Layer takes 1 input."; + CHECK_EQ(top->size(), 1) << "ArgMaxLayer Layer takes 1 output."; + out_max_val_ = this->layer_param_.argmax_param().out_max_val(); + // Produces max_ind and max_val + if (out_max_val_) { + (*top)[0]->Reshape(bottom[0]->num(), 2, 1, 1); + } // Produces only max_ind + else { + (*top)[0]->Reshape(bottom[0]->num(), 1, 1, 1); + } +} + +template +Dtype ArgMaxLayer::Forward_cpu(const vector*>& bottom, + vector*>* top) { + const Dtype* bottom_data = bottom[0]->cpu_data(); + Dtype* top_data = (*top)[0]->mutable_cpu_data(); + int num = bottom[0]->num(); + int dim = bottom[0]->count() / bottom[0]->num(); + for (int i = 0; i < num; ++i) { + // Accuracy + Dtype max_val = -FLT_MAX; + int max_ind = 0; + for (int j = 0; j < dim; ++j) { + if (bottom_data[i * dim + j] > max_val) { + max_val = bottom_data[i * dim + j]; + max_ind = j; + } + } + if (out_max_val_) { + top_data[i * 2] = max_ind; + top_data[i * 2 + 1] = max_val; + } + else { + top_data[i] = max_ind; + } + } + return Dtype(0); +} + +INSTANTIATE_CLASS(ArgMaxLayer); + + +} // namespace caffe diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index ab3c2fecc5c..72e7e55b725 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -149,6 +149,7 @@ message LayerParameter { SPLIT = 22; TANH = 23; WINDOW_DATA = 24; + ARGMAX = 30; } optional LayerType type = 5; // the layer type from the enum above @@ -175,6 +176,7 @@ message LayerParameter { optional PoolingParameter pooling_param = 19; optional PowerParameter power_param = 21; optional WindowDataParameter window_data_param = 20; + optional ArgMaxLayer argmax_param = 23; // DEPRECATED: The layer parameters specified as a V0LayerParameter. // This should never be used by any code except to upgrade to the new @@ -182,6 +184,11 @@ message LayerParameter { optional V0LayerParameter layer = 1; } +// Message that stores parameters used by ArgMaxLayer +message ArgMaxLayer { + // If true produce pairs (argmax, maxval) + optional bool out_max_val = 1 [default = false]; + // Message that stores parameters used by ConcatLayer message ConcatParameter { // Concat Layer needs to specify the dimension along the concat will happen, From 7e12cb2b4f28f720fc1a2886cb42ec5a67fbf3b7 Mon Sep 17 00:00:00 2001 From: Sergio Date: Thu, 15 May 2014 09:49:36 -0700 Subject: [PATCH 02/10] Added Test for ArgMax Layer --- src/caffe/test/test_argmax_layer.cpp | 113 +++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/caffe/test/test_argmax_layer.cpp diff --git a/src/caffe/test/test_argmax_layer.cpp b/src/caffe/test/test_argmax_layer.cpp new file mode 100644 index 00000000000..c99dc23021f --- /dev/null +++ b/src/caffe/test/test_argmax_layer.cpp @@ -0,0 +1,113 @@ +// Copyright 2014 BVLC and contributors. + +#include + +#include "cuda_runtime.h" +#include "gtest/gtest.h" +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/filler.hpp" +#include "caffe/vision_layers.hpp" +#include "caffe/test/test_gradient_check_util.hpp" + +#include "caffe/test/test_caffe_main.hpp" + +namespace caffe { + +extern cudaDeviceProp CAFFE_TEST_CUDA_PROP; + +template +class ArgMaxLayerTest : public ::testing::Test { + protected: + ArgMaxLayerTest() + : blob_bottom_(new Blob(20, 10, 1, 1)), + blob_top_(new Blob()) { + Caffe::set_random_seed(1701); + // fill the values + FillerParameter filler_param; + GaussianFiller filler(filler_param); + filler.Fill(this->blob_bottom_); + blob_bottom_vec_.push_back(blob_bottom_); + blob_top_vec_.push_back(blob_top_); + } + virtual ~ArgMaxLayerTest() { delete blob_bottom_; delete blob_top_; } + Blob* const blob_bottom_; + Blob* const blob_top_; + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; +}; + +typedef ::testing::Types Dtypes; +TYPED_TEST_CASE(ArgMaxLayerTest, Dtypes); + + +TYPED_TEST(ArgMaxLayerTest, TestSetup) { + LayerParameter layer_param; + ThresholdLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); + EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num()); + EXPECT_EQ(this->blob_top_->channels(), 1); +} + +TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) { + LayerParameter layer_param; + ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); + argmax_param->set_out_max_val(true) + ThresholdLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); + EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num()); + EXPECT_EQ(this->blob_top_->channels(), 2); +} + +TYPED_TEST(ArgMaxLayerTest, TestCPU) { + LayerParameter layer_param; + Caffe::set_mode(Caffe::CPU); + ArgMaxLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); + layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_)); + // Now, check values + const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); + const TypeParam* top_data = this->blob_top_->cpu_data(); + int max_ind; + TypeParam max_val; + int num = this->blob_bottom_->num(); + int dim = this->blob_bottom_->count() / num; + for (int i = 0; i < num; ++i) { + EXPECT_GE(top_data[i], 0); + EXPECT_LE(top_data[i], dim); + max_ind = top_data[i]; + max_val = bottom_data[i * dim + max_ind]; + for (int j = 0; j < dim; ++j) { + EXPECT_LE(bottom_data[i * dim + j], max_val); + } + } +} + +TYPED_TEST(ArgMaxLayerTest, TestCPUMaxVal) { + LayerParameter layer_param; + Caffe::set_mode(Caffe::CPU); + ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); + argmax_param->set_out_max_val(true) + ArgMaxLayer layer(layer_param); + layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); + layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_)); + // Now, check values + const TypeParam* bottom_data = this->blob_bottom_->cpu_data(); + const TypeParam* top_data = this->blob_top_->cpu_data(); + int max_ind; + TypeParam max_val; + int num = this->blob_bottom_->num(); + int dim = this->blob_bottom_->count() / num; + for (int i = 0; i < num; ++i) { + EXPECT_GE(top_data[i], 0); + EXPECT_LE(top_data[i], dim); + max_ind = top_data[i * 2]; + max_val = top_data[i * 2 + 1]; + EXPECT_EQ(bottom_data[i * dim + max_ind],max_val); + for (int j = 0; j < dim; ++j) { + EXPECT_LE(bottom_data[i * dim + j], max_val); + } + } +} + +} // namespace caffe From 04b3e1d4efaa94dd8b51b912cde8cbadf0af5a43 Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 17:39:52 -0700 Subject: [PATCH 03/10] Fixed numbers in proto and name of ArgMaxParameter Conflicts: src/caffe/proto/caffe.proto --- src/caffe/proto/caffe.proto | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index 72e7e55b725..91ab2e9fa1a 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -176,7 +176,8 @@ message LayerParameter { optional PoolingParameter pooling_param = 19; optional PowerParameter power_param = 21; optional WindowDataParameter window_data_param = 20; - optional ArgMaxLayer argmax_param = 23; + optional ArgMaxParameter argmax_param = 23; + // DEPRECATED: The layer parameters specified as a V0LayerParameter. // This should never be used by any code except to upgrade to the new @@ -185,9 +186,10 @@ message LayerParameter { } // Message that stores parameters used by ArgMaxLayer -message ArgMaxLayer { +message ArgMaxParameter { // If true produce pairs (argmax, maxval) optional bool out_max_val = 1 [default = false]; +} // Message that stores parameters used by ConcatLayer message ConcatParameter { From 93593105ea03110a38e24281d927575addb55944 Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 17:42:38 -0700 Subject: [PATCH 04/10] Fix types of ArgMax Layers params Conflicts: include/caffe/vision_layers.hpp src/caffe/proto/caffe.proto --- src/caffe/proto/caffe.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index 91ab2e9fa1a..bc1d1478c87 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -178,7 +178,6 @@ message LayerParameter { optional WindowDataParameter window_data_param = 20; optional ArgMaxParameter argmax_param = 23; - // DEPRECATED: The layer parameters specified as a V0LayerParameter. // This should never be used by any code except to upgrade to the new // LayerParameter specification. @@ -186,6 +185,7 @@ message LayerParameter { } // Message that stores parameters used by ArgMaxLayer + message ArgMaxParameter { // If true produce pairs (argmax, maxval) optional bool out_max_val = 1 [default = false]; From 80c8bfc2a566e744998bdb6f874644274a4ad20b Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 16:09:07 -0700 Subject: [PATCH 05/10] Added FLT_MAX to argmax layer --- src/caffe/layers/argmax_layer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/caffe/layers/argmax_layer.cpp b/src/caffe/layers/argmax_layer.cpp index b09fd7883e2..33ec1d34089 100644 --- a/src/caffe/layers/argmax_layer.cpp +++ b/src/caffe/layers/argmax_layer.cpp @@ -1,12 +1,11 @@ // Copyright 2014 BVLC and contributors. -#include #include +#include #include "caffe/layer.hpp" #include "caffe/vision_layers.hpp" -using std::max; namespace caffe { From a68dc3ff2a254d84300191e15c832c2af78ac67c Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 16:43:01 -0700 Subject: [PATCH 06/10] Added missing ; --- src/caffe/test/test_argmax_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/caffe/test/test_argmax_layer.cpp b/src/caffe/test/test_argmax_layer.cpp index c99dc23021f..bc3a8ecd1e0 100644 --- a/src/caffe/test/test_argmax_layer.cpp +++ b/src/caffe/test/test_argmax_layer.cpp @@ -52,7 +52,7 @@ TYPED_TEST(ArgMaxLayerTest, TestSetup) { TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) { LayerParameter layer_param; ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); - argmax_param->set_out_max_val(true) + argmax_param->set_out_max_val(true); ThresholdLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num()); @@ -87,7 +87,7 @@ TYPED_TEST(ArgMaxLayerTest, TestCPUMaxVal) { LayerParameter layer_param; Caffe::set_mode(Caffe::CPU); ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); - argmax_param->set_out_max_val(true) + argmax_param->set_out_max_val(true); ArgMaxLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_)); From 65cf80cbd23d35c1922d831b2bde5cd29b5fabe1 Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 16:54:21 -0700 Subject: [PATCH 07/10] Fixed name of ArgMaxLayerParameter --- src/caffe/test/test_argmax_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/caffe/test/test_argmax_layer.cpp b/src/caffe/test/test_argmax_layer.cpp index bc3a8ecd1e0..b30e7edbf66 100644 --- a/src/caffe/test/test_argmax_layer.cpp +++ b/src/caffe/test/test_argmax_layer.cpp @@ -51,7 +51,7 @@ TYPED_TEST(ArgMaxLayerTest, TestSetup) { TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) { LayerParameter layer_param; - ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); + ArgMaxLayerParameter* argmax_param = layer_param.mutable_argmax_param(); argmax_param->set_out_max_val(true); ThresholdLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); @@ -86,7 +86,7 @@ TYPED_TEST(ArgMaxLayerTest, TestCPU) { TYPED_TEST(ArgMaxLayerTest, TestCPUMaxVal) { LayerParameter layer_param; Caffe::set_mode(Caffe::CPU); - ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); + ArgMaxLayerParameter* argmax_param = layer_param.mutable_argmax_param(); argmax_param->set_out_max_val(true); ArgMaxLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); From 77eab791d7c04d8f59d3a15ec9e95f9a31462b58 Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 16:55:45 -0700 Subject: [PATCH 08/10] Fixed name of blob_bottom_ --- src/caffe/test/test_argmax_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/caffe/test/test_argmax_layer.cpp b/src/caffe/test/test_argmax_layer.cpp index b30e7edbf66..0174e8988e1 100644 --- a/src/caffe/test/test_argmax_layer.cpp +++ b/src/caffe/test/test_argmax_layer.cpp @@ -45,7 +45,7 @@ TYPED_TEST(ArgMaxLayerTest, TestSetup) { LayerParameter layer_param; ThresholdLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); - EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num()); + EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); EXPECT_EQ(this->blob_top_->channels(), 1); } @@ -55,7 +55,7 @@ TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) { argmax_param->set_out_max_val(true); ThresholdLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); - EXPECT_EQ(this->blob_top_->num(), this->bottom_top_->num()); + EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); EXPECT_EQ(this->blob_top_->channels(), 2); } From 3e846f941244dceed1c693c787af9c45e98d956d Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 18:01:04 -0700 Subject: [PATCH 09/10] Change ThresholdLayer to ArgMaxLayer in test_argmax --- src/caffe/test/test_argmax_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/caffe/test/test_argmax_layer.cpp b/src/caffe/test/test_argmax_layer.cpp index 0174e8988e1..f0754f0c1d2 100644 --- a/src/caffe/test/test_argmax_layer.cpp +++ b/src/caffe/test/test_argmax_layer.cpp @@ -43,7 +43,7 @@ TYPED_TEST_CASE(ArgMaxLayerTest, Dtypes); TYPED_TEST(ArgMaxLayerTest, TestSetup) { LayerParameter layer_param; - ThresholdLayer layer(layer_param); + ArgMaxLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); EXPECT_EQ(this->blob_top_->channels(), 1); @@ -53,7 +53,7 @@ TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) { LayerParameter layer_param; ArgMaxLayerParameter* argmax_param = layer_param.mutable_argmax_param(); argmax_param->set_out_max_val(true); - ThresholdLayer layer(layer_param); + ArgMaxLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); EXPECT_EQ(this->blob_top_->num(), this->blob_bottom_->num()); EXPECT_EQ(this->blob_top_->channels(), 2); From cfa71681e1345948e0ffaebbb4f9d2c00c1d2029 Mon Sep 17 00:00:00 2001 From: Sergio Guadarrama Date: Thu, 15 May 2014 18:02:08 -0700 Subject: [PATCH 10/10] Change ArgMaxLayerParam to ArgMaxParam for consitency --- src/caffe/test/test_argmax_layer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/caffe/test/test_argmax_layer.cpp b/src/caffe/test/test_argmax_layer.cpp index f0754f0c1d2..627dd575904 100644 --- a/src/caffe/test/test_argmax_layer.cpp +++ b/src/caffe/test/test_argmax_layer.cpp @@ -51,7 +51,7 @@ TYPED_TEST(ArgMaxLayerTest, TestSetup) { TYPED_TEST(ArgMaxLayerTest, TestSetupMaxVal) { LayerParameter layer_param; - ArgMaxLayerParameter* argmax_param = layer_param.mutable_argmax_param(); + ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); argmax_param->set_out_max_val(true); ArgMaxLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_)); @@ -86,7 +86,7 @@ TYPED_TEST(ArgMaxLayerTest, TestCPU) { TYPED_TEST(ArgMaxLayerTest, TestCPUMaxVal) { LayerParameter layer_param; Caffe::set_mode(Caffe::CPU); - ArgMaxLayerParameter* argmax_param = layer_param.mutable_argmax_param(); + ArgMaxParameter* argmax_param = layer_param.mutable_argmax_param(); argmax_param->set_out_max_val(true); ArgMaxLayer layer(layer_param); layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));