centerloss 理解

今天看了一下centerloss 源码 ,觉得还是挺值得借鉴的,所以分享一下。
centerloss主要在caffe的基础上加了三项。

一. caffe.proto

1.加proto 格式 的 ID号147

centerloss 理解_第1张图片

2.加proto格式的定义

centerloss 理解_第2张图片
这里面的参数都是层的参数,也是超参,在prototxt中赋值。
axis是默认为1的。

二.加入hpp 文件到include/caffe/layers/ ,

centerloss 理解_第3张图片

主要包含cpp文件的方法和参数的定义。

三.加入cpp文件到src/caffe/layers/

centerloss 理解_第4张图片

centerloss 理解_第5张图片

#include 

#include "caffe/filler.hpp"
#include "caffe/layers/center_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void CenterLossLayer::LayerSetUp(const vector*>& bottom,
      const vector*>& top) {
  const int num_output = this->layer_param_.center_loss_param().num_output();  
  N_ = num_output;
  const int axis = bottom[0]->CanonicalAxisIndex( //一个常见的blob数据包括(N,C,H,W)四个维度,可以通过设定axis来选取哪一个维度
      this->layer_param_.center_loss_param().axis());//把axis后面的都拉为一个向量,最后是chw变成k维的
  // Dimensions starting from "axis" are "flattened" into a single
  // length K_ vector. For example, if bottom[0]'s shape is (N, C, H, W),
  // and axis == 1, N inner products with dimension CHW are performed.
  K_ = bottom[0]->count(axis);
  // Check if we need to set up the weights
  if (this->blobs_.size() > 0) {
    LOG(INFO) << "Skipping parameter initialization";
  } else {
    this->blobs_.resize(1);
    // Intialize the weight
    vector<int> center_shape(2);
    center_shape[0] = N_;
    center_shape[1] = K_;
    this->blobs_[0].reset(new Blob(center_shape));//尺寸设成centershape的大小
    // fill the weights
    shared_ptr > center_filler(GetFiller(
        this->layer_param_.center_loss_param().center_filler()));// Fillers are random number generators that fills a blob using the specified algorithm. //这个很重要,就是如何初始化,这里是使用prototxt中定义的xavier方法初始化,可以看到 
       //center_loss_param {
      // num_output: 10572
     //center_filler {
    // type: "xavier"
   // }
  // }
    center_filler->Fill(this->blobs_[0].get());

  }  // parameter initialization
  this->param_propagate_down_.resize(this->blobs_.size(), true);
}

template <typename Dtype>
void CenterLossLayer::Reshape(const vector*>& bottom,
      const vector*>& top) {
  CHECK_EQ(bottom[1]->channels(), 1);
  CHECK_EQ(bottom[1]->height(), 1);
  CHECK_EQ(bottom[1]->width(), 1);
  M_ = bottom[0]->num();
  // The top shape will be the bottom shape with the flattened axes dropped,
  // and replaced by a single axis with dimension num_output (N_).
  LossLayer::Reshape(bottom, top);
  distance_.ReshapeLike(*bottom[0]);
  variation_sum_.ReshapeLike(*this->blobs_[0]);
}

template <typename Dtype>
void CenterLossLayer::Forward_cpu(const vector*>& bottom,
    const vector*>& top) {
  const Dtype* bottom_data = bottom[0]->cpu_data();//输入的倒数第二个卷积层的feature
  const Dtype* label = bottom[1]->cpu_data();//输入的label
  const Dtype* center = this->blobs_[0]->cpu_data();//指针指向,后面会赋值给这个地方
  Dtype* distance_data = distance_.mutable_cpu_data();//存储每一类xi-cyi的地方

  // the i-th distance_data
  for (int i = 0; i < M_; i++) {
    const int label_value = static_cast<int>(label[i]);//第i类
    // D(i,:) = X(i,:) - C(y(i),:)
    caffe_sub(K_, bottom_data + i * K_, center + label_value * K_, distance_data + i * K_);//算好减法,这里这个center很有意思,因为只在前向传播中出现,让人怀疑为什么它存储了center的值。其实是这样,它指向的是blob_[0]
中的cpu_data,然后在更新参数时,会自动加上反向传播时计算好的center_diff,即
blobs_[0]->mutable_cpu_diff()。
 }
  Dtype dot = caffe_cpu_dot(M_ * K_, distance_.cpu_data(), distance_.cpu_data());//这是vector的乘积,而非matrix,算好l2范数
  Dtype loss = dot / M_ / Dtype(2);//算好前面的项
  top[0]->mutable_cpu_data()[0] = loss;//存好loss
}

template <typename Dtype>
void CenterLossLayer::Backward_cpu(const vector*>& top,
    const vector<bool>& propagate_down,
    const vector*>& bottom) {
  // Gradient with respect to centers
  if (this->param_propagate_down_[0]) {
    const Dtype* label = bottom[1]->cpu_data();//标签
    Dtype* center_diff = this->blobs_[0]->mutable_cpu_diff();//存center更新值的地方。
    Dtype* variation_sum_data = variation_sum_.mutable_cpu_data();
    const Dtype* distance_data = distance_.cpu_data();
//上面这两个都是存中间的值。
    // \sum_{y_i==j}
    caffe_set(N_ * K_, (Dtype)0., variation_sum_.mutable_cpu_data());//设置为0
    for (int n = 0; n < N_; n++) {
      int count = 0;
      for (int m = 0; m < M_; m++) {
        const int label_value = static_cast<int>(label[m]);
        if (label_value == n) {
          count++;
          caffe_sub(K_, variation_sum_data + n * K_, distance_data + m * K_, variation_sum_data + n * K_);
        }
   //distance_data里面存的是前向时存的D(i,:) = X(i,:) - C(y(i),:)
      }
      caffe_axpy(K_, (Dtype)1./(count + (Dtype)1.), variation_sum_data + n * K_, center_diff + n * K_);前面第二第三个相乘存到最后一个
    }
  }
  // Gradient with respect to bottom data //就是Lc对xi求偏导数
  if (propagate_down[0]) {
    caffe_copy(M_ * K_, distance_.cpu_data(), bottom[0]->mutable_cpu_diff());
    caffe_scal(M_ * K_, top[0]->cpu_diff()[0] / M_, bottom[0]->mutable_cpu_diff());//这里求l2范数的导数 ,bottom[0]->mutable_cpu_diff()只是D(i,:) = X(i,:) - C(y(i),:)。
  }
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
}

#ifdef CPU_ONLY
STUB_GPU(CenterLossLayer);
#endif

INSTANTIATE_CLASS(CenterLossLayer);
REGISTER_LAYER_CLASS(CenterLoss);

}  // namespace caffe

最后附上我随手写的非常潦草的论文阅读笔记,上面一些备注有利于加深对centerloss的理解
centerloss 理解_第6张图片

你可能感兴趣的:(计算机视觉)