我正在阅读Caffe
的源代码,然后我想到了这个问题。
以caffe/relu_layer.cpp
为例。在计算梯度时,
void ReLULayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) {
if (propagate_down[0]) {
const Dtype* bottom_data = bottom[0]->cpu_data();
const Dtype* top_diff = top[0]->cpu_diff();
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
const int count = bottom[0]->count();
Dtype negative_slope = this->layer_param_.relu_param().negative_slope();
for (int i = 0; i < count; ++i) {
bottom_diff[i] = top_diff[i] * ((bottom_data[i] > 0)
+ negative_slope * (bottom_data[i] <= 0));
}
}
}
我们可以看到最终为bottom_diff
分配了一个值,表明该值是相应底部斑点的梯度。
但是,当多层将一个斑点作为输入时,例如,在一个斑点上堆叠多个ReLU
层,Caffe
如何处理梯度计算?第一层ReLU
修改了bottom_diff
,第二层ReLU
似乎只是对其进行了覆盖,而不是添加两个渐变。
我没看到任何地方进行梯度求和,这让我感到困惑。如果我错过了重要的事情,请告知我,非常感谢。
答案 0 :(得分:0)
在多个底部使用顶部斑点时,Caffe自动插入“分割”层。这是在Net<Dtype>::Init(...)
内部通过从InsertSplits(...)
调用caffe/utils/insert_splits.cpp
来完成的。
示例:
protobuf对象NetParameter
中的原始网络(此处的节点为层):
data ---> conv1 -> conv2 -> ...
\-> somelayer -> ...
在Net
之后,在内存中有 Layer
个Net::Init()
:
data -> split ---> conv1 -> conv2 -> ...
\-> somelayer -> ...
(一个有趣的细节,顺便说一下:.diff
分配了激活Blobs
中的Backward()
,而{{ 1}}。)