From eb4ca169b53e53b1b288920b2bae9db0c59b4ec2 Mon Sep 17 00:00:00 2001 From: manuele Date: Tue, 9 Dec 2014 15:12:28 +0100 Subject: [PATCH] MemoryDataLayer now correctly consumes batch_size elements --- include/caffe/data_layers.hpp | 1 + include/caffe/data_transformer.hpp | 3 +- src/caffe/data_transformer.cpp | 10 +-- src/caffe/layers/memory_data_layer.cpp | 61 ++++++++-------- src/caffe/test/test_memory_data_layer.cpp | 114 ++++++++++++++++++++++++++---- 5 files changed, 140 insertions(+), 49 deletions(-) diff --git a/include/caffe/data_layers.hpp b/include/caffe/data_layers.hpp index 117b1b5..e8c6eec 100644 --- a/include/caffe/data_layers.hpp +++ b/include/caffe/data_layers.hpp @@ -266,6 +266,7 @@ class MemoryDataLayer : public BaseDataLayer { // Reset should accept const pointers, but can't, because the memory // will be given to Blob, which is mutable void Reset(Dtype* data, Dtype* label, int n); + void ChangeBatchSize(int new_size); int batch_size() { return batch_size_; } int channels() { return channels_; } diff --git a/include/caffe/data_transformer.hpp b/include/caffe/data_transformer.hpp index c5d7a22..95062d4 100644 --- a/include/caffe/data_transformer.hpp +++ b/include/caffe/data_transformer.hpp @@ -60,9 +60,10 @@ class DataTransformer { * This is destination blob. It can be part of top blob's data if * set_cpu_data() is used. See memory_layer.cpp for an example. */ +#ifndef OSX void Transform(const vector & mat_vector, Blob* transformed_blob); - +#endif /** * @brief Applies the transformation defined in the data layer's * transform_param block to a cv::Mat diff --git a/src/caffe/data_transformer.cpp b/src/caffe/data_transformer.cpp index 3b4fd12..3e11085 100644 --- a/src/caffe/data_transformer.cpp +++ b/src/caffe/data_transformer.cpp @@ -163,8 +163,8 @@ void DataTransformer::Transform(const vector & datum_vector, const int width = transformed_blob->width(); CHECK_GT(datum_num, 0) << "There is no datum to add"; - CHECK_LE(datum_num, num) << - "The size of datum_vector must be smaller than transformed_blob->num()"; + CHECK_EQ(datum_num, num) << + "The size of datum_vector must be equals to transformed_blob->num()"; Blob uni_blob(1, channels, height, width); for (int item_id = 0; item_id < datum_num; ++item_id) { int offset = transformed_blob->offset(item_id); @@ -173,6 +173,7 @@ void DataTransformer::Transform(const vector & datum_vector, } } +#ifndef OSX template void DataTransformer::Transform(const vector & mat_vector, Blob* transformed_blob) { @@ -183,8 +184,8 @@ void DataTransformer::Transform(const vector & mat_vector, const int width = transformed_blob->width(); CHECK_GT(mat_num, 0) << "There is no MAT to add"; - CHECK_LE(mat_num, num) << - "The size of mat_vector must be smaller than transformed_blob->num()"; + CHECK_EQ(mat_num, num) << + "The size of mat_vector must be equals to transformed_blob->num()"; Blob uni_blob(1, channels, height, width); for (int item_id = 0; item_id < mat_num; ++item_id) { int offset = transformed_blob->offset(item_id); @@ -192,6 +193,7 @@ void DataTransformer::Transform(const vector & mat_vector, Transform(mat_vector[item_id], &uni_blob); } } +#endif template void DataTransformer::Transform(const cv::Mat& cv_img, diff --git a/src/caffe/layers/memory_data_layer.cpp b/src/caffe/layers/memory_data_layer.cpp index f36eb6f..214f9d8 100644 --- a/src/caffe/layers/memory_data_layer.cpp +++ b/src/caffe/layers/memory_data_layer.cpp @@ -23,6 +23,7 @@ void MemoryDataLayer::DataLayerSetUp(const vector*>& bottom, added_label_.Reshape(batch_size_, 1, 1, 1); data_ = NULL; labels_ = NULL; + needs_reshape_ = false; added_data_.cpu_data(); added_label_.cpu_data(); } @@ -32,19 +33,14 @@ void MemoryDataLayer::AddDatumVector(const vector& datum_vector) { CHECK(!has_new_data_) << "Can't add Datum when earlier ones haven't been consumed" << " by the upper layers"; - size_t num = datum_vector.size(); - if (batch_size_ != num) { - needs_reshape_ = true; - batch_size_ = num; - added_data_.Reshape(batch_size_, channels_, height_, width_); - added_label_.Reshape(batch_size_, 1, 1, 1); - } - CHECK_GT(num, 0) << "There is no datum to add"; - CHECK_LE(num, batch_size_) << - "The number of added datum must be no greater than the batch size"; - + CHECK_LE(num % batch_size_, 0) << + "The number of added datum must be multiple of the batch size"; + if (num > batch_size_) { + added_data_.Reshape(num, channels_, height_, width_); + added_label_.Reshape(num, 1, 1, 1); + } // Apply data transformations (mirror, scale, crop...) this->data_transformer_.Transform(datum_vector, &added_data_); // Copy Labels @@ -54,33 +50,24 @@ void MemoryDataLayer::AddDatumVector(const vector& datum_vector) { } // num_images == batch_size_ Dtype* top_data = added_data_.mutable_cpu_data(); - Reset(top_data, top_label, batch_size_); + Reset(top_data, top_label, num); has_new_data_ = true; } template void MemoryDataLayer::AddMatVector(const vector& mat_vector, const vector& labels) { - + size_t num = mat_vector.size(); CHECK(!has_new_data_) << "Can't add Mat when earlier ones haven't been consumed" << " by the upper layers"; - - CHECK_EQ(mat_vector.size(), labels.size()) << - "vector of labels and vector of mats need to be of the same size"; - - size_t num = mat_vector.size(); - if (batch_size_ != num) { - needs_reshape_ = true; - batch_size_ = num; - added_data_.Reshape(batch_size_, channels_, height_, width_); - added_label_.Reshape(batch_size_, 1, 1, 1); - } - + CHECK_LE(num % batch_size_, 0) << + "The number of added datum must be multiple of the batch size"; CHECK_GT(num, 0) << "There is no mat to add"; - CHECK_LE(num, batch_size_) << - "The number of added mat must be no greater than the batch size"; - + if (num > batch_size_) { + added_data_.Reshape(num, channels_, height_, width_); + added_label_.Reshape(num, 1, 1, 1); + } // Apply data transformations (mirror, scale, crop...) this->data_transformer_.Transform(mat_vector, &added_data_); // Copy Labels @@ -90,7 +77,7 @@ void MemoryDataLayer::AddMatVector(const vector& mat_vector, } // num_images == batch_size_ Dtype* top_data = added_data_.mutable_cpu_data(); - Reset(top_data, top_label, batch_size_); + Reset(top_data, top_label, num); has_new_data_ = true; } @@ -106,18 +93,30 @@ void MemoryDataLayer::Reset(Dtype* data, Dtype* labels, int n) { } template +void MemoryDataLayer::ChangeBatchSize(int new_size) { + CHECK(!has_new_data_) << + "Can't change batch_size before all data haven't been consumed" + << " by the upper layers"; + batch_size_ = new_size; + added_data_.Reshape(batch_size_, channels_, height_, width_); + added_label_.Reshape(batch_size_, 1, 1, 1); + needs_reshape_ = true; +} + +template void MemoryDataLayer::Forward_cpu(const vector*>& bottom, const vector*>& top) { CHECK(data_) << "MemoryDataLayer needs to be initalized by calling Reset"; if (needs_reshape_) { top[0]->Reshape(batch_size_, channels_, height_, width_); top[1]->Reshape(batch_size_, 1, 1, 1); + needs_reshape_ = false; } top[0]->set_cpu_data(data_ + pos_ * size_); top[1]->set_cpu_data(labels_ + pos_); pos_ = (pos_ + batch_size_) % n_; - has_new_data_ = false; - needs_reshape_ = false; + if (pos_ == 0) + has_new_data_ = false; } INSTANTIATE_CLASS(MemoryDataLayer); diff --git a/src/caffe/test/test_memory_data_layer.cpp b/src/caffe/test/test_memory_data_layer.cpp index 72b2759..bc6c9b4 100644 --- a/src/caffe/test/test_memory_data_layer.cpp +++ b/src/caffe/test/test_memory_data_layer.cpp @@ -122,11 +122,13 @@ TYPED_TEST(MemoryDataLayerTest, AddDatumVectorDefaultTransform) { memory_data_param->set_width(this->width_); MemoryDataLayer layer(param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - - vector datum_vector(this->batch_size_); + // We add batch_size*num_iter items, then for each iteration + // we forward batch_size elements + int num_iter = 5; + vector datum_vector(this->batch_size_ * num_iter); const size_t count = this->channels_ * this->height_ * this->width_; size_t pixel_index = 0; - for (int i = 0; i < this->batch_size_; ++i) { + for (int i = 0; i < this->batch_size_ * num_iter; ++i) { datum_vector[i].set_channels(this->channels_); datum_vector[i].set_height(this->height_); datum_vector[i].set_width(this->width_); @@ -137,18 +139,18 @@ TYPED_TEST(MemoryDataLayerTest, AddDatumVectorDefaultTransform) { } datum_vector[i].set_data(&(pixels[0]), count); } - layer.AddDatumVector(datum_vector); int data_index; // Go through the data 5 times - for (int iter = 0; iter < 5; ++iter) { + for (int iter = 0; iter < num_iter; ++iter) { + int offset = this->batch_size_ * iter; layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->data_blob_->cpu_data(); size_t index = 0; for (int i = 0; i < this->batch_size_; ++i) { - const string& data_string = datum_vector[i].data(); - EXPECT_EQ(i, this->label_blob_->cpu_data()[i]); + const string& data_string = datum_vector[offset + i].data(); + EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); for (int c = 0; c < this->channels_; ++c) { for (int h = 0; h < this->height_; ++h) { for (int w = 0; w < this->width_; ++w) { @@ -165,7 +167,52 @@ TYPED_TEST(MemoryDataLayerTest, AddDatumVectorDefaultTransform) { TYPED_TEST(MemoryDataLayerTest, AddMatVectorDefaultTransform) { typedef typename TypeParam::Dtype Dtype; + LayerParameter param; + MemoryDataParameter* memory_data_param = param.mutable_memory_data_param(); + memory_data_param->set_batch_size(this->batch_size_); + memory_data_param->set_channels(this->channels_); + memory_data_param->set_height(this->height_); + memory_data_param->set_width(this->width_); + MemoryDataLayer layer(param); + layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); + // We add batch_size*num_iter items, then for each iteration + // we forward batch_size elements + int num_iter = 5; + vector mat_vector(this->batch_size_ * num_iter); + vector label_vector(this->batch_size_ * num_iter); + for (int i = 0; i < this->batch_size_*num_iter; ++i) { + mat_vector[i] = cv::Mat(this->height_, this->width_, CV_8UC4); + label_vector[i] = i; + cv::randu(mat_vector[i], cv::Scalar::all(0), cv::Scalar::all(255)); + } + layer.AddMatVector(mat_vector, label_vector); + int data_index; + const size_t count = this->channels_ * this->height_ * this->width_; + for (int iter = 0; iter < num_iter; ++iter) { + int offset = this->batch_size_ * iter; + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + const Dtype* data = this->data_blob_->cpu_data(); + for (int i = 0; i < this->batch_size_; ++i) { + EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); + for (int h = 0; h < this->height_; ++h) { + const unsigned char* ptr_mat = mat_vector[offset + i].ptr(h); + int index = 0; + for (int w = 0; w < this->width_; ++w) { + for (int c = 0; c < this->channels_; ++c) { + data_index = (i*count) + (c * this->height_ + h) * this->width_ + w; + Dtype pixel = static_cast(ptr_mat[index++]); + EXPECT_EQ(static_cast(pixel), + data[data_index]); + } + } + } + } + } +} + +TYPED_TEST(MemoryDataLayerTest, TestChangeBatchSize) { + typedef typename TypeParam::Dtype Dtype; LayerParameter param; MemoryDataParameter* memory_data_param = param.mutable_memory_data_param(); memory_data_param->set_batch_size(this->batch_size_); @@ -174,23 +221,64 @@ TYPED_TEST(MemoryDataLayerTest, AddMatVectorDefaultTransform) { memory_data_param->set_width(this->width_); MemoryDataLayer layer(param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); - vector mat_vector(this->batch_size_); - vector label_vector(this->batch_size_); - for (int i = 0; i < this->batch_size_; ++i) { + // first add data as usual + int num_iter = 5; + vector mat_vector(this->batch_size_ * num_iter); + vector label_vector(this->batch_size_ * num_iter); + for (int i = 0; i < this->batch_size_*num_iter; ++i) { mat_vector[i] = cv::Mat(this->height_, this->width_, CV_8UC4); label_vector[i] = i; cv::randu(mat_vector[i], cv::Scalar::all(0), cv::Scalar::all(255)); } layer.AddMatVector(mat_vector, label_vector); + // then consume the data int data_index; const size_t count = this->channels_ * this->height_ * this->width_; - for (int iter = 0; iter < 5; ++iter) { + for (int iter = 0; iter < num_iter; ++iter) { + int offset = this->batch_size_ * iter; layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* data = this->data_blob_->cpu_data(); for (int i = 0; i < this->batch_size_; ++i) { - EXPECT_EQ(i, this->label_blob_->cpu_data()[i]); + EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); + for (int h = 0; h < this->height_; ++h) { + const unsigned char* ptr_mat = mat_vector[offset + i].ptr(h); + int index = 0; + for (int w = 0; w < this->width_; ++w) { + for (int c = 0; c < this->channels_; ++c) { + data_index = (i*count) + (c * this->height_ + h) * this->width_ + w; + Dtype pixel = static_cast(ptr_mat[index++]); + EXPECT_EQ(static_cast(pixel), + data[data_index]); + } + } + } + } + } + // and then add new data with different batch_size + int new_batch_size = 16; + layer.ChangeBatchSize(new_batch_size); + mat_vector.clear(); + mat_vector.resize(new_batch_size * num_iter); + label_vector.clear(); + label_vector.resize(new_batch_size * num_iter); + for (int i = 0; i < new_batch_size*num_iter; ++i) { + mat_vector[i] = cv::Mat(this->height_, this->width_, CV_8UC4); + label_vector[i] = i; + cv::randu(mat_vector[i], cv::Scalar::all(0), cv::Scalar::all(255)); + } + layer.AddMatVector(mat_vector, label_vector); + + // finally consume new data and check if everything is fine + for (int iter = 0; iter < num_iter; ++iter) { + int offset = new_batch_size * iter; + layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); + EXPECT_EQ(new_batch_size, this->blob_top_vec_[0]->num()); + EXPECT_EQ(new_batch_size, this->blob_top_vec_[1]->num()); + const Dtype* data = this->data_blob_->cpu_data(); + for (int i = 0; i < new_batch_size; ++i) { + EXPECT_EQ(offset + i, this->label_blob_->cpu_data()[i]); for (int h = 0; h < this->height_; ++h) { - const unsigned char* ptr_mat = mat_vector[i].ptr(h); + const unsigned char* ptr_mat = mat_vector[offset + i].ptr(h); int index = 0; for (int w = 0; w < this->width_; ++w) { for (int c = 0; c < this->channels_; ++c) { -- 2.7.4