【问题标题】:How does caffe compute gradient when there are multiple branches?有多个分支时,caffe 是如何计算梯度的?
【发布时间】:2019-08-10 08:06:23
【问题描述】:

我现在正在阅读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赋值了一个值,表示该值是对应底部blob的梯度。

但是,当多个层将一个 blob 作为输入时,例如,在一个 blob 上堆叠多个 ReLU 层,Caffe 如何处理梯度计算?第一个ReLU 层修改了bottom_diff,似乎第二个ReLU 层只是覆盖它,而不是添加两个渐变。

我没有看到任何地方执行梯度求和,我很困惑。如果我错过了重要的事情,请告诉我,非常感谢。

【问题讨论】:

    标签: machine-learning optimization deep-learning gradient caffe


    【解决方案1】:

    当一个顶部 blob 用于多个底部时,Caffe 会自动插入拆分层。这是通过从caffe/utils/insert_splits.cpp 调用InsertSplits(...)Net&lt;Dtype&gt;::Init(...) 内完成的。

    例子:

    NetParameterprotobuf 对象中的原始网络(这里的节点是层):

    data ---> conv1 -> conv2 -> ...
          \-> somelayer -> ...
    

    NetLayers 在内存中Net::Init()之后:

    data -> split ---> conv1 -> conv2 -> ...
                   \-> somelayer -> ...
    

    (顺便说一句,一个有趣的细节:.diff 在激活时BlobsBackward() 分配,而.diff 在层可学习参数中由Backward() 添加。)

    【讨论】:

      猜你喜欢
      • 2018-05-28
      • 2015-11-27
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 2019-11-01
      • 1970-01-01
      相关资源
      最近更新 更多