void Im2colLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { ConvolutionParameter conv_param = this->layer_param_.convolution_param(); force_nd_im2col_ = conv_param.force_nd_im2col(); const int input_num_dims = bottom[0]->shape().size(); channel_axis_ = bottom[0]->CanonicalAxisIndex(conv_param.axis()); const int first_spatial_dim = channel_axis_ + 1; num_spatial_axes_ = input_num_dims - first_spatial_dim; CHECK_GE(num_spatial_axes_, 1); vector<int> dim_blob_shape(1, num_spatial_axes_); // Setup filter kernel dimensions (kernel_shape_). kernel_shape_.Reshape(dim_blob_shape); int* kernel_shape_data = kernel_shape_.mutable_cpu_data(); if (conv_param.has_kernel_h() || conv_param.has_kernel_w()) { CHECK_EQ(num_spatial_axes_, 2) << "kernel_h & kernel_w can only be used for 2D convolution."; CHECK_EQ(0, conv_param.kernel_size_size()) << "Either kernel_size or kernel_h/w should be specified; not both."; kernel_shape_data[0] = conv_param.kernel_h(); kernel_shape_data[1] = conv_param.kernel_w(); } else { const int num_kernel_dims = conv_param.kernel_size_size(); CHECK(num_kernel_dims == 1 || num_kernel_dims == num_spatial_axes_) << "kernel_size must be specified once, or once per spatial dimension " << "(kernel_size specified " << num_kernel_dims << " times; " << num_spatial_axes_ << " spatial dims);"; for (int i = 0; i < num_spatial_axes_; ++i) { kernel_shape_data[i] = conv_param.kernel_size((num_kernel_dims == 1) ? 0 : i); } } for (int i = 0; i < num_spatial_axes_; ++i) { CHECK_GT(kernel_shape_data[i], 0) << "Filter dimensions must be nonzero."; } // Setup stride dimensions (stride_). stride_.Reshape(dim_blob_shape); int* stride_data = stride_.mutable_cpu_data(); if (conv_param.has_stride_h() || conv_param.has_stride_w()) { CHECK_EQ(num_spatial_axes_, 2) << "stride_h & stride_w can only be used for 2D convolution."; CHECK_EQ(0, conv_param.stride_size()) << "Either stride or stride_h/w should be specified; not both."; stride_data[0] = conv_param.stride_h(); stride_data[1] = conv_param.stride_w(); } else { const int num_stride_dims = conv_param.stride_size(); CHECK(num_stride_dims == 0 || num_stride_dims == 1 || num_stride_dims == num_spatial_axes_) << "stride must be specified once, or once per spatial dimension " << "(stride specified " << num_stride_dims << " times; " << num_spatial_axes_ << " spatial dims);"; const int kDefaultStride = 1; for (int i = 0; i < num_spatial_axes_; ++i) { stride_data[i] = (num_stride_dims == 0) ? kDefaultStride : conv_param.stride((num_stride_dims == 1) ? 0 : i); CHECK_GT(stride_data[i], 0) << "Stride dimensions must be nonzero."; } } // Setup pad dimensions (pad_). pad_.Reshape(dim_blob_shape); int* pad_data = pad_.mutable_cpu_data(); if (conv_param.has_pad_h() || conv_param.has_pad_w()) { CHECK_EQ(num_spatial_axes_, 2) << "pad_h & pad_w can only be used for 2D convolution."; CHECK_EQ(0, conv_param.pad_size()) << "Either pad or pad_h/w should be specified; not both."; pad_data[0] = conv_param.pad_h(); pad_data[1] = conv_param.pad_w(); } else { const int num_pad_dims = conv_param.pad_size(); CHECK(num_pad_dims == 0 || num_pad_dims == 1 || num_pad_dims == num_spatial_axes_) << "pad must be specified once, or once per spatial dimension " << "(pad specified " << num_pad_dims << " times; " << num_spatial_axes_ << " spatial dims);"; const int kDefaultPad = 0; for (int i = 0; i < num_spatial_axes_; ++i) { pad_data[i] = (num_pad_dims == 0) ? kDefaultPad : conv_param.pad((num_pad_dims == 1) ? 0 : i); } } }
void CropLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // Calculate number of spatial axis CropParameter crop_param = this->layer_param_.crop_param(); channel_axis_ = bottom[0]->CanonicalAxisIndex(crop_param.axis()); channels_ = bottom[0]->shape(channel_axis_); const int first_spatial_axis = channel_axis_ + 1; num_axes_ = bottom[0]->num_axes(); num_spatial_axes_ = num_axes_ - first_spatial_axis; CHECK_GE(num_spatial_axes_, 1); vector<int> dim_blob_shape(1, num_axes_); // Construct a map from top blobs to layer inds, skipping over in-place // connections. CHECK(this->net_!=NULL) << "Crop Layer must be used in a net"; map<Blob<Dtype>*, int> down_map; for (int layer_ind = 0; layer_ind < this->net_->top_vecs().size(); ++layer_ind) { vector<Blob<Dtype>*> tops = this->net_->top_vecs()[layer_ind]; for (int top_ind = 0; top_ind < tops.size(); ++top_ind) { if (down_map.find(tops[top_ind]) == down_map.end()) { down_map[tops[top_ind]] = layer_ind; } } } // Walk back from the first bottom, keeping track of all the blobs we pass. set<Blob<Dtype>*> path_blobs; Blob<Dtype>* blob = bottom[0]; int layer_ind; // TODO this logic can be simplified if all blobs are tops path_blobs.insert(blob); while (down_map.find(blob) != down_map.end()) { layer_ind = down_map[blob]; if (this->net_->bottom_vecs()[layer_ind].size() == 0) { break; } blob = this->net_->bottom_vecs()[layer_ind][0]; path_blobs.insert(blob); } // Now walk back from the second bottom, until we find a blob of intersection. Blob<Dtype>* inter_blob = bottom[1]; while (path_blobs.find(inter_blob) == path_blobs.end()) { CHECK(down_map.find(inter_blob) != down_map.end()) << "Cannot align apparently disconnected blobs."; layer_ind = down_map[inter_blob]; CHECK_GT(this->net_->bottom_vecs()[layer_ind].size(), 0) << "Cannot align apparently disconnected blobs."; inter_blob = this->net_->bottom_vecs()[layer_ind][0]; } // Compute the coord map from the blob of intersection to each bottom. vector<DiagonalAffineMap<Dtype> > coord_maps(2, DiagonalAffineMap<Dtype>::identity(num_spatial_axes_)); for (int i = 0; i < 2; ++i) { for (Blob<Dtype>* blob = bottom[i]; blob != inter_blob; blob = this->net_->bottom_vecs()[down_map[blob]][0]) { shared_ptr<Layer<Dtype> > layer = this->net_->layers()[down_map[blob]]; // printf("[%d] %s\n",i,layer->type()); coord_maps[i] = coord_maps[i].compose(layer->coord_map(num_spatial_axes_)); // printf("done [%d] %s\n",i,layer->type()); } } // Compute the mapping from first bottom coordinates to second. crop_.Reshape(dim_blob_shape); top_shape_.Reshape(dim_blob_shape); bottom_shape_.Reshape(dim_blob_shape); int* crop_data = crop_.mutable_cpu_data(); int* top_shape_data = top_shape_.mutable_cpu_data(); int* bottom_shape_data = bottom_shape_.mutable_cpu_data(); // printf("maps %d %d \n",coord_maps[0].size(), coord_maps[1].size()); DiagonalAffineMap<Dtype> crop_map = coord_maps[1].compose(coord_maps[0].inv()); // printf("Done compute map \n"); // printf("num_axes_ %d \n",num_axes_); caffe_set(num_axes_, static_cast<int>(0), crop_data); for (int i = 0; i < num_spatial_axes_; ++i) { // Check for scale mismatch (unfortunately, CHECK_DOUBLE_EQ does not // support a message like the other CHECKs). CHECK_DOUBLE_EQ(crop_map.coefs()[i].first, 1); CHECK_LE(crop_map.coefs()[i].second, 0) << "Negative crop width."; // Check that the crop width is an integer. CHECK_DOUBLE_EQ(crop_map.coefs()[i].second, round(crop_map.coefs()[i].second)); crop_data[first_spatial_axis+i] = - round(crop_map.coefs()[i].second); } // printf("shapes \n"); for (int i = 0; i < channel_axis_+1; ++i) { bottom_shape_data[i] = bottom[0]->shape(i); top_shape_data[i] = bottom[0]->shape(i); } // printf("shapes2 \n"); for (int i = 0; i < num_spatial_axes_; ++i) { bottom_shape_data[first_spatial_axis+i] = bottom[0]->shape(first_spatial_axis+i); top_shape_data[first_spatial_axis+i] = bottom[1]->shape(first_spatial_axis+i); } // printf("line size \n"); line_size_ = top_shape_data[num_axes_-1]; // printf("done \n"); }