From ccf4eb53d51c53ffbb4fb263b98ce2cc877ded05 Mon Sep 17 00:00:00 2001 From: sguada Date: Mon, 17 Feb 2014 10:08:39 -0800 Subject: [PATCH] Renamed input_layer to images_layer --- src/caffe/layer_factory.cpp | 4 +- .../layers/{input_layer.cpp => images_layer.cpp} | 38 +++--- src/caffe/proto/caffe.proto | 8 +- src/caffe/test/test_images_layer.cpp | 128 +++++++++++++++++++++ 4 files changed, 154 insertions(+), 24 deletions(-) rename src/caffe/layers/{input_layer.cpp => images_layer.cpp} (88%) create mode 100644 src/caffe/test/test_images_layer.cpp diff --git a/src/caffe/layer_factory.cpp b/src/caffe/layer_factory.cpp index 7e2a3c8..61d0e0d 100644 --- a/src/caffe/layer_factory.cpp +++ b/src/caffe/layer_factory.cpp @@ -27,8 +27,8 @@ Layer* GetLayer(const LayerParameter& param) { return new ConvolutionLayer(param); } else if (type == "data") { return new DataLayer(param); - } else if (type == "input") { - return new InputLayer(param); + } else if (type == "images") { + return new ImagesLayer(param); } else if (type == "dropout") { return new DropoutLayer(param); } else if (type == "euclidean_loss") { diff --git a/src/caffe/layers/input_layer.cpp b/src/caffe/layers/images_layer.cpp similarity index 88% rename from src/caffe/layers/input_layer.cpp rename to src/caffe/layers/images_layer.cpp index db3d634..f600dbc 100644 --- a/src/caffe/layers/input_layer.cpp +++ b/src/caffe/layers/images_layer.cpp @@ -19,9 +19,9 @@ using std::pair; namespace caffe { template -void* InputLayerPrefetch(void* layer_pointer) { +void* ImagesLayerPrefetch(void* layer_pointer) { CHECK(layer_pointer); - InputLayer* layer = reinterpret_cast*>(layer_pointer); + ImagesLayer* layer = reinterpret_cast*>(layer_pointer); CHECK(layer); Datum datum; CHECK(layer->prefetch_data_); @@ -31,7 +31,8 @@ void* InputLayerPrefetch(void* layer_pointer) { const int batchsize = layer->layer_param_.batchsize(); const int cropsize = layer->layer_param_.cropsize(); const bool mirror = layer->layer_param_.mirror(); - const int resize_image = layer->layer_param_.resize_image(); + const int new_height = layer->layer_param_.new_height(); + const int new_width = layer->layer_param_.new_height(); if (mirror && cropsize == 0) { LOG(FATAL) << "Current implementation requires mirror and cropsize to be " @@ -48,7 +49,7 @@ void* InputLayerPrefetch(void* layer_pointer) { // get a blob CHECK_GT(lines_size,layer->lines_id_); if (!ReadImageToDatum(layer->lines_[layer->lines_id_].first, layer->lines_[layer->lines_id_].second, - resize_image, resize_image, &datum)) { + new_height, new_width, &datum)) { continue; }; const string& data = datum.data(); @@ -115,7 +116,7 @@ void* InputLayerPrefetch(void* layer_pointer) { // We have reached the end. Restart from the first. DLOG(INFO) << "Restarting data prefetching from start."; layer->lines_id_=0; - if (layer->layer_param_.shuffle_data()) { + if (layer->layer_param_.shuffle_images()) { std::random_shuffle(layer->lines_.begin(), layer->lines_.end()); } } @@ -125,13 +126,13 @@ void* InputLayerPrefetch(void* layer_pointer) { } template -InputLayer::~InputLayer() { +ImagesLayer::~ImagesLayer() { // Finally, join the thread CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed."; } template -void InputLayer::SetUp(const vector*>& bottom, +void ImagesLayer::SetUp(const vector*>& bottom, vector*>* top) { CHECK_EQ(bottom.size(), 0) << "Input Layer takes no input blobs."; CHECK_EQ(top->size(), 2) << "Input Layer takes two blobs as output."; @@ -144,7 +145,7 @@ void InputLayer::SetUp(const vector*>& bottom, lines_.push_back(std::make_pair(filename, label)); } - if (this->layer_param_.shuffle_data()) { + if (this->layer_param_.shuffle_images()) { // randomly shuffle data LOG(INFO) << "Shuffling data"; std::random_shuffle(lines_.begin(), lines_.end()); @@ -161,9 +162,10 @@ void InputLayer::SetUp(const vector*>& bottom, } // Read a data point, and use it to initialize the top blob. Datum datum; - const int resize_image = this->layer_param_.resize_image(); + const int new_height = layer->layer_param_.new_height(); + const int new_width = layer->layer_param_.new_height(); CHECK(ReadImageToDatum(lines_[lines_id_].first, lines_[lines_id_].second, - resize_image,resize_image,&datum)); + new_height,new_width,&datum)); // image int cropsize = this->layer_param_.cropsize(); if (cropsize > 0) { @@ -215,13 +217,13 @@ void InputLayer::SetUp(const vector*>& bottom, prefetch_label_->mutable_cpu_data(); data_mean_.cpu_data(); DLOG(INFO) << "Initializing prefetch"; - CHECK(!pthread_create(&thread_, NULL, InputLayerPrefetch, + CHECK(!pthread_create(&thread_, NULL, ImagesLayerPrefetch, reinterpret_cast(this))) << "Pthread execution failed."; DLOG(INFO) << "Prefetch initialized."; } template -void InputLayer::Forward_cpu(const vector*>& bottom, +void ImagesLayer::Forward_cpu(const vector*>& bottom, vector*>* top) { // First, join the thread CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed."; @@ -231,12 +233,12 @@ void InputLayer::Forward_cpu(const vector*>& bottom, memcpy((*top)[1]->mutable_cpu_data(), prefetch_label_->cpu_data(), sizeof(Dtype) * prefetch_label_->count()); // Start a new prefetch thread - CHECK(!pthread_create(&thread_, NULL, InputLayerPrefetch, + CHECK(!pthread_create(&thread_, NULL, ImagesLayerPrefetch, reinterpret_cast(this))) << "Pthread execution failed."; } template -void InputLayer::Forward_gpu(const vector*>& bottom, +void ImagesLayer::Forward_gpu(const vector*>& bottom, vector*>* top) { // First, join the thread CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed."; @@ -248,23 +250,23 @@ void InputLayer::Forward_gpu(const vector*>& bottom, prefetch_label_->cpu_data(), sizeof(Dtype) * prefetch_label_->count(), cudaMemcpyHostToDevice)); // Start a new prefetch thread - CHECK(!pthread_create(&thread_, NULL, InputLayerPrefetch, + CHECK(!pthread_create(&thread_, NULL, ImagesLayerPrefetch, reinterpret_cast(this))) << "Pthread execution failed."; } // The backward operations are dummy - they do not carry any computation. template -Dtype InputLayer::Backward_cpu(const vector*>& top, +Dtype ImagesLayer::Backward_cpu(const vector*>& top, const bool propagate_down, vector*>* bottom) { return Dtype(0.); } template -Dtype InputLayer::Backward_gpu(const vector*>& top, +Dtype ImagesLayer::Backward_gpu(const vector*>& top, const bool propagate_down, vector*>* bottom) { return Dtype(0.); } -INSTANTIATE_CLASS(InputLayer); +INSTANTIATE_CLASS(ImagesLayer); } // namespace caffe diff --git a/src/caffe/proto/caffe.proto b/src/caffe/proto/caffe.proto index dd09b73..d9a5524 100644 --- a/src/caffe/proto/caffe.proto +++ b/src/caffe/proto/caffe.proto @@ -92,10 +92,10 @@ message LayerParameter { // be larger than the number of keys in the leveldb. optional uint32 rand_skip = 53 [ default = 0 ]; - // Used by Input_layer to shuffle the list of files at every epoch - optional bool shuffle_data = 61 [default = false]; - // If >0 then it will resize input images to size given by resize_image using cv::resize - optional int32 resize_image = 62 [default = 0 ]; + // Used by ImageLayer to shuffle the list of files at every epoch it will also + // resize images if new_height or new_width are not zero + optional bool shuffle_images = 64 [default = false]; + } message LayerConnection { diff --git a/src/caffe/test/test_images_layer.cpp b/src/caffe/test/test_images_layer.cpp new file mode 100644 index 0000000..f98df37 --- /dev/null +++ b/src/caffe/test/test_images_layer.cpp @@ -0,0 +1,128 @@ +// Copyright 2014 Sergio Guadarrama + +#include +#include +#include + +#include + +#include "gtest/gtest.h" +#include "caffe/blob.hpp" +#include "caffe/common.hpp" +#include "caffe/filler.hpp" +#include "caffe/vision_layers.hpp" +#include "caffe/proto/caffe.pb.h" +#include "caffe/test/test_caffe_main.hpp" + +using std::string; + +namespace caffe { + +extern cudaDeviceProp CAFFE_TEST_CUDA_PROP; + +template +class ImagesLayerTest : public ::testing::Test { + protected: + ImagesLayerTest() + : blob_top_data_(new Blob()), + blob_top_label_(new Blob()), + filename(NULL) {}; + virtual void SetUp() { + blob_top_vec_.push_back(blob_top_data_); + blob_top_vec_.push_back(blob_top_label_); + // Create a Vector of files with labels + filename = tmpnam(NULL); // get temp name + std::ofstream outfile(filename, std::ofstream::out); + LOG(INFO) << "Using temporary file " << filename; + for (int i = 0; i < 5; ++i) { + outfile << "data/cat.jpg " << i; + } + outfile.close(); + }; + + virtual ~ImagesLayerTest() { delete blob_top_data_; delete blob_top_label_; } + + char* filename; + Blob* const blob_top_data_; + Blob* const blob_top_label_; + vector*> blob_bottom_vec_; + vector*> blob_top_vec_; +}; + +typedef ::testing::Types Dtypes; +TYPED_TEST_CASE(ImagesLayerTest, Dtypes); + +TYPED_TEST(ImagesLayerTest, TestRead) { + LayerParameter param; + param.set_batchsize(5); + param.set_source(this->filename); + param.set_shuffle_images(false); + ImagesLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, &this->blob_top_vec_); + EXPECT_EQ(this->blob_top_data_->num(), 5); + EXPECT_EQ(this->blob_top_data_->channels(), 3); + EXPECT_EQ(this->blob_top_data_->height(), 1200); + EXPECT_EQ(this->blob_top_data_->width(), 1600); + EXPECT_EQ(this->blob_top_label_->num(), 5); + EXPECT_EQ(this->blob_top_label_->channels(), 1); + EXPECT_EQ(this->blob_top_label_->height(), 1); + EXPECT_EQ(this->blob_top_label_->width(), 1); + // Go through the data 5 times + for (int iter = 0; iter < 5; ++iter) { + layer.Forward(this->blob_bottom_vec_, &this->blob_top_vec_); + for (int i = 0; i < 5; ++i) { + EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]); + } + } +} + +TYPED_TEST(ImagesLayerTest, TestResize) { + LayerParameter param; + param.set_batchsize(5); + param.set_source(this->filename); + param.set_resize_image(256); + param.set_shuffle_images(false); + ImagesLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, &this->blob_top_vec_); + EXPECT_EQ(this->blob_top_data_->num(), 5); + EXPECT_EQ(this->blob_top_data_->channels(), 3); + EXPECT_EQ(this->blob_top_data_->height(), 256); + EXPECT_EQ(this->blob_top_data_->width(), 256); + EXPECT_EQ(this->blob_top_label_->num(), 5); + EXPECT_EQ(this->blob_top_label_->channels(), 1); + EXPECT_EQ(this->blob_top_label_->height(), 1); + EXPECT_EQ(this->blob_top_label_->width(), 1); + // Go through the data 50 times + for (int iter = 0; iter < 5; ++iter) { + layer.Forward(this->blob_bottom_vec_, &this->blob_top_vec_); + for (int i = 0; i < 5; ++i) { + EXPECT_EQ(i, this->blob_top_label_->cpu_data()[i]); + } + } +} + +TYPED_TEST(ImagesLayerTest, TestShuffle) { + LayerParameter param; + param.set_batchsize(5); + param.set_source(this->filename); + param.set_shuffle_images(true); + ImagesLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, &this->blob_top_vec_); + EXPECT_EQ(this->blob_top_data_->num(), 5); + EXPECT_EQ(this->blob_top_data_->channels(), 3); + EXPECT_EQ(this->blob_top_data_->height(), 1200); + EXPECT_EQ(this->blob_top_data_->width(), 1600); + EXPECT_EQ(this->blob_top_label_->num(), 5); + EXPECT_EQ(this->blob_top_label_->channels(), 1); + EXPECT_EQ(this->blob_top_label_->height(), 1); + EXPECT_EQ(this->blob_top_label_->width(), 1); + // Go through the data 5 times + for (int iter = 0; iter < 5; ++iter) { + layer.Forward(this->blob_bottom_vec_, &this->blob_top_vec_); + for (int i = 0; i < 5; ++i) { + EXPECT_GE(this->blob_top_label_->cpu_data()[i],0); + EXPECT_LE(this->blob_top_label_->cpu_data()[i],5); + } + } +} +} -- 2.7.4