| 184 | |
| 185 | template <typename Dtype> |
| 186 | void BaseConvolutionLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom, |
| 187 | const vector<Blob<Dtype>*>& top) { |
| 188 | const int first_spatial_axis = channel_axis_ + 1; |
| 189 | CHECK_EQ(bottom[0]->num_axes(), first_spatial_axis + num_spatial_axes_) |
| 190 | << "bottom num_axes may not change."; |
| 191 | num_ = bottom[0]->count(0, channel_axis_); |
| 192 | CHECK_EQ(bottom[0]->shape(channel_axis_), channels_) |
| 193 | << "Input size incompatible with convolution kernel."; |
| 194 | // TODO: generalize to handle inputs of different shapes. |
| 195 | for (int bottom_id = 1; bottom_id < bottom.size(); ++bottom_id) { |
| 196 | CHECK(bottom[0]->shape() == bottom[bottom_id]->shape()) |
| 197 | << "All inputs must have the same shape."; |
| 198 | } |
| 199 | // Shape the tops. |
| 200 | bottom_shape_ = &bottom[0]->shape(); |
| 201 | compute_output_shape(); |
| 202 | vector<int> top_shape(bottom[0]->shape().begin(), |
| 203 | bottom[0]->shape().begin() + channel_axis_); |
| 204 | top_shape.push_back(num_output_); |
| 205 | for (int i = 0; i < num_spatial_axes_; ++i) { |
| 206 | top_shape.push_back(output_shape_[i]); |
| 207 | } |
| 208 | for (int top_id = 0; top_id < top.size(); ++top_id) { |
| 209 | top[top_id]->Reshape(top_shape); |
| 210 | } |
| 211 | if (reverse_dimensions()) { |
| 212 | conv_out_spatial_dim_ = bottom[0]->count(first_spatial_axis); |
| 213 | } else { |
| 214 | conv_out_spatial_dim_ = top[0]->count(first_spatial_axis); |
| 215 | } |
| 216 | col_offset_ = kernel_dim_ * conv_out_spatial_dim_; |
| 217 | output_offset_ = conv_out_channels_ * conv_out_spatial_dim_ / group_; |
| 218 | // Setup input dimensions (conv_input_shape_). |
| 219 | vector<int> bottom_dim_blob_shape(1, num_spatial_axes_ + 1); |
| 220 | conv_input_shape_.Reshape(bottom_dim_blob_shape); |
| 221 | int* conv_input_shape_data = conv_input_shape_.mutable_cpu_data(); |
| 222 | for (int i = 0; i < num_spatial_axes_ + 1; ++i) { |
| 223 | if (reverse_dimensions()) { |
| 224 | conv_input_shape_data[i] = top[0]->shape(channel_axis_ + i); |
| 225 | } else { |
| 226 | conv_input_shape_data[i] = bottom[0]->shape(channel_axis_ + i); |
| 227 | } |
| 228 | } |
| 229 | // The im2col result buffer will only hold one image at a time to avoid |
| 230 | // overly large memory usage. In the special case of 1x1 convolution |
| 231 | // it goes lazily unused to save memory. |
| 232 | col_buffer_shape_.clear(); |
| 233 | col_buffer_shape_.push_back(kernel_dim_ * group_); |
| 234 | for (int i = 0; i < num_spatial_axes_; ++i) { |
| 235 | if (reverse_dimensions()) { |
| 236 | col_buffer_shape_.push_back(input_shape(i + 1)); |
| 237 | } else { |
| 238 | col_buffer_shape_.push_back(output_shape_[i]); |
| 239 | } |
| 240 | } |
| 241 | col_buffer_.Reshape(col_buffer_shape_); |
| 242 | bottom_dim_ = bottom[0]->count(channel_axis_); |
| 243 | top_dim_ = top[0]->count(channel_axis_); |
no test coverage detected