| 10 | |
| 11 | template <typename Dtype> |
| 12 | void BaseConvolutionLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, |
| 13 | const vector<Blob<Dtype>*>& top) { |
| 14 | // Configure the kernel size, padding, stride, and inputs. |
| 15 | ConvolutionParameter conv_param = this->layer_param_.convolution_param(); |
| 16 | force_nd_im2col_ = conv_param.force_nd_im2col(); |
| 17 | channel_axis_ = bottom[0]->CanonicalAxisIndex(conv_param.axis()); |
| 18 | const int first_spatial_axis = channel_axis_ + 1; |
| 19 | const int num_axes = bottom[0]->num_axes(); |
| 20 | num_spatial_axes_ = num_axes - first_spatial_axis; |
| 21 | CHECK_GE(num_spatial_axes_, 0); |
| 22 | vector<int> bottom_dim_blob_shape(1, num_spatial_axes_ + 1); |
| 23 | vector<int> spatial_dim_blob_shape(1, std::max(num_spatial_axes_, 1)); |
| 24 | // Setup filter kernel dimensions (kernel_shape_). |
| 25 | kernel_shape_.Reshape(spatial_dim_blob_shape); |
| 26 | int* kernel_shape_data = kernel_shape_.mutable_cpu_data(); |
| 27 | if (conv_param.has_kernel_h() || conv_param.has_kernel_w()) { |
| 28 | CHECK_EQ(num_spatial_axes_, 2) |
| 29 | << "kernel_h & kernel_w can only be used for 2D convolution."; |
| 30 | CHECK_EQ(0, conv_param.kernel_size_size()) |
| 31 | << "Either kernel_size or kernel_h/w should be specified; not both."; |
| 32 | kernel_shape_data[0] = conv_param.kernel_h(); |
| 33 | kernel_shape_data[1] = conv_param.kernel_w(); |
| 34 | } else { |
| 35 | const int num_kernel_dims = conv_param.kernel_size_size(); |
| 36 | CHECK(num_kernel_dims == 1 || num_kernel_dims == num_spatial_axes_) |
| 37 | << "kernel_size must be specified once, or once per spatial dimension " |
| 38 | << "(kernel_size specified " << num_kernel_dims << " times; " |
| 39 | << num_spatial_axes_ << " spatial dims)."; |
| 40 | for (int i = 0; i < num_spatial_axes_; ++i) { |
| 41 | kernel_shape_data[i] = |
| 42 | conv_param.kernel_size((num_kernel_dims == 1) ? 0 : i); |
| 43 | } |
| 44 | } |
| 45 | for (int i = 0; i < num_spatial_axes_; ++i) { |
| 46 | CHECK_GT(kernel_shape_data[i], 0) << "Filter dimensions must be nonzero."; |
| 47 | } |
| 48 | // Setup stride dimensions (stride_). |
| 49 | stride_.Reshape(spatial_dim_blob_shape); |
| 50 | int* stride_data = stride_.mutable_cpu_data(); |
| 51 | if (conv_param.has_stride_h() || conv_param.has_stride_w()) { |
| 52 | CHECK_EQ(num_spatial_axes_, 2) |
| 53 | << "stride_h & stride_w can only be used for 2D convolution."; |
| 54 | CHECK_EQ(0, conv_param.stride_size()) |
| 55 | << "Either stride or stride_h/w should be specified; not both."; |
| 56 | stride_data[0] = conv_param.stride_h(); |
| 57 | stride_data[1] = conv_param.stride_w(); |
| 58 | } else { |
| 59 | const int num_stride_dims = conv_param.stride_size(); |
| 60 | CHECK(num_stride_dims == 0 || num_stride_dims == 1 || |
| 61 | num_stride_dims == num_spatial_axes_) |
| 62 | << "stride must be specified once, or once per spatial dimension " |
| 63 | << "(stride specified " << num_stride_dims << " times; " |
| 64 | << num_spatial_axes_ << " spatial dims)."; |
| 65 | const int kDefaultStride = 1; |
| 66 | for (int i = 0; i < num_spatial_axes_; ++i) { |
| 67 | stride_data[i] = (num_stride_dims == 0) ? kDefaultStride : |
| 68 | conv_param.stride((num_stride_dims == 1) ? 0 : i); |
| 69 | CHECK_GT(stride_data[i], 0) << "Stride dimensions must be nonzero."; |
nothing calls this directly
no test coverage detected