| 15 | |
| 16 | template <typename Dtype> |
| 17 | void ConcatLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom, |
| 18 | const vector<Blob<Dtype>*>& top) { |
| 19 | const int num_axes = bottom[0]->num_axes(); |
| 20 | const ConcatParameter& concat_param = this->layer_param_.concat_param(); |
| 21 | if (concat_param.has_concat_dim()) { |
| 22 | concat_axis_ = static_cast<int>(concat_param.concat_dim()); |
| 23 | // Don't allow negative indexing for concat_dim, a uint32 -- almost |
| 24 | // certainly unintended. |
| 25 | CHECK_GE(concat_axis_, 0) << "casting concat_dim from uint32 to int32 " |
| 26 | << "produced negative result; concat_dim must satisfy " |
| 27 | << "0 <= concat_dim < " << kMaxBlobAxes; |
| 28 | CHECK_LT(concat_axis_, num_axes) << "concat_dim out of range."; |
| 29 | } else { |
| 30 | concat_axis_ = bottom[0]->CanonicalAxisIndex(concat_param.axis()); |
| 31 | } |
| 32 | // Initialize with the first blob. |
| 33 | vector<int> top_shape = bottom[0]->shape(); |
| 34 | num_concats_ = bottom[0]->count(0, concat_axis_); |
| 35 | concat_input_size_ = bottom[0]->count(concat_axis_ + 1); |
| 36 | int bottom_count_sum = bottom[0]->count(); |
| 37 | for (int i = 1; i < bottom.size(); ++i) { |
| 38 | CHECK_EQ(num_axes, bottom[i]->num_axes()) |
| 39 | << "All inputs must have the same #axes."; |
| 40 | for (int j = 0; j < num_axes; ++j) { |
| 41 | if (j == concat_axis_) { continue; } |
| 42 | CHECK_EQ(top_shape[j], bottom[i]->shape(j)) |
| 43 | << "All inputs must have the same shape, except at concat_axis."; |
| 44 | } |
| 45 | bottom_count_sum += bottom[i]->count(); |
| 46 | top_shape[concat_axis_] += bottom[i]->shape(concat_axis_); |
| 47 | } |
| 48 | top[0]->Reshape(top_shape); |
| 49 | CHECK_EQ(bottom_count_sum, top[0]->count()); |
| 50 | if (bottom.size() == 1) { |
| 51 | top[0]->ShareData(*bottom[0]); |
| 52 | top[0]->ShareDiff(*bottom[0]); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | template <typename Dtype> |
| 57 | void ConcatLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, |