void LTLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int cols = bottom[0]->shape()[1]; CHECK_EQ(cols, 3) << "bottom input & top output must 3"; vector<int> top_shape = bottom[0]->shape(); top[0]->Reshape(top_shape); N_ = 3; K_ = 3; M_ = bottom[0]->count(0, 1); //Linear transform matrix allocation vector<int> weight_shape(2); weight_shape[0] = N_; weight_shape[1] = K_; R.Reshape(weight_shape); vector<int> bias_shape(1, N_); T.Reshape(bias_shape); //Matrix setting Dtype RMat[9] = { -20.683149, 957.240906, 290.486237, 963.990662, -9.238551, 198.420578, 201.575638, 238.804276, -907.819397 }; Dtype TMat[3] = { 54.133713, -222.452713, 879.145020 }; caffe_copy(9, RMat, R.mutable_cpu_data()); caffe_copy(3, TMat, T.mutable_cpu_data()); }
void ConvolutionTopologyLayer<Dtype>::ConstructWeightMask() { vector<int> weight_shape(2); const int N_ = *(this->kernel_shape_.cpu_data()); weight_shape[0] = N_; weight_shape[1] = N_; topology_filter_.Reshape(weight_shape); Dtype* data = topology_filter_.mutable_cpu_data(); for(int weight_index = 0; weight_index < N_; weight_index++) { data[weight_index * N_ + weight_index] = 1; if (weight_index - 1 >= 0) data[weight_index * N_ + weight_index - 1] = 0.5; if (weight_index - 2 >= 0) data[weight_index * N_ + weight_index - 2] = 0.25; if (weight_index + 1 < N_) data[weight_index * N_ + weight_index + 1] = 0.5; if (weight_index + 2 < N_) data[weight_index* N_ + weight_index + 2] = 0.25; } }
void InnerProductLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int num_output = this->layer_param_.inner_product_param().num_output(); bias_term_ = this->layer_param_.inner_product_param().bias_term(); transpose_ = this->layer_param_.inner_product_param().transpose(); N_ = num_output; const int axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.inner_product_param().axis()); // Dimensions starting from "axis" are "flattened" into a single // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W), // and axis == 1, N inner products with dimension CHW are performed. K_ = bottom[0]->count(axis); // Check if we need to set up the weights if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize the weights vector<int> weight_shape(2); if (transpose_) { weight_shape[0] = K_; weight_shape[1] = N_; } else { weight_shape[0] = N_; weight_shape[1] = K_; } this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); // fill the weights shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, intiialize and fill the bias term if (bias_term_) { vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // parameter initialization this->param_propagate_down_.resize(this->blobs_.size(), true); //add by zhaoyang 4.18 this->has_backward_filter = this->layer_param_.inner_product_param().has_backward_filter(); if (this->has_backward_filter) { string backward_filter_path = this->layer_param_.inner_product_param().backward_filter_path(); FILE *f = fopen(backward_filter_path.c_str(), "r"); int temp; while (fscanf(f, "%d", &temp) != EOF) { this->filter.push_back((bool)temp); } } //---- }
void TopologyLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int num_output = this->layer_param_.topology_param().num_output(); bias_term_ = this->layer_param_.topology_param().bias_term(); N_ = num_output; weighted_bottom_.Reshape(bottom[0]->shape()); const int axis = bottom[0]->CanonicalAxisIndex(this->layer_param_.topology_param().axis()); // Dimensions starting from "axis" are "flattened" into a single // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W), // and axis == 1, N inner products with dimension CHW are performed. K_ = bottom[0]->count(axis); // Check if we need to set up the weights if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Intialize the weight vector<int> weight_shape(2); weight_shape[0] = N_; weight_shape[1] = K_; this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); // Fill the weights shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>(this->layer_param_.topology_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, intiialize and fill the bias term if (bias_term_) { vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>(this->layer_param_.topology_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } this->param_propagate_down_.resize(this->blobs_.size(), true); ConstructWeightMask(); }
void InnerProductDataLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int num_output = this->layer_param_.inner_product_param().num_output(); bias_term_ = this->layer_param_.inner_product_param().bias_term(); N_ = num_output; const int axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.inner_product_param().axis()); // Dimensions starting from "axis" are "flattened" into a single // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W), // and axis == 1, N inner products with dimension CHW are performed. K_ = bottom[0]->count(axis); // Check if we need to set up the weights if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Intialize the weight vector<int> weight_shape(2); weight_shape[0] = N_; weight_shape[1] = K_; this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); // fill the weights if (Caffe::getThreadId() == 0) { shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); } Dtype* weight = this->blobs_[0]->mutable_cpu_data(); MPI_Bcast(weight, this->blobs_[0]->count(), MPI_FLOAT, 0, MPI_COMM_WORLD); // If necessary, intiialize and fill the bias term if (bias_term_) { vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); if (Caffe::getThreadId() == 0) { shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } Dtype* bias = this->blobs_[1]->mutable_cpu_data(); MPI_Bcast(bias, this->blobs_[1]->count(), MPI_FLOAT, 0, MPI_COMM_WORLD); } } // parameter initialization this->param_propagate_down_.resize(this->blobs_.size(), true); }
void InnerProductLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int num_output = this->layer_param_.inner_product_param().num_output(); bias_term_ = this->layer_param_.inner_product_param().bias_term();//bool bias_term transpose_ = this->layer_param_.inner_product_param().transpose();//bool transpose_if true, transposed weights N_ = num_output;//表示全连接层输出神经元的个数 const int axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.inner_product_param().axis()); // Dimensions starting from "axis" are "flattened" into a single // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W), // and axis == 1, N inner products with dimension CHW are performed. K_ = bottom[0]->count(axis);//表示单个样本特征向量长度 // Check if we need to set up the weights if (this->blobs_.size() > 0) { //为什么blob_.size大于0就跳过参数初始化 LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) {//w blob和b blob this->blobs_.resize(2); } else { //否则只有w blob this->blobs_.resize(1); } // Initialize the weights vector<int> weight_shape(2); if (transpose_) {//如果权重被转置了 weight_shape[0] = K_; weight_shape[1] = N_; } else { weight_shape[0] = N_; weight_shape[1] = K_; } this->blobs_[0].reset(new Blob<Dtype>(weight_shape));//根据是否转置调整权重W维度 // fill the weights shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); //权重过滤器填充W过滤器 // If necessary, intiialize and fill the bias term if (bias_term_) {//有偏置项 vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape));//b blob重新调整维度 shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().bias_filler()));//得到偏置过滤器 bias_filler->Fill(this->blobs_[1].get());//权重过滤器填充 } } // parameter initialization //vector< bool > param_propagate_down_ this->param_propagate_down_.resize(this->blobs_.size(), true);//? }
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]; } } }
void WeightPlusLayer<Dtype>::LayerSetUp( const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top){ batch_ = bottom[0]->num(); dim_ = this->layer_param_.weight_plus_param().dim(); CHECK_EQ(bottom[0]->channels(), dim_) << "Weight Plus Layer: the codelenght should match."; this->blobs_.resize(1); // for the scale hashing vector<int> weight_shape(1); weight_shape[0] = dim_; this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); shared_ptr<Filler<Dtype>> weight_filler(GetFiller<Dtype>( this->layer_param_.weight_plus_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // the weight is 1 first this->param_propagate_down_.resize(this->blobs_.size(), true); weight_pow_.Reshape(dim_, 1, 1, 1); weight_two_.Reshape(dim_, 1, 1, 1); data_meta_.Reshape(batch_, dim_, 1, 1); }
void SparseInnerProductLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // three bottom blobs are: value, indices and ptr M_ = bottom[2]->count() - 1; K_ = this->layer_param_.sparse_inner_product_param().input_dim(); N_ = this->layer_param_.sparse_inner_product_param().num_output(); bias_term_ = this->layer_param_.sparse_inner_product_param().bias_term(); transpose_ = this->layer_param_.sparse_inner_product_param().transpose(); if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize the weights vector<int> weight_shape(2); if (transpose_) { weight_shape[0] = K_; weight_shape[1] = N_; } else { weight_shape[0] = N_; weight_shape[1] = K_; } this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); // fill the weights shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.sparse_inner_product_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, intiialize and fill the bias term if (bias_term_) { vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.sparse_inner_product_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // parameter initialization this->param_propagate_down_.resize(this->blobs_.size(), true); }
void TopologyLayer<Dtype>::ConstructWeightMask() { vector<int> weight_shape(2); weight_shape[0] = N_; weight_shape[1] = N_; weight_mask_.Reshape(weight_shape); Dtype* data = weight_mask_.mutable_cpu_data(); for(int weight_index = 0; weight_index < N_; weight_index++) { data[weight_index * N_ + weight_index] = 1; if (weight_index - 1 >= 0) data[weight_index * N_ + weight_index - 1] = 0.5; if (weight_index - 2 >= 0) data[weight_index * N_ + weight_index - 2] = 0.25; if (weight_index + 1 < N_) data[weight_index *N_ + weight_index + 1] = 0.5; if (weight_index + 2 < N_) data[weight_index* N_ + weight_index + 2] = 0.25; } }
void EmbedLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { N_ = this->layer_param_.embed_param().num_output(); CHECK_GT(N_, 0) << "EmbedLayer num_output must be positive."; K_ = this->layer_param_.embed_param().input_dim(); CHECK_GT(K_, 0) << "EmbedLayer input_dim must be positive."; bias_term_ = this->layer_param_.embed_param().bias_term(); // Check if we need to set up the weights if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize the weights -- // transposed from InnerProductLayer for spatial locality. vector<int> weight_shape(2); weight_shape[0] = K_; weight_shape[1] = N_; this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); // fill the weights shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.embed_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, initialize and fill the bias term if (bias_term_) { vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.embed_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // parameter initialization this->param_propagate_down_.resize(this->blobs_.size(), true); }
void RepeatLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int num_output = this->layer_param_.repeat_param().num_repeats(); N_ = num_output; const int axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.repeat_param().axis()); K_ = bottom[0]->count(axis); if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { this->blobs_.resize(1); vector<int> weight_shape(2); weight_shape[0] = N_ * K_; weight_shape[1] = K_; this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); Dtype* weight_data = this->blobs_[0]->mutable_cpu_data(); for( int i = 0; i < N_ ; i ++ ) for( int j = 0 ; j < K_ ; j ++ ) caffe_set(1, Dtype(1), weight_data + this->blobs_[0]->offset( j + i * K_, j ) ); } }
void InnerProductLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int num_output = this->layer_param_.inner_product_param().num_output(); bias_term_ = this->layer_param_.inner_product_param().bias_term(); transpose_ = this->layer_param_.inner_product_param().transpose(); // 全连接层输出神经元的个数 N_ = num_output; const int axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.inner_product_param().axis()); // K_ 单个样本特征向量长度 // Dimensions starting from "axis" are "flattened" into a single // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W), // and axis == 1, N inner products with dimension CHW are performed. K_ = bottom[0]->count(axis); // 在Caffe.proto里,LayerParameter中有一个repeated blobs field,但是在更多 // net的定义文件即prototxt文件里并没有blobs,那么在这里将进行处理__显然,如 // 果this->blobs_.size()>0那么参数blob就不需要初始化了,skip;反之,则进行初始化 // Check if we need to set up the weights if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize the weights vector<int> weight_shape(2); if (transpose_) { weight_shape[0] = K_; weight_shape[1] = N_; } else { weight_shape[0] = N_; weight_shape[1] = K_; } // 可以认为blobs_[0]的维度为N_*K_,即通常,我们将权值矩阵设为N*K维。可以 // 这么认为,但是在实际上,在C++中数据都是存放在内存中,并没有所谓的矩阵的概念 this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); // fill the weights 定义了一个智能指针 shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, intiialize and fill the bias term if (bias_term_) { vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // parameter initialization // param_propagate_down_是从Layer<Dtype> 继承来的数据成员 this->param_propagate_down_.resize(this->blobs_.size(), true); }
void CmpInnerProductLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const int num_output = this->layer_param_.inner_product_param().num_output(); bias_term_ = this->layer_param_.inner_product_param().bias_term(); transpose_ = this->layer_param_.inner_product_param().transpose(); N_ = num_output; const int axis = bottom[0]->CanonicalAxisIndex( this->layer_param_.inner_product_param().axis()); // Dimensions starting from "axis" are "flattened" into a single // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W), // and axis == 1, N inner products with dimension CHW are performed. K_ = bottom[0]->count(axis); // Check if we need to set up the weights if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize the weights vector<int> weight_shape(2); if (transpose_) { weight_shape[0] = K_; weight_shape[1] = N_; } else { weight_shape[0] = N_; weight_shape[1] = K_; } this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); // fill the weights shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, intiialize and fill the bias term if (bias_term_) { vector<int> bias_shape(1, N_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.inner_product_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // parameter initialization this->param_propagate_down_.resize(this->blobs_.size(), true); this->sparse_ratio_ = this->layer_param_.inner_product_param().sparse_ratio(); this->class_num_ = this->layer_param_.inner_product_param().class_num(); this->quantize_term_ = this->layer_param_.inner_product_param().quantize_term(); int count = this->blobs_[0]->count() ; vector<int> mask_shape(1,count); this->masks_.Reshape(mask_shape); int *mask_data = this->masks_.mutable_cpu_data(); caffe_set(count, 1, this->masks_.mutable_cpu_data()); if(quantize_term_) { this->indices_.Reshape(mask_shape); vector<int> cen_shape(1,class_num_); this->centroids_.Reshape(cen_shape); this->tmpDiff_.Reshape(cen_shape); this->freq_.Reshape(cen_shape); } }
void BaseConvolutionNDLayer<Dtype>::LayerSetUp( const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // Configure the kernel size, padding, stride, and inputs. ConvolutionParameter conv_param = this->layer_param_.convolution_param(); channel_axis_ = bottom[0]->CanonicalAxisIndex(conv_param.axis()); const int first_spatial_axis = channel_axis_ + 1; const int num_axes = bottom[0]->num_axes(); num_spatial_axes_ = num_axes - first_spatial_axis; CHECK_GE(num_spatial_axes_, 1); // Setup input dimensions (input_shape_). vector<int> bottom_dim_blob_shape(1, num_spatial_axes_ + 1); input_shape_.Reshape(bottom_dim_blob_shape); int* input_shape_data = input_shape_.mutable_cpu_data(); for (int i = 0; i < num_spatial_axes_ + 1; ++i) { input_shape_data[i] = bottom[0]->shape(channel_axis_ + i); } vector<int> spatial_dim_blob_shape(1, num_spatial_axes_); // Setup filter kernel dimensions (kernel_shape_). kernel_shape_.Reshape(spatial_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(spatial_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(spatial_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); } } // Special case: im2col is the identity for 1x1 convolution with stride 1 // and no padding, so flag for skipping the buffer and transformation. is_1x1_ = true; for (int i = 0; i < num_spatial_axes_; ++i) { is_1x1_ &= kernel_shape_data[i] == 1 && stride_data[i] == 1 && pad_data[i] == 0; if (!is_1x1_) { break; } } // Configure output channels and groups. channels_ = bottom[0]->shape(channel_axis_); num_output_ = this->layer_param_.convolution_param().num_output(); CHECK_GT(num_output_, 0); group_ = this->layer_param_.convolution_param().group(); CHECK_EQ(channels_ % group_, 0); CHECK_EQ(num_output_ % group_, 0) << "Number of output should be multiples of group."; if (reverse_dimensions()) { conv_out_channels_ = channels_; conv_in_channels_ = num_output_; } else { conv_out_channels_ = num_output_; conv_in_channels_ = channels_; } // Handle the parameters: weights and biases. // - blobs_[0] holds the filter weights // - blobs_[1] holds the biases (optional) bias_term_ = this->layer_param_.convolution_param().bias_term(); if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize and fill the weights: // output channels x input channels per-group x kernel height x kernel width vector<int> weight_shape(2); weight_shape[0] = conv_out_channels_; weight_shape[1] = conv_in_channels_ / group_; for (int i = 0; i < num_spatial_axes_; ++i) { weight_shape.push_back(kernel_shape_data[i]); } this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, initialize and fill the biases. if (bias_term_) { vector<int> bias_shape(1, num_output_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // Propagate gradients to the parameters (as directed by backward pass). this->param_propagate_down_.resize(this->blobs_.size(), true); }
SaberStatus SaberConv2DAct<X86, OpDtype, inDtype, outDtype, LayOutType_op, LayOutType_in, LayOutType_out>::init( const std::vector<DataTensor_in*>& inputs, std::vector<DataTensor_out*>& outputs, ConvActiveParam<OpTensor> ¶m, Context<X86> &ctx) { SaberStatus ret = SaberUnImplError; ConvParam<OpTensor> *conv_param = &(param.conv_param); const OpTensor *weight = conv_param->weight(); Shape weight_shape(weight->shape()); // go to different engines per different input parameters if (conv_param->group == weight_shape[0] && conv_param->group == weight_shape[1]) { // depth-wise convolution if (this->impl) { delete this->impl; } this->impl = new JitUniDWConvolution<OpDtype, inDtype, outDtype, LayOutType_op, LayOutType_in, LayOutType_out>; ret = this->impl->init(inputs, outputs, param, ctx); if (ret == SaberSuccess) { // LOG(INFO) << "++++++++++++JitUniDWConvolution"; return ret; } } else if (weight_shape[2] == 1 && weight_shape[3] == 1) { // 1x1 convolution+act if (this->impl) { delete this->impl; } this->impl = new JitAvx512Conv1x1Act<OpDtype, inDtype, outDtype, LayOutType_op, LayOutType_in, LayOutType_out>; ret = this->impl->init(inputs, outputs, param, ctx); if (ret == SaberSuccess) { // LOG(INFO) << "++++++++++++JitAvx512Conv1x1Act"; return ret; } } else if (std::is_same<LayOutType_out, NCHW_C16>::value) { if (this->impl) { delete this->impl; } this->impl = new JitAvx512ConvAct<OpDtype, inDtype, outDtype, LayOutType_op, LayOutType_in, LayOutType_out>; ret = this->impl->init(inputs, outputs, param, ctx); if (ret == SaberSuccess) { // LOG(INFO) << "++++++++++++JitAvx512ConvAct"; return ret; } } else if (std::is_same<LayOutType_out, NCHW_C8>::value) { if (this->impl) { delete this->impl; } this->impl = new JitAvx2ConvAct<OpDtype, inDtype, outDtype, LayOutType_op, LayOutType_in, LayOutType_out>; ret = this->impl->init(inputs, outputs, param, ctx); if (ret == SaberSuccess) { // LOG(INFO) << "++++++++++++JitAvx2ConvAct"; return ret; } } return SaberUnImplError; }
TYPED_TEST(ClusteringLayerTest, TestReshapeForwardForTest) { typedef typename TypeParam::Dtype Dtype; LayerParameter layer_param; ClusteringParameter* clustering_layer_param = layer_param.mutable_clustering_param(); clustering_layer_param->set_num_output(NUM_OUT); clustering_layer_param->set_total_class(1); clustering_layer_param->set_branch(false); clustering_layer_param->set_across_class(true); clustering_layer_param->set_k(K); clustering_layer_param->set_num_layer(1); ClusteringLayer<Dtype> layer(layer_param); layer.blobs().resize(K * 3); vector<int> weight_shape(2); weight_shape[0] = NUM_OUT; weight_shape[1] = CHENNAL*HEIGHT*WIDTH; vector<int> bias_shape(1, NUM_OUT); for (int i = 0; i < K * 2; ){ layer.blobs()[i++].reset(new Blob<Dtype>(weight_shape)); shared_ptr<Blob<Dtype> > & blob = layer.blobs()[i-1]; for (int c = 0; c < blob->count(); ++c){ blob->mutable_cpu_data()[c] = 1; } layer.blobs()[i++].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Blob<Dtype> > & blob1 = layer.blobs()[i-1]; for (int c = 0; c < blob1->count(); ++c){ blob1->mutable_cpu_data()[c] = 0; } } vector<int> shape(4); shape[0] = 1; shape[1] = CHENNAL; shape[2] = HEIGHT; shape[3] = WIDTH; for (int i = K * 2, v = 1; i < K * 3; v ++, i ++){ layer.blobs()[i].reset(new Blob<Dtype>(shape)); shared_ptr<Blob<Dtype> > & blob = layer.blobs()[i]; for (int c = 0; c < blob->count(); ++c){ blob->mutable_cpu_data()[c] = v; } } for (int i = 0; i < NUM; ++i){ for (int j = 0; j < CHENNAL * HEIGHT * WIDTH; ++j){ int idx = i * CHENNAL * HEIGHT * WIDTH + j; this->blob_bottom1_->mutable_cpu_data()[idx] = caffe_rng_rand() % 10; } } // let the layer caching enough data // do kmeans layer.Reshape(this->blob_bottom_vec_, this->blob_top_vec_); this->blob_bottom_vec_.clear(); this->blob_bottom_vec_.push_back(this->blob_bottom1_); for (int i = 0; i < 10; ++i){ layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_); } // LOG(ERROR) << this->blob_to_string(this->blob_bottom_vec_[0]); // LOG(ERROR) << this->blob_to_string(this->blob_top_vec_[0]); // LOG(ERROR) << " check point " ; // getchar(); }
void ConvolutionPerforatedLayer<Dtype>::LayerSetUp( const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // Configure the kernel size, padding, stride, and inputs. ConvolutionParameter conv_param = this->layer_param_.convolution_param(); if (conv_param.has_kernel_h() || conv_param.has_kernel_w()) { CHECK_EQ(0, conv_param.kernel_size_size()) << "Either kernel_size or kernel_h/w should be specified; not both."; kernel_h_ = conv_param.kernel_h(); kernel_w_ = conv_param.kernel_w(); } else { const int num_kernel_dims = conv_param.kernel_size_size(); CHECK(num_kernel_dims == 1 || num_kernel_dims == 2) << "kernel_size must be specified once, or once per spatial dimension "; kernel_h_ = conv_param.kernel_size(0); kernel_w_ = conv_param.kernel_size((num_kernel_dims == 1) ? 0 : 1); } CHECK_GT(kernel_h_, 0) << "Filter dimensions cannot be zero."; CHECK_GT(kernel_w_, 0) << "Filter dimensions cannot be zero."; // Setup stride dimensions (stride_). if (conv_param.has_stride_h() || conv_param.has_stride_w()) { CHECK_EQ(0, conv_param.stride_size()) << "Either stride or stride_h/w should be specified; not both."; stride_h_ = conv_param.stride_h(); stride_w_ = 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 == 2) << "stride must be specified once, or once per spatial dimension "; const int kDefaultStride = 1; stride_h_ = (num_stride_dims == 0) ? kDefaultStride : conv_param.stride(0); stride_w_ = (num_stride_dims == 0) ? kDefaultStride : conv_param.stride((num_stride_dims == 1) ? 0 : 1); } CHECK_GT(stride_h_, 0) << "Stride dimensions must be nonzero."; CHECK_GT(stride_w_, 0) << "Stride dimensions must be nonzero."; // Setup pad dimensions (pad_). if (conv_param.has_pad_h() || conv_param.has_pad_w()) { CHECK_EQ(0, conv_param.pad_size()) << "Either pad or pad_h/w should be specified; not both."; pad_h_ = conv_param.pad_h(); pad_w_ = 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 == 2) << "pad must be specified once, or once per spatial dimension "; const int kDefaultPad = 0; pad_h_ = (num_pad_dims == 0) ? kDefaultPad : conv_param.pad(0); pad_w_ = (num_pad_dims == 0) ? kDefaultPad : conv_param.pad((num_pad_dims == 1) ? 0 : 1); } // Configure output channels and groups. channels_ = bottom[0]->channels(); num_output_ = this->layer_param_.convolution_param().num_output(); CHECK_GT(num_output_, 0); group_ = this->layer_param_.convolution_param().group(); CHECK_EQ(channels_ % group_, 0); CHECK_EQ(num_output_ % group_, 0) << "Number of output should be multiples of group."; // Handle the parameters: weights and biases. // - blobs_[0] holds the filter weights // - blobs_[1] holds the biases (optional) vector<int> weight_shape(4); weight_shape[0] = num_output_; weight_shape[1] = channels_ / group_; weight_shape[2] = kernel_h_; weight_shape[3] = kernel_w_; bias_term_ = this->layer_param_.convolution_param().bias_term(); vector<int> bias_shape(bias_term_, num_output_); if (this->blobs_.size() > 0) { CHECK_EQ(1 + bias_term_, this->blobs_.size()) << "Incorrect number of weight blobs."; if (weight_shape != this->blobs_[0]->shape()) { Blob<Dtype> weight_shaped_blob(weight_shape); LOG(FATAL) << "Incorrect weight shape: expected shape " << weight_shaped_blob.shape_string() << "; instead, shape was " << this->blobs_[0]->shape_string(); } if (bias_term_ && bias_shape != this->blobs_[1]->shape()) { Blob<Dtype> bias_shaped_blob(bias_shape); LOG(FATAL) << "Incorrect bias shape: expected shape " << bias_shaped_blob.shape_string() << "; instead, shape was " << this->blobs_[1]->shape_string(); } LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize and fill the weights: // output channels x input channels per-group x kernel height x kernel width this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, initialize and fill the biases. if (bias_term_) { this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // Propagate gradients to the parameters (as directed by backward pass). this->param_propagate_down_.resize(this->blobs_.size(), true); }
void BaseConvolutionLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { // Configure the kernel size, padding, stride, and inputs. ConvolutionParameter conv_param = this->layer_param_.convolution_param(); force_nd_im2col_ = conv_param.force_nd_im2col(); channel_axis_ = bottom[0]->CanonicalAxisIndex(conv_param.axis()); const int num_axes = bottom[0]->num_axes(); if (num_axes == 5 && channel_axis_ == 1 && bottom[0]->shape(2) == 1) { forced_3d_ = true; } else { forced_3d_ = false; } const int first_spatial_axis = channel_axis_ + 1 + forced_3d_; num_spatial_axes_ = num_axes - first_spatial_axis; CHECK_GE(num_spatial_axes_, 0); vector<int> spatial_dim_blob_shape(1, std::max(num_spatial_axes_, 1)); // Setup filter kernel dimensions (kernel_shape_). kernel_shape_.Reshape(spatial_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(spatial_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(spatial_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); } } // Setup dilation dimensions (dilation_). dilation_.Reshape(spatial_dim_blob_shape); int* dilation_data = dilation_.mutable_cpu_data(); const int num_dilation_dims = conv_param.dilation_size(); CHECK(num_dilation_dims == 0 || num_dilation_dims == 1 || num_dilation_dims == num_spatial_axes_) << "dilation must be specified once, or once per spatial dimension " << "(dilation specified " << num_dilation_dims << " times; " << num_spatial_axes_ << " spatial dims)."; const int kDefaultDilation = 1; for (int i = 0; i < num_spatial_axes_; ++i) { dilation_data[i] = (num_dilation_dims == 0) ? kDefaultDilation : conv_param.dilation((num_dilation_dims == 1) ? 0 : i); } // Special case: im2col is the identity for 1x1 convolution with stride 1 // and no padding, so flag for skipping the buffer and transformation. is_1x1_ = true; for (int i = 0; i < num_spatial_axes_; ++i) { is_1x1_ &= kernel_shape_data[i] == 1 && stride_data[i] == 1 && pad_data[i] == 0; if (!is_1x1_) { break; } } // Configure output channels and groups. channels_ = bottom[0]->shape(channel_axis_); num_output_ = this->layer_param_.convolution_param().num_output(); CHECK_GT(num_output_, 0); group_ = this->layer_param_.convolution_param().group(); CHECK_EQ(channels_ % group_, 0); CHECK_EQ(num_output_ % group_, 0) << "Number of output should be multiples of group."; if (reverse_dimensions()) { conv_out_channels_ = channels_; conv_in_channels_ = num_output_; } else { conv_out_channels_ = num_output_; conv_in_channels_ = channels_; } // Handle the parameters: weights and biases. // - blobs_[0] holds the filter weights // - blobs_[1] holds the biases (optional) vector<int> weight_shape(2); weight_shape[0] = conv_out_channels_; weight_shape[1] = conv_in_channels_ / group_; for (int i = 0; i < num_spatial_axes_; ++i) { weight_shape.push_back(kernel_shape_data[i]); } bias_term_ = this->layer_param_.convolution_param().bias_term(); vector<int> bias_shape(bias_term_, num_output_); if (this->blobs_.size() > 0) { CHECK_EQ(1 + bias_term_, this->blobs_.size()) << "Incorrect number of weight blobs."; // true_blob_shape is original blob_shape (n,c,h,w) in case of forced_3d_ // where blob_shape is expanded to (n,c,1,h,w) vector<int> true_blob_shape = this->blobs_[0]->shape(); if (forced_3d_) true_blob_shape.erase(true_blob_shape.begin()+2); if (weight_shape != true_blob_shape) { Blob<Dtype> weight_shaped_blob(weight_shape); LOG(FATAL) << "Incorrect weight shape: expected shape " << weight_shaped_blob.shape_string() << "; instead, shape was " << this->blobs_[0]->shape_string(); } if (bias_term_ && bias_shape != this->blobs_[1]->shape()) { Blob<Dtype> bias_shaped_blob(bias_shape); LOG(FATAL) << "Incorrect bias shape: expected shape " << bias_shaped_blob.shape_string() << "; instead, shape was " << this->blobs_[1]->shape_string(); } LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize and fill the weights: // output channels x input channels per-group x kernel height x kernel width this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, initialize and fill the biases. if (bias_term_) { this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } kernel_dim_ = this->blobs_[0]->count(1); weight_offset_ = conv_out_channels_ * kernel_dim_ / group_; // Propagate gradients to the parameters (as directed by backward pass). this->param_propagate_down_.resize(this->blobs_.size(), true); }
void CudnnNdConvolutionLayer<Dtype>::LayerSetUp( const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { ConvolutionParameter conv_param = this->layer_param_.convolution_param(); // Configure the kernel size, padding, stride, and inputs. CHECK(conv_param.has_kernel_shape()) << "Kernel shape is required."; if (conv_param.has_pad_shape()) { CHECK_EQ(conv_param.kernel_shape().dim_size(), conv_param.pad_shape().dim_size()) << "Kernel and Pad shape don't match !"; } if (conv_param.has_stride_shape()) { CHECK_EQ(conv_param.kernel_shape().dim_size(), conv_param.stride_shape().dim_size()) << "Kernel and Stride shape don't match !"; } for (int i = 0; i < conv_param.kernel_shape().dim_size(); ++i) { kernel_shape_.push_back(conv_param.kernel_shape().dim(i)); CHECK_GT(kernel_shape_[i], 0) << "Filter dimensions cannot be zero."; } if (conv_param.has_pad_shape()) { for (int i = 0; i < conv_param.kernel_shape().dim_size(); ++i) { pad_shape_.push_back(conv_param.pad_shape().dim(i)); } } else { pad_shape_ = std::vector<int>(kernel_shape_.size(), 0); } if (conv_param.has_stride_shape()) { for (int i = 0; i < conv_param.kernel_shape().dim_size(); ++i) { stride_shape_.push_back(conv_param.stride_shape().dim(i)); } } else { stride_shape_ = std::vector<int>(kernel_shape_.size(), 1); } // Configure output channels and groups. channels_ = bottom[0]->shape(1); num_output_ = this->layer_param_.convolution_param().num_output(); CHECK_GT(num_output_, 0); group_ = this->layer_param_.convolution_param().group(); CHECK_EQ(channels_ % group_, 0); CHECK_EQ(num_output_ % group_, 0) << "Number of output should be multiples of group."; // Handle the parameters: weights and biases. // - blobs_[0] holds the filter weights // - blobs_[1] holds the biases (optional) bias_term_ = this->layer_param_.convolution_param().bias_term(); vector<int> weight_shape(kernel_shape_); weight_shape.insert(weight_shape.begin(), channels_ / group_); weight_shape.insert(weight_shape.begin(), num_output_); if (this->blobs_.size() > 0) { LOG(INFO) << "Skipping parameter initialization"; } else { if (bias_term_) { this->blobs_.resize(2); } else { this->blobs_.resize(1); } // Initialize and fill the weights: // output channels x input channels per-group x kernel height x kernel width this->blobs_[0].reset(new Blob<Dtype>(weight_shape)); shared_ptr<Filler<Dtype> > weight_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().weight_filler())); weight_filler->Fill(this->blobs_[0].get()); // If necessary, initialize and fill the biases. if (bias_term_) { vector<int> bias_shape(1, num_output_); this->blobs_[1].reset(new Blob<Dtype>(bias_shape)); shared_ptr<Filler<Dtype> > bias_filler(GetFiller<Dtype>( this->layer_param_.convolution_param().bias_filler())); bias_filler->Fill(this->blobs_[1].get()); } } // Propagate gradients to the parameters (as directed by backward pass). this->param_propagate_down_.resize(this->blobs_.size(), true); // Initialize CUDA streams and cuDNN. stream_ = new cudaStream_t[this->group_ * CUDNN_STREAMS_PER_GROUP]; handle_ = new cudnnHandle_t[this->group_ * CUDNN_STREAMS_PER_GROUP]; workspaceSizeInBytes = 0; workspace_data_ = NULL; for (int g = 0; g < this->group_ * CUDNN_STREAMS_PER_GROUP; g++) { CUDA_CHECK(cudaStreamCreate(&stream_[g])); CUDNN_CHECK(cudnnCreate(&handle_[g])); CUDNN_CHECK(cudnnSetStream(handle_[g], stream_[g])); } // Set the indexing parameters. weight_shape[0] /= group_; weight_offset_ = 1; for (int i = 0; i < weight_shape.size(); ++i) { weight_offset_ *= weight_shape[i]; } bias_offset_ = weight_shape[0]; // Create filter descriptor. cudnn::createNdFilterDesc<Dtype>(&filter_desc_, weight_shape); bwd_filter_algo_= new cudnnConvolutionBwdFilterAlgo_t[bottom.size()]; bwd_data_algo_ = new cudnnConvolutionBwdDataAlgo_t[bottom.size()]; workspace_bwd_filter_sizes_ = new size_t[bottom.size()]; workspace_bwd_data_sizes_ = new size_t[bottom.size()]; workspace_ = new void*[this->group_ * CUDNN_STREAMS_PER_GROUP]; // Create tensor descriptor(s) for data and corresponding convolution(s). for (int i = 0; i < bottom.size(); i++) { cudnnTensorDescriptor_t bottom_desc; cudnn::createTensorDesc<Dtype>(&bottom_desc); bottom_descs_.push_back(bottom_desc); cudnnTensorDescriptor_t top_desc; cudnn::createTensorDesc<Dtype>(&top_desc); top_descs_.push_back(top_desc); cudnnConvolutionDescriptor_t conv_desc; cudnn::createConvolutionDesc<Dtype>(&conv_desc); conv_descs_.push_back(conv_desc); workspace_bwd_data_sizes_[i] = 0; workspace_bwd_filter_sizes_[i] = 0; } // Tensor descriptor for bias. if (this->bias_term_) { cudnn::createTensorDesc<Dtype>(&bias_desc_); } handles_setup_ = true; }