Skip to content

Commit

Permalink
[test] simple test for DeconvolutionLayer
Browse files Browse the repository at this point in the history
  • Loading branch information
longjon committed Jan 27, 2015
1 parent 408133c commit 25c2e3f
Showing 1 changed file with 158 additions and 0 deletions.
158 changes: 158 additions & 0 deletions src/caffe/test/test_deconvolution_layer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include <cstring>
#include <vector>

#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_caffe_main.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

namespace caffe {

// Since ConvolutionLayerTest checks the shared conv/deconv code in detail,
// we'll just do a simple forward test and a gradient check.
template <typename TypeParam>
class DeconvolutionLayerTest : public MultiDeviceTest<TypeParam> {
typedef typename TypeParam::Dtype Dtype;

protected:
DeconvolutionLayerTest()
: blob_bottom_(new Blob<Dtype>(2, 3, 6, 4)),
blob_bottom_2_(new Blob<Dtype>(2, 3, 6, 4)),
blob_top_(new Blob<Dtype>()),
blob_top_2_(new Blob<Dtype>()) {}
virtual void SetUp() {
// fill the values
FillerParameter filler_param;
filler_param.set_value(1.);
GaussianFiller<Dtype> filler(filler_param);
filler.Fill(this->blob_bottom_);
filler.Fill(this->blob_bottom_2_);
blob_bottom_vec_.push_back(blob_bottom_);
blob_top_vec_.push_back(blob_top_);
}

virtual ~DeconvolutionLayerTest() {
delete blob_bottom_;
delete blob_bottom_2_;
delete blob_top_;
delete blob_top_2_;
}

Blob<Dtype>* const blob_bottom_;
Blob<Dtype>* const blob_bottom_2_;
Blob<Dtype>* const blob_top_;
Blob<Dtype>* const blob_top_2_;
vector<Blob<Dtype>*> blob_bottom_vec_;
vector<Blob<Dtype>*> blob_top_vec_;
};

TYPED_TEST_CASE(DeconvolutionLayerTest, TestDtypesAndDevices);

TYPED_TEST(DeconvolutionLayerTest, TestSetup) {
typedef typename TypeParam::Dtype Dtype;
LayerParameter layer_param;
ConvolutionParameter* convolution_param =
layer_param.mutable_convolution_param();
convolution_param->set_kernel_size(3);
convolution_param->set_stride(2);
convolution_param->set_num_output(4);
this->blob_bottom_vec_.push_back(this->blob_bottom_2_);
this->blob_top_vec_.push_back(this->blob_top_2_);
shared_ptr<Layer<Dtype> > layer(
new DeconvolutionLayer<Dtype>(layer_param));
layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_);
EXPECT_EQ(this->blob_top_->num(), 2);
EXPECT_EQ(this->blob_top_->channels(), 4);
EXPECT_EQ(this->blob_top_->height(), 13);
EXPECT_EQ(this->blob_top_->width(), 9);
EXPECT_EQ(this->blob_top_2_->num(), 2);
EXPECT_EQ(this->blob_top_2_->channels(), 4);
EXPECT_EQ(this->blob_top_2_->height(), 13);
EXPECT_EQ(this->blob_top_2_->width(), 9);
// setting group should not change the shape
convolution_param->set_num_output(3);
convolution_param->set_group(3);
layer.reset(new DeconvolutionLayer<Dtype>(layer_param));
layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_);
EXPECT_EQ(this->blob_top_->num(), 2);
EXPECT_EQ(this->blob_top_->channels(), 3);
EXPECT_EQ(this->blob_top_->height(), 13);
EXPECT_EQ(this->blob_top_->width(), 9);
EXPECT_EQ(this->blob_top_2_->num(), 2);
EXPECT_EQ(this->blob_top_2_->channels(), 3);
EXPECT_EQ(this->blob_top_2_->height(), 13);
EXPECT_EQ(this->blob_top_2_->width(), 9);
}

TYPED_TEST(DeconvolutionLayerTest, TestSimpleDeconvolution) {
typedef typename TypeParam::Dtype Dtype;
this->blob_bottom_vec_.push_back(this->blob_bottom_2_);
this->blob_top_vec_.push_back(this->blob_top_2_);
LayerParameter layer_param;
ConvolutionParameter* convolution_param =
layer_param.mutable_convolution_param();
convolution_param->set_kernel_size(3);
convolution_param->set_stride(2);
convolution_param->set_num_output(4);
convolution_param->mutable_weight_filler()->set_type("constant");
convolution_param->mutable_weight_filler()->set_value(1);
convolution_param->mutable_bias_filler()->set_type("constant");
convolution_param->mutable_bias_filler()->set_value(0.1);
shared_ptr<Layer<Dtype> > layer(
new DeconvolutionLayer<Dtype>(layer_param));
layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_);
// constant-fill the bottom blobs
FillerParameter filler_param;
filler_param.set_value(1.);
ConstantFiller<Dtype> filler(filler_param);
filler.Fill(this->blob_bottom_);
filler.Fill(this->blob_bottom_2_);
layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_);
// simply check that accumulation works with overlapping filters
const Dtype* top_data = this->blob_top_->cpu_data();
for (int n = 0; n < this->blob_top_->num(); ++n) {
for (int c = 0; c < this->blob_top_->channels(); ++c) {
for (int h = 0; h < this->blob_top_->height(); ++h) {
for (int w = 0; w < this->blob_top_->width(); ++w) {
Dtype expected = 3.1;
bool h_overlap = h % 2 == 0 && h > 0
&& h < this->blob_top_->height() - 1;
bool w_overlap = w % 2 == 0 && w > 0
&& w < this->blob_top_->width() - 1;
if (h_overlap && w_overlap) {
expected += 9;
} else if (h_overlap || w_overlap) {
expected += 3;
}
EXPECT_NEAR(top_data[this->blob_top_->offset(n, c, h, w)],
expected, 1e-4);
}
}
}
}
}

TYPED_TEST(DeconvolutionLayerTest, TestGradient) {
typedef typename TypeParam::Dtype Dtype;
LayerParameter layer_param;
ConvolutionParameter* convolution_param =
layer_param.mutable_convolution_param();
this->blob_bottom_vec_.push_back(this->blob_bottom_2_);
this->blob_top_vec_.push_back(this->blob_top_2_);
convolution_param->set_kernel_size(2);
convolution_param->set_stride(1);
convolution_param->set_num_output(1);
convolution_param->mutable_weight_filler()->set_type("gaussian");
convolution_param->mutable_bias_filler()->set_type("gaussian");
DeconvolutionLayer<Dtype> layer(layer_param);
GradientChecker<Dtype> checker(1e-2, 1e-3);
checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_,
this->blob_top_vec_);
}

} // namespace caffe

0 comments on commit 25c2e3f

Please sign in to comment.