TYPED_TEST(HDF5DataLayerTest, TestSkip) { typedef typename TypeParam::Dtype Dtype; LayerParameter param; param.add_top("data"); param.add_top("label"); HDF5DataParameter* hdf5_data_param = param.mutable_hdf5_data_param(); int batch_size = 5; hdf5_data_param->set_batch_size(batch_size); hdf5_data_param->set_source(*(this->filename)); Caffe::set_solver_count(8); for (int dev = 0; dev < Caffe::solver_count(); ++dev) { Caffe::set_solver_rank(dev); HDF5DataLayer<Dtype> layer(param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); int label = dev; for (int iter = 0; iter < 1; ++iter) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); for (int i = 0; i < batch_size; ++i) { EXPECT_EQ(1 + label, this->blob_top_label_->cpu_data()[i]); label = (label + Caffe::solver_count()) % (batch_size * 2); } } } Caffe::set_solver_count(1); Caffe::set_solver_rank(0); }
TYPED_TEST(HDF5DataLayerTest, TestSkip) { typedef typename TypeParam::Dtype Dtype; LayerParameter param; param.set_type("HDF5Data"); param.add_top("data"); param.add_top("label"); if (std::is_same<Dtype, half_fp>::value) { param.set_bottom_data_type(CAFFE_FLOAT); param.set_compute_data_type(CAFFE_FLOAT); param.set_top_data_type(proto_data_type<Dtype>()); } HDF5DataParameter* hdf5_data_param = param.mutable_hdf5_data_param(); int batch_size = 5; hdf5_data_param->set_batch_size(batch_size); hdf5_data_param->set_source(*(this->filename)); int_tp num_cols = 8; int_tp height = 6; int_tp width = 5; Caffe::set_solver_count(8); for (int dev = 0; dev < Caffe::solver_count(); ++dev) { Caffe::set_solver_rank(dev); shared_ptr<LayerBase> layer = CreateLayer(param); layer->SetUp(this->blob_bottom_base_vec_, this->blob_top_base_vec_); EXPECT_EQ(this->blob_top_data_->num(), batch_size); EXPECT_EQ(this->blob_top_data_->channels(), num_cols); EXPECT_EQ(this->blob_top_data_->height(), height); EXPECT_EQ(this->blob_top_data_->width(), width); EXPECT_EQ(this->blob_top_label_->num_axes(), 2); EXPECT_EQ(this->blob_top_label_->shape(0), batch_size); EXPECT_EQ(this->blob_top_label_->shape(1), 1); int label = dev; for (int iter = 0; iter < 1; ++iter) { layer->Forward(this->blob_bottom_base_vec_, this->blob_top_base_vec_, nullptr); for (int i = 0; i < batch_size; ++i) { EXPECT_EQ(1 + label, this->blob_top_label_->cpu_data()[i]); label = (label + Caffe::solver_count()) % (batch_size * 2); } } } Caffe::set_solver_count(1); Caffe::set_solver_rank(0); }
TYPED_TEST(HDF5DataLayerTest, TestRead) { typedef typename TypeParam::Dtype Dtype; this->blob_top_vec_.push_back(this->blob_top_label2_); this->blob_top_base_vec_.push_back(this->blob_top_label2_); // Create LayerParameter with the known parameters. // The data file we are reading has 10 rows and 8 columns, // with values from 0 to 10*8 reshaped in row-major order. LayerParameter param; param.set_type("HDF5Data"); param.add_top("data"); param.add_top("label"); param.add_top("label2"); if (std::is_same<Dtype, half_fp>::value) { param.set_bottom_data_type(CAFFE_FLOAT); param.set_compute_data_type(CAFFE_FLOAT); param.set_top_data_type(proto_data_type<Dtype>()); } HDF5DataParameter* hdf5_data_param = param.mutable_hdf5_data_param(); int_tp batch_size = 5; hdf5_data_param->set_batch_size(batch_size); hdf5_data_param->set_source(*(this->filename)); int_tp num_cols = 8; int_tp height = 6; int_tp width = 5; // Test that the layer setup gives correct parameters. shared_ptr<LayerBase> layer = CreateLayer(param); layer->SetUp(this->blob_bottom_base_vec_, this->blob_top_base_vec_); EXPECT_EQ(this->blob_top_data_->num(), batch_size); EXPECT_EQ(this->blob_top_data_->channels(), num_cols); EXPECT_EQ(this->blob_top_data_->height(), height); EXPECT_EQ(this->blob_top_data_->width(), width); EXPECT_EQ(this->blob_top_label_->num_axes(), 2); EXPECT_EQ(this->blob_top_label_->shape(0), batch_size); EXPECT_EQ(this->blob_top_label_->shape(1), 1); EXPECT_EQ(this->blob_top_label2_->num_axes(), 2); EXPECT_EQ(this->blob_top_label2_->shape(0), batch_size); EXPECT_EQ(this->blob_top_label2_->shape(1), 1); layer->SetUp(this->blob_bottom_base_vec_, this->blob_top_base_vec_); // Go through the data 10 times (5 batches). const int_tp data_size = num_cols * height * width; for (int_tp iter = 0; iter < 10; ++iter) { layer->Forward(this->blob_bottom_base_vec_, this->blob_top_base_vec_, nullptr); // On even iterations, we're reading the first half_fp of the data. // On odd iterations, we're reading the second half_fp of the data. // NB: label is 1-indexed int_tp label_offset = 1 + ((iter % 2 == 0) ? 0 : batch_size); int_tp label2_offset = 1 + label_offset; int_tp data_offset = (iter % 2 == 0) ? 0 : batch_size * data_size; // Every two iterations we are reading the second file, // which has the same labels, but data is offset by total data size, // which is 2400 (see generate_sample_data). int_tp file_offset = (iter % 4 < 2) ? 0 : 2400; for (int_tp i = 0; i < batch_size; ++i) { if (label_offset + i <= type_max_integer_representable<Dtype>()) { EXPECT_EQ( label_offset + i, this->blob_top_label_->cpu_data()[i]); } if (label2_offset + i <= type_max_integer_representable<Dtype>()) { EXPECT_EQ( label2_offset + i, this->blob_top_label2_->cpu_data()[i]); } } for (int_tp i = 0; i < batch_size; ++i) { for (int_tp j = 0; j < num_cols; ++j) { for (int_tp h = 0; h < height; ++h) { for (int_tp w = 0; w < width; ++w) { int_tp idx = ( i * num_cols * height * width + j * height * width + h * width + w); if (file_offset + data_offset + idx <= type_max_integer_representable<Dtype>()) { EXPECT_EQ( file_offset + data_offset + idx, this->blob_top_data_->cpu_data()[idx]) << "debug: i " << i << " j " << j << " iter " << iter; } } } } } } }
void RecurrentLayer<Dtype, MItype, MOtype>::LayerSetUp( const vector<Blob<MItype>*>& bottom, const vector<Blob<MOtype>*>& top) { CHECK_GE(bottom[0]->num_axes(), 2) << "bottom[0] must have at least 2 axes -- (#timesteps, #streams, ...)"; T_ = bottom[0]->shape(0); N_ = bottom[0]->shape(1); LOG(INFO) << "Initializing recurrent layer: assuming input batch contains " << T_ << " timesteps of " << N_ << " independent streams."; CHECK_EQ(bottom[1]->num_axes(), 2) << "bottom[1] must have exactly 2 axes -- (#timesteps, #streams)"; CHECK_EQ(T_, bottom[1]->shape(0)); CHECK_EQ(N_, bottom[1]->shape(1)); // If expose_hidden is set, we take as input and produce as output // the hidden state blobs at the first and last timesteps. expose_hidden_ = this->layer_param_.recurrent_param().expose_hidden(); // Get (recurrent) input/output names. vector<string> output_names; OutputBlobNames(&output_names); vector<string> recur_input_names; RecurrentInputBlobNames(&recur_input_names); vector<string> recur_output_names; RecurrentOutputBlobNames(&recur_output_names); const int num_recur_blobs = recur_input_names.size(); CHECK_EQ(num_recur_blobs, recur_output_names.size()); // If provided, bottom[2] is a static input to the recurrent net. const int num_hidden_exposed = expose_hidden_ * num_recur_blobs; static_input_ = (bottom.size() > 2 + num_hidden_exposed); if (static_input_) { CHECK_GE(bottom[2]->num_axes(), 1); CHECK_EQ(N_, bottom[2]->shape(0)); } // Create a NetParameter; setup the inputs that aren't unique to particular // recurrent architectures. NetParameter net_param; LayerParameter* input_layer_param = net_param.add_layer(); input_layer_param->set_type("Input"); InputParameter* input_param = input_layer_param->mutable_input_param(); input_layer_param->add_top("X"); BlobShape input_shape; for (int i = 0; i < bottom[0]->num_axes(); ++i) { input_shape.add_dim(bottom[0]->shape(i)); } input_param->add_shape()->CopyFrom(input_shape); input_shape.Clear(); for (int i = 0; i < bottom[1]->num_axes(); ++i) { input_shape.add_dim(bottom[1]->shape(i)); } input_layer_param->add_top("cont"); input_param->add_shape()->CopyFrom(input_shape); if (static_input_) { input_shape.Clear(); for (int i = 0; i < bottom[2]->num_axes(); ++i) { input_shape.add_dim(bottom[2]->shape(i)); } input_layer_param->add_top("x_static"); input_param->add_shape()->CopyFrom(input_shape); } // Call the child's FillUnrolledNet implementation to specify the unrolled // recurrent architecture. this->FillUnrolledNet(&net_param); // Prepend this layer's name to the names of each layer in the unrolled net. const string& layer_name = this->layer_param_.name(); if (layer_name.size()) { for (int i = 0; i < net_param.layer_size(); ++i) { LayerParameter* layer = net_param.mutable_layer(i); layer->set_name(layer_name + "_" + layer->name()); } } // Add "pseudo-losses" to all outputs to force backpropagation. // (Setting force_backward is too aggressive as we may not need to backprop to // all inputs, e.g., the sequence continuation indicators.) vector<string> pseudo_losses(output_names.size()); for (int i = 0; i < output_names.size(); ++i) { LayerParameter* layer = net_param.add_layer(); pseudo_losses[i] = output_names[i] + "_pseudoloss"; layer->set_name(pseudo_losses[i]); layer->set_type("Reduction"); layer->add_bottom(output_names[i]); layer->add_top(pseudo_losses[i]); layer->add_loss_weight(1); } // Create the unrolled net. unrolled_net_.reset(new Net<Dtype>(net_param, this->device_)); unrolled_net_->set_debug_info( this->layer_param_.recurrent_param().debug_info()); // Setup pointers to the inputs. x_input_blob_ = static_cast<Blob<Dtype>*>( CHECK_NOTNULL(unrolled_net_->blob_by_name("X").get())); cont_input_blob_ = static_cast<Blob<Dtype>*>( CHECK_NOTNULL(unrolled_net_->blob_by_name("cont").get())); if (static_input_) { x_static_input_blob_ = static_cast<Blob<Dtype>*>( CHECK_NOTNULL(unrolled_net_->blob_by_name("x_static").get())); } // Setup pointers to paired recurrent inputs/outputs. recur_input_blobs_.resize(num_recur_blobs); recur_output_blobs_.resize(num_recur_blobs); for (int i = 0; i < recur_input_names.size(); ++i) { recur_input_blobs_[i] = static_cast<Blob<Dtype>*>( CHECK_NOTNULL(unrolled_net_->blob_by_name(recur_input_names[i]).get())); recur_output_blobs_[i] = static_cast<Blob<Dtype>*>( CHECK_NOTNULL(unrolled_net_->blob_by_name(recur_output_names[i]).get())); } // Setup pointers to outputs. CHECK_EQ(top.size() - num_hidden_exposed, output_names.size()) << "OutputBlobNames must provide an output blob name for each top."; output_blobs_.resize(output_names.size()); for (int i = 0; i < output_names.size(); ++i) { output_blobs_[i] = static_cast<Blob<Dtype>*>( CHECK_NOTNULL(unrolled_net_->blob_by_name(output_names[i]).get())); } // We should have 2 inputs (X and cont), plus a number of recurrent inputs, // plus maybe a static input. CHECK_EQ(2 + num_recur_blobs + static_input_, unrolled_net_->input_blobs().size()); // This layer's parameters are any parameters in the layers of the unrolled // net. We only want one copy of each parameter, so check that the parameter // is "owned" by the layer, rather than shared with another. this->blobs_.clear(); for (int i = 0; i < unrolled_net_->params().size(); ++i) { if (unrolled_net_->param_owners()[i] == -1) { LOG(INFO) << "Adding parameter " << i << ": " << unrolled_net_->param_display_names()[i]; this->blobs_.push_back( static_pointer_cast<Blob<Dtype> >(unrolled_net_->params()[i])); } } // Check that param_propagate_down is set for all of the parameters in the // unrolled net; set param_propagate_down to true in this layer. for (int i = 0; i < unrolled_net_->layers().size(); ++i) { for (int j = 0; j < unrolled_net_->layers()[i]->blobs_size(); ++j) { CHECK(unrolled_net_->layers()[i]->param_propagate_down(j)) << "param_propagate_down not set for layer " << i << ", param " << j; } } this->param_propagate_down_.clear(); this->param_propagate_down_.resize(this->blobs_.size(), true); // Set the diffs of recurrent outputs to 0 -- we can't backpropagate across // batches. for (int i = 0; i < recur_output_blobs_.size(); ++i) { caffe_set(recur_output_blobs_[i]->count(), Dtype(0), recur_output_blobs_[i]->mutable_cpu_diff()); } // Check that the last output_names.size() layers are the pseudo-losses; // set last_layer_index so that we don't actually run these layers. const vector<string>& layer_names = unrolled_net_->layer_names(); last_layer_index_ = layer_names.size() - 1 - pseudo_losses.size(); for (int i = last_layer_index_ + 1, j = 0; i < layer_names.size(); ++i, ++j) { CHECK_EQ(layer_names[i], pseudo_losses[j]); } this->InitializeQuantizers(bottom, top); }
TYPED_TEST(HDF5DataLayerTest, TestRead) { typedef typename TypeParam::Dtype Dtype; // Create LayerParameter with the known parameters. // The data file we are reading has 10 rows and 8 columns, // with values from 0 to 10*8 reshaped in row-major order. LayerParameter param; param.add_top("data"); param.add_top("label"); param.add_top("label2"); HDF5DataParameter* hdf5_data_param = param.mutable_hdf5_data_param(); int batch_size = 5; hdf5_data_param->set_batch_size(batch_size); hdf5_data_param->set_source(*(this->filename)); int num_cols = 8; int height = 6; int width = 5; // Test that the layer setup got the correct parameters. HDF5DataLayer<Dtype> layer(param); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); EXPECT_EQ(this->blob_top_data_->num(), batch_size); EXPECT_EQ(this->blob_top_data_->channels(), num_cols); EXPECT_EQ(this->blob_top_data_->height(), height); EXPECT_EQ(this->blob_top_data_->width(), width); EXPECT_EQ(this->blob_top_label_->num_axes(), 2); EXPECT_EQ(this->blob_top_label_->shape(0), batch_size); EXPECT_EQ(this->blob_top_label_->shape(1), 1); EXPECT_EQ(this->blob_top_label2_->num_axes(), 2); EXPECT_EQ(this->blob_top_label2_->shape(0), batch_size); EXPECT_EQ(this->blob_top_label2_->shape(1), 1); layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_); // Go through the data 10 times (5 batches). const int data_size = num_cols * height * width; for (int iter = 0; iter < 10; ++iter) { layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); // On even iterations, we're reading the first half of the data. // On odd iterations, we're reading the second half of the data. // NB: label is 1-indexed int label_offset = 1 + ((iter % 2 == 0) ? 0 : batch_size); int label2_offset = 1 + label_offset; int data_offset = (iter % 2 == 0) ? 0 : batch_size * data_size; // Every two iterations we are reading the second file, // which has the same labels, but data is offset by total data size, // which is 2400 (see generate_sample_data). int file_offset = (iter % 4 < 2) ? 0 : 2400; for (int i = 0; i < batch_size; ++i) { EXPECT_EQ( label_offset + i, this->blob_top_label_->cpu_data()[i]); EXPECT_EQ( label2_offset + i, this->blob_top_label2_->cpu_data()[i]); } for (int i = 0; i < batch_size; ++i) { for (int j = 0; j < num_cols; ++j) { for (int h = 0; h < height; ++h) { for (int w = 0; w < width; ++w) { int idx = ( i * num_cols * height * width + j * height * width + h * width + w); EXPECT_EQ( file_offset + data_offset + idx, this->blob_top_data_->cpu_data()[idx]) << "debug: i " << i << " j " << j << " iter " << iter; } } } } } }