Eltwise层的操作有三个:product(点乘), sum(相加减) 和 max(取大值),其中sum是默认操作。
1. PROD:按元素乘积
2. SUM:按元素求和(默认)
3. MAX:保存元素大者
该层还定义了 coeff
参数,该参数只对SUM操作起作用。
最后,caffe还设定了stable_prod_grad #[default = true ]
来选择是否渐进较慢的梯度计算方法,该方法只适用于PROD操作,对SUM操作无效。
更多细节参见下面的源码。
#include
#include
#include "caffe/layers/eltwise_layer.hpp"
#include "caffe/util/math_functions.hpp"
namespace caffe {
template <typename Dtype>
void EltwiseLayer::LayerSetUp(const vector *>& bottom,
const vector *>& top) {
CHECK(this->layer_param().eltwise_param().coeff_size() == 0
|| this->layer_param().eltwise_param().coeff_size() == bottom.size()) <<
"Eltwise Layer takes one coefficient per bottom blob.";
CHECK(!(this->layer_param().eltwise_param().operation()
== EltwiseParameter_EltwiseOp_PROD
&& this->layer_param().eltwise_param().coeff_size())) <<
"Eltwise layer only takes coefficients for summation.";
op_ = this->layer_param_.eltwise_param().operation();
// Blob-wise coefficients for the elementwise operation.
coeffs_ = vector (bottom.size(), 1);
if (this->layer_param().eltwise_param().coeff_size()) {
for (int i = 0; i < bottom.size(); ++i) {
coeffs_[i] = this->layer_param().eltwise_param().coeff(i);
}
}
stable_prod_grad_ = this->layer_param_.eltwise_param().stable_prod_grad();
}
template <typename Dtype>
void EltwiseLayer::Reshape(const vector *>& bottom,
const vector *>& top) {
for (int i = 1; i < bottom.size(); ++i) {
CHECK(bottom[i]->shape() == bottom[0]->shape());
}
top[0]->ReshapeLike(*bottom[0]);
// If max operation, we will initialize the vector index part.
if (this->layer_param_.eltwise_param().operation() ==
EltwiseParameter_EltwiseOp_MAX && top.size() == 1) {
max_idx_.Reshape(bottom[0]->shape());
}
}
template <typename Dtype>
void EltwiseLayer::Forward_cpu(
const vector *>& bottom, const vector *>& top) {
int* mask = NULL;
const Dtype* bottom_data_a = NULL;
const Dtype* bottom_data_b = NULL;
const int count = top[0]->count();
Dtype* top_data = top[0]->mutable_cpu_data();
switch (op_) { //choose different operations according to op_
case EltwiseParameter_EltwiseOp_PROD: //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;
case EltwiseParameter_EltwiseOp_SUM: //SUM 按位和,这里有coffs_为系数,可以通过指定某一输入的系数来完成按位加和按位减
caffe_set(count, Dtype(0), top_data);
// TODO(shelhamer) does BLAS optimize to sum for coeff = 1?
for (int i = 0; i < bottom.size(); ++i) {
caffe_axpy(count, coeffs_[i], bottom[i]->cpu_data(), top_data);
}
break;
case EltwiseParameter_EltwiseOp_MAX: //按位取大数
// Initialize
mask = max_idx_.mutable_cpu_data();
caffe_set(count, -1, mask);
caffe_set(count, Dtype(-FLT_MAX), top_data);
// bottom 0 & 1
bottom_data_a = bottom[0]->cpu_data();
bottom_data_b = bottom[1]->cpu_data();
for (int idx = 0; idx < count; ++idx) {
if (bottom_data_a[idx] > bottom_data_b[idx]) {
top_data[idx] = bottom_data_a[idx]; // maxval
mask[idx] = 0; // maxid
} else {
top_data[idx] = bottom_data_b[idx]; // maxval
mask[idx] = 1; // maxid
}
}
// bottom 2++
for (int blob_idx = 2; blob_idx < bottom.size(); ++blob_idx) {
bottom_data_b = bottom[blob_idx]->cpu_data();
for (int idx = 0; idx < count; ++idx) {
if (bottom_data_b[idx] > top_data[idx]) {
top_data[idx] = bottom_data_b[idx]; // maxval
mask[idx] = blob_idx; // maxid
}
}
}
break;
default:
LOG(FATAL) << "Unknown elementwise operation.";
}
}
template <typename Dtype>
void EltwiseLayer::Backward_cpu(const vector *>& top,
const vector<bool>& propagate_down, const vector *>& bottom) {
const int* mask = NULL;
const int count = top[0]->count();
const Dtype* top_data = top[0]->cpu_data();
const Dtype* top_diff = top[0]->cpu_diff();
for (int i = 0; i < bottom.size(); ++i) {
if (propagate_down[i]) {
const Dtype* bottom_data = bottom[i]->cpu_data();
Dtype* bottom_diff = bottom[i]->mutable_cpu_diff();
switch (op_) {
case EltwiseParameter_EltwiseOp_PROD:
if (stable_prod_grad_) {
bool initialized = false;
for (int j = 0; j < bottom.size(); ++j) {
if (i == j) { continue; }
if (!initialized) {
caffe_copy(count, bottom[j]->cpu_data(), bottom_diff);
initialized = true;
} else {
caffe_mul(count, bottom[j]->cpu_data(), bottom_diff,
bottom_diff);
}
}
} else {
caffe_div(count, top_data, bottom_data, bottom_diff);
}
caffe_mul(count, bottom_diff, top_diff, bottom_diff);
break;
case EltwiseParameter_EltwiseOp_SUM:
if (coeffs_[i] == Dtype(1)) {
caffe_copy(count, top_diff, bottom_diff);
} else {
caffe_cpu_scale(count, coeffs_[i], top_diff, bottom_diff);
}
break;
case EltwiseParameter_EltwiseOp_MAX:
mask = max_idx_.cpu_data();
for (int index = 0; index < count; ++index) {
Dtype gradient = 0;
if (mask[index] == i) {
gradient += top_diff[index];
}
bottom_diff[index] = gradient;
}
break;
default:
LOG(FATAL) << "Unknown elementwise operation.";
}
}
}
}
#ifdef CPU_ONLY
STUB_GPU(EltwiseLayer);
#endif
INSTANTIATE_CLASS(EltwiseLayer);
REGISTER_LAYER_CLASS(Eltwise);
} // namespace caffe
假设输入(bottom)为A和B,如果要实现element_wise的A+B,即A和B的对应元素相加,prototxt文件如下:
layer { name: "eltwise_layer" type: "Eltwise" bottom: "A" bottom: "B" top: "diff" eltwise_param { operation: SUM } }
如果实现A-B,则prototxt为:
layer { name: "eltwise_layer" type: "Eltwise" bottom: "A" bottom: "B" top: "diff" eltwise_param { operation: SUM coeff: 1 coeff: -1 } }
其中A和B的系数(coefficient)都要给出!
转载链接:http://blog.csdn.net/m0_37407756/article/details/72556750