| 12 | |
| 13 | template <typename Dtype> |
| 14 | void RecurrentLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, |
| 15 | const vector<Blob<Dtype>*>& top) { |
| 16 | CHECK_GE(bottom[0]->num_axes(), 2) |
| 17 | << "bottom[0] must have at least 2 axes -- (#timesteps, #streams, ...)"; |
| 18 | T_ = bottom[0]->shape(0); |
| 19 | N_ = bottom[0]->shape(1); |
| 20 | LOG(INFO) << "Initializing recurrent layer: assuming input batch contains " |
| 21 | << T_ << " timesteps of " << N_ << " independent streams."; |
| 22 | |
| 23 | CHECK_EQ(bottom[1]->num_axes(), 2) |
| 24 | << "bottom[1] must have exactly 2 axes -- (#timesteps, #streams)"; |
| 25 | CHECK_EQ(T_, bottom[1]->shape(0)); |
| 26 | CHECK_EQ(N_, bottom[1]->shape(1)); |
| 27 | |
| 28 | // If expose_hidden is set, we take as input and produce as output |
| 29 | // the hidden state blobs at the first and last timesteps. |
| 30 | expose_hidden_ = this->layer_param_.recurrent_param().expose_hidden(); |
| 31 | |
| 32 | // Get (recurrent) input/output names. |
| 33 | vector<string> output_names; |
| 34 | OutputBlobNames(&output_names); |
| 35 | vector<string> recur_input_names; |
| 36 | RecurrentInputBlobNames(&recur_input_names); |
| 37 | vector<string> recur_output_names; |
| 38 | RecurrentOutputBlobNames(&recur_output_names); |
| 39 | const int num_recur_blobs = recur_input_names.size(); |
| 40 | CHECK_EQ(num_recur_blobs, recur_output_names.size()); |
| 41 | |
| 42 | // If provided, bottom[2] is a static input to the recurrent net. |
| 43 | const int num_hidden_exposed = expose_hidden_ * num_recur_blobs; |
| 44 | static_input_ = (bottom.size() > 2 + num_hidden_exposed); |
| 45 | if (static_input_) { |
| 46 | CHECK_GE(bottom[2]->num_axes(), 1); |
| 47 | CHECK_EQ(N_, bottom[2]->shape(0)); |
| 48 | } |
| 49 | |
| 50 | // Create a NetParameter; setup the inputs that aren't unique to particular |
| 51 | // recurrent architectures. |
| 52 | NetParameter net_param; |
| 53 | |
| 54 | LayerParameter* input_layer_param = net_param.add_layer(); |
| 55 | input_layer_param->set_type("Input"); |
| 56 | InputParameter* input_param = input_layer_param->mutable_input_param(); |
| 57 | input_layer_param->add_top("x"); |
| 58 | BlobShape input_shape; |
| 59 | for (int i = 0; i < bottom[0]->num_axes(); ++i) { |
| 60 | input_shape.add_dim(bottom[0]->shape(i)); |
| 61 | } |
| 62 | input_param->add_shape()->CopyFrom(input_shape); |
| 63 | |
| 64 | input_shape.Clear(); |
| 65 | for (int i = 0; i < bottom[1]->num_axes(); ++i) { |
| 66 | input_shape.add_dim(bottom[1]->shape(i)); |
| 67 | } |
| 68 | input_layer_param->add_top("cont"); |
| 69 | input_param->add_shape()->CopyFrom(input_shape); |
| 70 | |
| 71 | if (static_input_) { |
nothing calls this directly
no test coverage detected