Renamed input_layer to images_layer
authorsguada <sguada@gmail.com>
Mon, 17 Feb 2014 18:08:39 +0000 (10:08 -0800)
committersguada <sguada@gmail.com>
Mon, 17 Feb 2014 18:32:37 +0000 (10:32 -0800)
src/caffe/layer_factory.cpp
src/caffe/layers/images_layer.cpp [moved from src/caffe/layers/input_layer.cpp with 88% similarity]
src/caffe/proto/caffe.proto
src/caffe/test/test_images_layer.cpp [new file with mode: 0644]

index 7e2a3c8..61d0e0d 100644 (file)
@@ -27,8 +27,8 @@ Layer<Dtype>* GetLayer(const LayerParameter& param) {
     return new ConvolutionLayer<Dtype>(param);
   } else if (type == "data") {
     return new DataLayer<Dtype>(param);
-  } else if (type == "input") {
-    return new InputLayer<Dtype>(param);
+  } else if (type == "images") {
+    return new ImagesLayer<Dtype>(param);
   } else if (type == "dropout") {
     return new DropoutLayer<Dtype>(param);
   } else if (type == "euclidean_loss") {
similarity index 88%
rename from src/caffe/layers/input_layer.cpp
rename to src/caffe/layers/images_layer.cpp
index db3d634..f600dbc 100644 (file)
@@ -19,9 +19,9 @@ using std::pair;
 namespace caffe {
 
 template <typename Dtype>
-void* InputLayerPrefetch(void* layer_pointer) {
+void* ImagesLayerPrefetch(void* layer_pointer) {
   CHECK(layer_pointer);
-  InputLayer<Dtype>* layer = reinterpret_cast<InputLayer<Dtype>*>(layer_pointer);
+  ImagesLayer<Dtype>* layer = reinterpret_cast<ImagesLayer<Dtype>*>(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 <typename Dtype>
-InputLayer<Dtype>::~InputLayer<Dtype>() {
+ImagesLayer<Dtype>::~ImagesLayer<Dtype>() {
   // Finally, join the thread
   CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
 }
 
 template <typename Dtype>
-void InputLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
+void ImagesLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* 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<Dtype>::SetUp(const vector<Blob<Dtype>*>& 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<Dtype>::SetUp(const vector<Blob<Dtype>*>& 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<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
   prefetch_label_->mutable_cpu_data();
   data_mean_.cpu_data();
   DLOG(INFO) << "Initializing prefetch";
-  CHECK(!pthread_create(&thread_, NULL, InputLayerPrefetch<Dtype>,
+  CHECK(!pthread_create(&thread_, NULL, ImagesLayerPrefetch<Dtype>,
       reinterpret_cast<void*>(this))) << "Pthread execution failed.";
   DLOG(INFO) << "Prefetch initialized.";
 }
 
 template <typename Dtype>
-void InputLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
+void ImagesLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
   // First, join the thread
   CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
@@ -231,12 +233,12 @@ void InputLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& 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<Dtype>,
+  CHECK(!pthread_create(&thread_, NULL, ImagesLayerPrefetch<Dtype>,
       reinterpret_cast<void*>(this))) << "Pthread execution failed.";
 }
 
 template <typename Dtype>
-void InputLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
+void ImagesLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
       vector<Blob<Dtype>*>* top) {
   // First, join the thread
   CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
@@ -248,23 +250,23 @@ void InputLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
       prefetch_label_->cpu_data(), sizeof(Dtype) * prefetch_label_->count(),
       cudaMemcpyHostToDevice));
   // Start a new prefetch thread
-  CHECK(!pthread_create(&thread_, NULL, InputLayerPrefetch<Dtype>,
+  CHECK(!pthread_create(&thread_, NULL, ImagesLayerPrefetch<Dtype>,
       reinterpret_cast<void*>(this))) << "Pthread execution failed.";
 }
 
 // The backward operations are dummy - they do not carry any computation.
 template <typename Dtype>
-Dtype InputLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
+Dtype ImagesLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
       const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
   return Dtype(0.);
 }
 
 template <typename Dtype>
-Dtype InputLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
+Dtype ImagesLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
       const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
   return Dtype(0.);
 }
 
-INSTANTIATE_CLASS(InputLayer);
+INSTANTIATE_CLASS(ImagesLayer);
 
 }  // namespace caffe
index dd09b73..d9a5524 100644 (file)
@@ -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 (file)
index 0000000..f98df37
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright 2014 Sergio Guadarrama
+
+#include <cuda_runtime.h>
+#include <iostream>
+#include <fstream>
+
+#include <string>
+
+#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 <typename Dtype>
+class ImagesLayerTest : public ::testing::Test {
+ protected:
+  ImagesLayerTest()
+      : blob_top_data_(new Blob<Dtype>()),
+        blob_top_label_(new Blob<Dtype>()),
+        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<Dtype>* const blob_top_data_;
+  Blob<Dtype>* const blob_top_label_;
+  vector<Blob<Dtype>*> blob_bottom_vec_;
+  vector<Blob<Dtype>*> blob_top_vec_;
+};
+
+typedef ::testing::Types<float, double> 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<TypeParam> 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<TypeParam> 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<TypeParam> 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);
+    }
+  }
+}
+}