TYPED_TEST(EmbedLayerTest, TestForwardWithBias) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; EmbedParameter* embed_param = layer_param.mutable_embed_param(); const int kNumOutput = 10; const int kInputDim = 5; embed_param->set_num_output(kNumOutput); embed_param->set_input_dim(kInputDim); embed_param->mutable_weight_filler()->set_type("uniform"); embed_param->mutable_weight_filler()->set_min(-10); embed_param->mutable_weight_filler()->set_max(10); embed_param->mutable_bias_filler()->CopyFrom(embed_param->weight_filler()); embed_param->set_bias_term(true); shared_ptr<EmbedLayer<Dtype> > layer(new EmbedLayer<Dtype>(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); ASSERT_EQ(2, layer->blobs().size()); vector<int> weight_shape(2); weight_shape[0] = kInputDim; weight_shape[1] = kNumOutput; ASSERT_TRUE(weight_shape == layer->blobs()[0]->shape()); for (int i = 0; i < this->blob_bottom_->count(); ++i) { this->blob_bottom_->mutable_cpu_data()[i] = caffe_rng_rand() % kInputDim; } layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); vector<int> bias_offset(1, 0); vector<int> weight_offset(2, 0); vector<int> top_offset(5, 0); for (int i = 0; i < this->blob_bottom_->count(); ++i) { weight_offset[0] = static_cast<int>(this->blob_bottom_->cpu_data()[i]); weight_offset[1] = 0; top_offset[0] = i; top_offset[4] = 0; bias_offset[0] = 0; for (int j = 0; j < kNumOutput; ++j) { EXPECT_EQ(layer->blobs()[0]->data_at(weight_offset) + layer->blobs()[1]->data_at(bias_offset), this->blob_top_->data_at(top_offset)); ++top_offset[4]; ++weight_offset[1]; ++bias_offset[0]; } } }
TYPED_TEST(ConvolutionLayerTest, Test0DConvolution) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; ConvolutionParameter* convolution_param = layer_param.mutable_convolution_param(); const int kNumOutput = 3; convolution_param->set_num_output(kNumOutput); convolution_param->set_axis(3); convolution_param->mutable_weight_filler()->set_type("gaussian"); convolution_param->mutable_bias_filler()->set_type("gaussian"); shared_ptr<Layer<Dtype> > layer( new ConvolutionLayer<Dtype>(layer_param)); vector<int> top_shape = this->blob_bottom_->shape(); top_shape[3] = kNumOutput; layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); EXPECT_EQ(top_shape, this->blob_top_->shape()); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); // Check against reference convolution. vector<int> weight_offset(2); const Blob<Dtype>* weight = layer->blobs()[0].get(); const Blob<Dtype>* bias = layer->blobs()[1].get(); const int num = this->blob_top_->count(3); const int dim = this->blob_top_->shape(3); const int bottom_dim = this->blob_bottom_->shape(3); for (int n = 0; n < num; ++n) { for (int d = 0; d < dim; ++d) { weight_offset[0] = d; Dtype value = bias->cpu_data()[d]; for (int bottom_d = 0; bottom_d < bottom_dim; ++bottom_d) { weight_offset[1] = bottom_d; value += weight->data_at(weight_offset) * this->blob_bottom_->cpu_data()[n * bottom_dim + bottom_d]; } EXPECT_NEAR(value, this->blob_top_->cpu_data()[n * dim + d], 1e-4); } } }
void caffe_conv(const Blob<Dtype>* in, ConvolutionParameter* conv_param, const vector<shared_ptr<Blob<Dtype> > >& weights, Blob<Dtype>* out) { const bool has_depth = (out->num_axes() == 5); if (!has_depth) { CHECK_EQ(4, out->num_axes()); } // Kernel size, stride, and pad int kernel_h, kernel_w; if (conv_param->has_kernel_h() || conv_param->has_kernel_w()) { kernel_h = conv_param->kernel_h(); kernel_w = conv_param->kernel_w(); } else { kernel_h = kernel_w = conv_param->kernel_size(0); } int pad_h, pad_w; if (conv_param->has_pad_h() || conv_param->has_pad_w()) { pad_h = conv_param->pad_h(); pad_w = conv_param->pad_w(); } else { pad_h = pad_w = conv_param->pad_size() ? conv_param->pad(0) : 0; } int stride_h, stride_w; if (conv_param->has_stride_h() || conv_param->has_stride_w()) { stride_h = conv_param->stride_h(); stride_w = conv_param->stride_w(); } else { stride_h = stride_w = conv_param->stride_size() ? conv_param->stride(0) : 1; } int kernel_d, pad_d, stride_d; if (has_depth) { kernel_d = kernel_h; stride_d = stride_h; pad_d = pad_h; } else { kernel_d = stride_d = 1; pad_d = 0; } // Groups int groups = conv_param->group(); int o_g = out->shape(1) / groups; int k_g = in->shape(1) / groups; int o_head, k_head; // Convolution vector<int> weight_offset(4 + has_depth); vector<int> in_offset(4 + has_depth); vector<int> out_offset(4 + has_depth); Dtype* out_data = out->mutable_cpu_data(); for (int n = 0; n < out->shape(0); n++) { for (int g = 0; g < groups; g++) { o_head = o_g * g; k_head = k_g * g; for (int o = 0; o < o_g; o++) { for (int k = 0; k < k_g; k++) { for (int z = 0; z < (has_depth ? out->shape(2) : 1); z++) { for (int y = 0; y < out->shape(2 + has_depth); y++) { for (int x = 0; x < out->shape(3 + has_depth); x++) { for (int r = 0; r < kernel_d; r++) { for (int p = 0; p < kernel_h; p++) { for (int q = 0; q < kernel_w; q++) { int in_z = z * stride_d - pad_d + r; int in_y = y * stride_h - pad_h + p; int in_x = x * stride_w - pad_w + q; if (in_z >= 0 && in_z < (has_depth ? in->shape(2) : 1) && in_y >= 0 && in_y < in->shape(2 + has_depth) && in_x >= 0 && in_x < in->shape(3 + has_depth)) { weight_offset[0] = o + o_head; weight_offset[1] = k; if (has_depth) { weight_offset[2] = r; } weight_offset[2 + has_depth] = p; weight_offset[3 + has_depth] = q; in_offset[0] = n; in_offset[1] = k + k_head; if (has_depth) { in_offset[2] = in_z; } in_offset[2 + has_depth] = in_y; in_offset[3 + has_depth] = in_x; out_offset[0] = n; out_offset[1] = o + o_head; if (has_depth) { out_offset[2] = z; } out_offset[2 + has_depth] = y; out_offset[3 + has_depth] = x; out_data[out->offset(out_offset)] += in->data_at(in_offset) * weights[0]->data_at(weight_offset); } } } } } } } } } } } // Bias if (conv_param->bias_term()) { const Dtype* bias_data = weights[1]->cpu_data(); for (int n = 0; n < out->shape(0); n++) { for (int o = 0; o < out->shape(1); o++) { for (int z = 0; z < (has_depth ? out->shape(2) : 1); z++) { for (int y = 0; y < out->shape(2 + has_depth); y++) { for (int x = 0; x < out->shape(3 + has_depth); x++) { out_offset[0] = n; out_offset[1] = o; if (has_depth) { out_offset[2] = z; } out_offset[2 + has_depth] = y; out_offset[3 + has_depth] = x; out_data[out->offset(out_offset)] += bias_data[o]; } } } } } } }