#include #include #include "boost/scoped_ptr.hpp" #include "gtest/gtest.h" #include "caffe/blob.hpp" #include "caffe/common.hpp" #include "caffe/filler.hpp" #include "caffe/layers/softmax_loss_layer.hpp" #include "caffe/test/test_caffe_main.hpp" #include "caffe/test/test_gradient_check_util.hpp" using boost::scoped_ptr; namespace caffe { template class SoftmaxWithLossLayerTest : public MultiDeviceTest { typedef typename TypeParam::Dtype Dtype; protected: SoftmaxWithLossLayerTest() : blob_bottom_data_(new Blob(10, 5, 2, 3)), blob_bottom_label_(new Blob(10, 1, 2, 3)), blob_top_loss_(new Blob()) { // fill the values FillerParameter filler_param; filler_param.set_std(10); GaussianFiller filler(filler_param); filler.Fill(this->blob_bottom_data_); blob_bottom_vec_.push_back(blob_bottom_data_); for (int i = 0; i < blob_bottom_label_->count(); ++i) { blob_bottom_label_->mutable_cpu_data()[i] = caffe_rng_rand() % 5; } blob_bottom_vec_.push_back(blob_bottom_label_); blob_top_vec_.push_back(blob_top_loss_); } virtual ~SoftmaxWithLossLayerTest() { delete blob_bottom_data_; delete blob_bottom_label_; delete blob_top_loss_; } Blob* const blob_bottom_data_; Blob* const blob_bottom_label_; Blob* const blob_top_loss_; vector*> blob_bottom_vec_; vector*> blob_top_vec_; }; TYPED_TEST_CASE(SoftmaxWithLossLayerTest, TestDtypesAndDevices); TYPED_TEST(SoftmaxWithLossLayerTest, TestGradient) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; layer_param.add_loss_weight(3); SoftmaxWithLossLayer layer(layer_param); GradientChecker checker(1e-2, 1e-2, 1701); checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_, 0); } TYPED_TEST(SoftmaxWithLossLayerTest, TestForwardIgnoreLabel) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; layer_param.mutable_loss_param()->set_normalize(false); // First, compute the loss with all labels scoped_ptr > layer( new SoftmaxWithLossLayer(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); Dtype full_loss = this->blob_top_loss_->cpu_data()[0]; // Now, accumulate the loss, ignoring each label in {0, ..., 4} in turn. Dtype accum_loss = 0; for (int label = 0; label < 5; ++label) { layer_param.mutable_loss_param()->set_ignore_label(label); layer.reset(new SoftmaxWithLossLayer(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); accum_loss += this->blob_top_loss_->cpu_data()[0]; } // Check that each label was included all but once. EXPECT_NEAR(4 * full_loss, accum_loss, 1e-4); } TYPED_TEST(SoftmaxWithLossLayerTest, TestGradientIgnoreLabel) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; // labels are in {0, ..., 4}, so we'll ignore about a fifth of them layer_param.mutable_loss_param()->set_ignore_label(0); SoftmaxWithLossLayer layer(layer_param); GradientChecker checker(1e-2, 1e-2, 1701); checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_, 0); } TYPED_TEST(SoftmaxWithLossLayerTest, TestGradientUnnormalized) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; layer_param.mutable_loss_param()->set_normalize(false); SoftmaxWithLossLayer layer(layer_param); GradientChecker checker(1e-2, 1e-2, 1701); checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_, 0); } } // namespace caffe