Reproduce elementwise product layer in more generality.
Add elementwise operation parameter.
Prepare for elementwise sum operation choice.
int N_;
};
-/* EltwiseProductLayer
+/* EltwiseLayer
*/
template <typename Dtype>
-class EltwiseProductLayer : public Layer<Dtype> {
+class EltwiseLayer : public Layer<Dtype> {
public:
- explicit EltwiseProductLayer(const LayerParameter& param)
+ explicit EltwiseLayer(const LayerParameter& param)
: Layer<Dtype>(param) {}
virtual void SetUp(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);
const bool propagate_down, vector<Blob<Dtype>*>* bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom);
+
+ EltwiseParameter_EltwiseOp op_;
};
/* FlattenLayer
shared_ptr<PowerLayer<Dtype> > power_layer_;
Blob<Dtype> power_output_;
vector<Blob<Dtype>*> power_top_vec_;
- shared_ptr<EltwiseProductLayer<Dtype> > product_layer_;
+ shared_ptr<EltwiseLayer<Dtype> > product_layer_;
Blob<Dtype> product_data_input_;
vector<Blob<Dtype>*> product_bottom_vec_;
};
return new DropoutLayer<Dtype>(param);
case LayerParameter_LayerType_EUCLIDEAN_LOSS:
return new EuclideanLossLayer<Dtype>(param);
- case LayerParameter_LayerType_ELTWISE_PRODUCT:
- return new EltwiseProductLayer<Dtype>(param);
+ case LayerParameter_LayerType_ELTWISE:
+ return new EltwiseLayer<Dtype>(param);
case LayerParameter_LayerType_FLATTEN:
return new FlattenLayer<Dtype>(param);
case LayerParameter_LayerType_HDF5_DATA:
namespace caffe {
template <typename Dtype>
-void EltwiseProductLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
+void EltwiseLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
CHECK_GE(bottom.size(), 2) <<
"Eltwise Product Layer takes at least 2 blobs as input.";
CHECK_EQ(width, bottom[i]->width());
}
(*top)[0]->Reshape(num, channels, height, width);
+ op_ = this->layer_param_.eltwise_param().operation();
}
template <typename Dtype>
-Dtype EltwiseProductLayer<Dtype>::Forward_cpu(
+Dtype EltwiseLayer<Dtype>::Forward_cpu(
const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
const int count = (*top)[0]->count();
Dtype* top_data = (*top)[0]->mutable_cpu_data();
- caffe_mul(count, bottom[0]->cpu_data(), bottom[1]->cpu_data(), top_data);
- for (int i = 2; i < bottom.size(); ++i) {
- caffe_mul(count, top_data, bottom[i]->cpu_data(), top_data);
+ switch (op_) {
+ case EltwiseParameter_EltwiseOp_PROD:
+ caffe_mul(count, bottom[0]->cpu_data(), bottom[1]->cpu_data(), top_data);
+ for (int i = 2; i < bottom.size(); ++i) {
+ caffe_mul(count, top_data, bottom[i]->cpu_data(), top_data);
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unknown elementwise operation.";
}
return Dtype(0.);
}
template <typename Dtype>
-void EltwiseProductLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
+void EltwiseLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
if (propagate_down) {
const int count = top[0]->count();
for (int i = 0; i < bottom->size(); ++i) {
const Dtype* bottom_data = (*bottom)[i]->cpu_data();
Dtype* bottom_diff = (*bottom)[i]->mutable_cpu_diff();
- caffe_div(count, top_data, bottom_data, bottom_diff);
- caffe_mul(count, bottom_diff, top_diff, bottom_diff);
+ switch (op_) {
+ case EltwiseParameter_EltwiseOp_PROD:
+ caffe_div(count, top_data, bottom_data, bottom_diff);
+ caffe_mul(count, bottom_diff, top_diff, bottom_diff);
+ break;
+ default:
+ LOG(FATAL) << "Unknown elementwise operation.";
+ }
}
}
}
-INSTANTIATE_CLASS(EltwiseProductLayer);
+INSTANTIATE_CLASS(EltwiseLayer);
} // namespace caffe
namespace caffe {
template <typename Dtype>
-Dtype EltwiseProductLayer<Dtype>::Forward_gpu(
+Dtype EltwiseLayer<Dtype>::Forward_gpu(
const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
const int count = (*top)[0]->count();
Dtype* top_data = (*top)[0]->mutable_gpu_data();
- caffe_gpu_mul(count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), top_data);
- for (int i = 2; i < bottom.size(); ++i) {
- caffe_gpu_mul(count, top_data, bottom[i]->gpu_data(), top_data);
+ switch (op_) {
+ case EltwiseParameter_EltwiseOp_PROD:
+ caffe_gpu_mul(count, bottom[0]->gpu_data(), bottom[1]->gpu_data(), top_data);
+ for (int i = 2; i < bottom.size(); ++i) {
+ caffe_gpu_mul(count, top_data, bottom[i]->gpu_data(), top_data);
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unknown elementwise operation.";
}
return Dtype(0.);
}
template <typename Dtype>
-void EltwiseProductLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
+void EltwiseLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
if (propagate_down) {
const int count = top[0]->count();
for (int i = 0; i < bottom->size(); ++i) {
const Dtype* bottom_data = (*bottom)[i]->gpu_data();
Dtype* bottom_diff = (*bottom)[i]->mutable_gpu_diff();
- caffe_gpu_div(count, top_data, bottom_data, bottom_diff);
- caffe_gpu_mul(count, bottom_diff, top_diff, bottom_diff);
+ switch (op_) {
+ case EltwiseParameter_EltwiseOp_PROD:
+ caffe_gpu_div(count, top_data, bottom_data, bottom_diff);
+ caffe_gpu_mul(count, bottom_diff, top_diff, bottom_diff);
+ break;
+ default:
+ LOG(FATAL) << "Unknown elementwise operation.";
+ }
}
}
}
-INSTANTIATE_CLASS(EltwiseProductLayer);
+INSTANTIATE_CLASS(EltwiseLayer);
} // namespace caffe
product_bottom_vec_.push_back(bottom[0]);
product_bottom_vec_.push_back(&power_output_);
LayerParameter product_param;
- product_layer_.reset(new EltwiseProductLayer<Dtype>(product_param));
+ EltwiseParameter* eltwise_param = product_param.mutable_eltwise_param();
+ eltwise_param->set_operation(EltwiseParameter_EltwiseOp_PROD);
+ product_layer_.reset(new EltwiseLayer<Dtype>(product_param));
product_layer_->SetUp(product_bottom_vec_, top);
CHECK_EQ((*top)[0]->num(), num_);
CHECK_EQ((*top)[0]->channels(), channels_);
// NOTE
// Update the next available ID when you add a new LayerParameter field.
//
-// LayerParameter next available ID: 24 (last added: argmax_param)
+// LayerParameter next available ID: 25 (last added: eltwise_param)
message LayerParameter {
repeated string bottom = 2; // the name of the bottom blobs
repeated string top = 3; // the name of the top blobs
DATA = 5;
DROPOUT = 6;
EUCLIDEAN_LOSS = 7;
- ELTWISE_PRODUCT = 25;
+ ELTWISE = 25;
FLATTEN = 8;
HDF5_DATA = 9;
HDF5_OUTPUT = 10;
optional ConvolutionParameter convolution_param = 10;
optional DataParameter data_param = 11;
optional DropoutParameter dropout_param = 12;
+ optional EltwiseParameter eltwise_param = 24;
optional HDF5DataParameter hdf5_data_param = 13;
optional HDF5OutputParameter hdf5_output_param = 14;
optional ImageDataParameter image_data_param = 15;
optional float dropout_ratio = 1 [default = 0.5]; // dropout ratio
}
+// Message that stores parameters used by EltwiseLayer
+message EltwiseParameter {
+ enum EltwiseOp {
+ PROD = 0;
+ }
+ optional EltwiseOp operation = 1; // element-wise operation to compute
+}
+
// Message that stores parameters used by HDF5DataLayer
message HDF5DataParameter {
// Specify the data source.
extern cudaDeviceProp CAFFE_TEST_CUDA_PROP;
template <typename Dtype>
-class EltwiseProductLayerTest : public ::testing::Test {
+class EltwiseLayerTest : public ::testing::Test {
protected:
- EltwiseProductLayerTest()
+ EltwiseLayerTest()
: blob_bottom_a_(new Blob<Dtype>(2, 3, 4, 5)),
blob_bottom_b_(new Blob<Dtype>(2, 3, 4, 5)),
blob_bottom_c_(new Blob<Dtype>(2, 3, 4, 5)),
blob_bottom_vec_.push_back(blob_bottom_c_);
blob_top_vec_.push_back(blob_top_);
}
- virtual ~EltwiseProductLayerTest() {
+ virtual ~EltwiseLayerTest() {
delete blob_bottom_a_;
delete blob_bottom_b_;
delete blob_bottom_c_;
};
typedef ::testing::Types<float, double> Dtypes;
-TYPED_TEST_CASE(EltwiseProductLayerTest, Dtypes);
+TYPED_TEST_CASE(EltwiseLayerTest, Dtypes);
-TYPED_TEST(EltwiseProductLayerTest, TestSetUp) {
+TYPED_TEST(EltwiseLayerTest, TestSetUp) {
LayerParameter layer_param;
- shared_ptr<EltwiseProductLayer<TypeParam> > layer(
- new EltwiseProductLayer<TypeParam>(layer_param));
+ EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+ eltwise_param->set_operation(EltwiseParameter_EltwiseOp_PROD);
+ shared_ptr<EltwiseLayer<TypeParam> > layer(
+ new EltwiseLayer<TypeParam>(layer_param));
layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
EXPECT_EQ(this->blob_top_->num(), 2);
EXPECT_EQ(this->blob_top_->channels(), 3);
EXPECT_EQ(this->blob_top_->width(), 5);
}
-TYPED_TEST(EltwiseProductLayerTest, TestCPU) {
+TYPED_TEST(EltwiseLayerTest, TestCPU) {
Caffe::set_mode(Caffe::CPU);
LayerParameter layer_param;
- shared_ptr<EltwiseProductLayer<TypeParam> > layer(
- new EltwiseProductLayer<TypeParam>(layer_param));
+ EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+ eltwise_param->set_operation(EltwiseParameter_EltwiseOp_PROD);
+ shared_ptr<EltwiseLayer<TypeParam> > layer(
+ new EltwiseLayer<TypeParam>(layer_param));
layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
const TypeParam* data = this->blob_top_->cpu_data();
}
}
-TYPED_TEST(EltwiseProductLayerTest, TestGPU) {
+TYPED_TEST(EltwiseLayerTest, TestGPU) {
Caffe::set_mode(Caffe::GPU);
LayerParameter layer_param;
- shared_ptr<EltwiseProductLayer<TypeParam> > layer(
- new EltwiseProductLayer<TypeParam>(layer_param));
+ EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+ eltwise_param->set_operation(EltwiseParameter_EltwiseOp_PROD);
+ shared_ptr<EltwiseLayer<TypeParam> > layer(
+ new EltwiseLayer<TypeParam>(layer_param));
layer->SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
layer->Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
const TypeParam* data = this->blob_top_->cpu_data();
}
}
-TYPED_TEST(EltwiseProductLayerTest, TestCPUGradient) {
+TYPED_TEST(EltwiseLayerTest, TestCPUGradient) {
Caffe::set_mode(Caffe::CPU);
LayerParameter layer_param;
- EltwiseProductLayer<TypeParam> layer(layer_param);
+ EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+ eltwise_param->set_operation(EltwiseParameter_EltwiseOp_PROD);
+ EltwiseLayer<TypeParam> layer(layer_param);
GradientChecker<TypeParam> checker(1e-2, 1e-3);
checker.CheckGradientEltwise(&layer, &(this->blob_bottom_vec_),
&(this->blob_top_vec_));
}
-TYPED_TEST(EltwiseProductLayerTest, TestGPUGradient) {
+TYPED_TEST(EltwiseLayerTest, TestGPUGradient) {
Caffe::set_mode(Caffe::GPU);
LayerParameter layer_param;
- EltwiseProductLayer<TypeParam> layer(layer_param);
+ EltwiseParameter* eltwise_param = layer_param.mutable_eltwise_param();
+ eltwise_param->set_operation(EltwiseParameter_EltwiseOp_PROD);
+ EltwiseLayer<TypeParam> layer(layer_param);
GradientChecker<TypeParam> checker(1e-2, 1e-2);
checker.CheckGradientEltwise(&layer, &(this->blob_bottom_vec_),
&(this->blob_top_vec_));