[关闭]
@nrailgun 2015-09-19T17:10:18.000000Z 字数 2127 阅读 3972

Caffe 损失层实现反向传播

机器学习


Caffe 以 loss_layer 为基类,派生各种损失层:

通常不需要实现神经元层,只需要实现 data_layerloss_layerloss_layer 的实现简单一些,但是要考虑一些微积分求导数问题。

反向传播的数学形式定义为:

JWij=Jaj ×ajzj×zjwij

其中:
Jaj=k=1lJak×akzk×zkaj

显然 zkaj=wjk。至此,理论上可反向计算梯度。

定义:

σj=Jaj×ajzj,

σj=k=1l(σk×zkaj)×ajzj,

JWij=σj×zjwij.

引入中间变量 σ 减少计算量,这实在非常有用。

回到 Caffe,在 Caffe 的 loss_layer,你必须计算其 Jy。在 Caffe 中损失计算如下:

  1. template <typename Dtype>
  2. void EuclideanLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
  3. const vector<Blob<Dtype>*>& top) {
  4. int count = bottom[0]->count();
  5. caffe_sub(
  6. count,
  7. bottom[0]->cpu_data(),
  8. bottom[1]->cpu_data(),
  9. diff_.mutable_cpu_data());
  10. Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data());
  11. Dtype loss = dot / bottom[0]->num() / Dtype(2);
  12. top[0]->mutable_cpu_data()[0] = loss;
  13. }

Forward_cpu 比较简单,没有太多可说的。关键是反向的实现:

  1. template <typename Dtype>
  2. void EuclideanLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
  3. const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  4. for (int i = 0; i < 2; ++i) {
  5. if (propagate_down[i]) {
  6. const Dtype sign = (i == 0) ? 1 : -1;
  7. const Dtype alpha = sign * top[0]->cpu_diff()[0] / bottom[i]->num();
  8. caffe_cpu_axpby(
  9. bottom[i]->count(), // count
  10. alpha, // alpha
  11. diff_.cpu_data(), // a
  12. Dtype(0), // beta
  13. bottom[i]->mutable_cpu_diff()); // b
  14. }
  15. }
  16. }

恩,稍微不那么直观,则表示的含义是:

Jy=(yt)αN,

也就是计算损失对于神经网络输出(层的输入)的导数。

大体上,Caffe 的反向实现便是如此。称不上神秘;但是贾杨清的思路如此清晰,确实非常厉害。但是还是存在一些疑问,没读过神经元层的实现,对反向整体实现过程还有不解,不过暂时可以实现损失层了,哈哈。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注