void ReductionLayer<Dtype>::Forward_cpu( const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const Dtype* bottom_data = bottom[0]->cpu_data(); const Dtype* mult_data = NULL; if (sum_multiplier_.count() > 0) { mult_data = sum_multiplier_.cpu_data(); } Dtype* top_data = top[0]->mutable_cpu_data(); for (int i = 0; i < num_; ++i) { switch (op_) { case ReductionParameter_ReductionOp_SUM: case ReductionParameter_ReductionOp_MEAN: *top_data = caffe_cpu_dot(dim_, mult_data, bottom_data); break; case ReductionParameter_ReductionOp_ASUM: *top_data = caffe_cpu_asum(dim_, bottom_data); break; case ReductionParameter_ReductionOp_SUMSQ: *top_data = caffe_cpu_dot(dim_, bottom_data, bottom_data); break; default: LOG(FATAL) << "Unknown reduction op: " << ReductionParameter_ReductionOp_Name(op_); } bottom_data += dim_; ++top_data; } if (coeff_ != Dtype(1)) { // Reset the top_data pointer. top_data = top[0]->mutable_cpu_data(); caffe_scal(num_, coeff_, top_data); } }
void TestForward(ReductionParameter_ReductionOp op, float coeff = 1, int_tp axis = 0) { LayerParameter layer_param; ReductionParameter* reduction_param = layer_param.mutable_reduction_param(); reduction_param->set_operation(op); if (coeff != 1.0) { reduction_param->set_coeff(coeff); } if (axis != 0) { reduction_param->set_axis(axis); } shared_ptr<ReductionLayer<Dtype> > layer( new ReductionLayer<Dtype>(layer_param)); layer->SetUp(this->blob_bottom_vec_, this->blob_top_vec_); layer->Forward(this->blob_bottom_vec_, this->blob_top_vec_); const Dtype* in_data = this->blob_bottom_->cpu_data(); const int_tp num = this->blob_bottom_->count(0, axis); const int_tp dim = this->blob_bottom_->count(axis); for (int_tp n = 0; n < num; ++n) { Dtype expected_result = 0; for (int_tp d = 0; d < dim; ++d) { switch (op) { case ReductionParameter_ReductionOp_SUM: expected_result += *in_data; break; case ReductionParameter_ReductionOp_MEAN: expected_result += *in_data / dim; break; case ReductionParameter_ReductionOp_ASUM: expected_result += fabs(*in_data); break; case ReductionParameter_ReductionOp_SUMSQ: expected_result += (*in_data) * (*in_data); break; default: LOG(FATAL) << "Unknown reduction op: " << ReductionParameter_ReductionOp_Name(op); } ++in_data; } expected_result *= coeff; const Dtype computed_result = this->blob_top_->cpu_data()[n]; EXPECT_FLOAT_EQ(expected_result, computed_result) << "Incorrect result computed with op " << ReductionParameter_ReductionOp_Name(op) << ", coeff " << coeff; } }
void ReductionLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { if (!propagate_down[0]) { return; } // Get bottom_data, if needed. const Dtype* bottom_data = NULL; switch (op_) { // Operations that don't need bottom_data case ReductionParameter_ReductionOp_SUM: case ReductionParameter_ReductionOp_MEAN: break; // Operations that need bottom_data case ReductionParameter_ReductionOp_ASUM: case ReductionParameter_ReductionOp_SUMSQ: bottom_data = bottom[0]->cpu_data(); break; default: LOG(FATAL) << "Unknown reduction op: " << ReductionParameter_ReductionOp_Name(op_); } const Dtype* top_diff = top[0]->cpu_diff(); Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); for (int i = 0; i < num_; ++i) { Dtype bottom_coeff = (*top_diff) * coeff_; if (op_ == ReductionParameter_ReductionOp_MEAN) { bottom_coeff /= dim_; } switch (op_) { case ReductionParameter_ReductionOp_SUM: case ReductionParameter_ReductionOp_MEAN: caffe_set(dim_, bottom_coeff, bottom_diff); break; case ReductionParameter_ReductionOp_ASUM: caffe_cpu_sign(dim_, bottom_data, bottom_diff); caffe_scal(dim_, bottom_coeff, bottom_diff); break; case ReductionParameter_ReductionOp_SUMSQ: caffe_cpu_scale(dim_, 2 * bottom_coeff, bottom_data, bottom_diff); break; default: LOG(FATAL) << "Unknown reduction op: " << ReductionParameter_ReductionOp_Name(op_); } bottom_data += dim_; bottom_diff += dim_; ++top_diff; } }