论文阅读学习 - Center Loss: Caffe 实现_bottom[0]->count(axis) csdn-程序员宅基地

技术标签: 论文阅读  CenterLoss  Caffe  CaffeLayer  人脸识别  

Center Loss - Caffe

[caffe-face]

1. prototxt 中的使用

layer {
  name: "fc5"
  type: "InnerProduct"
  bottom: "res5_6"
  top: "fc5"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 512 # 提取特征层,特征维度
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}

############## center loss ###############
layer {
  name: "center_loss"
  type: "CenterLoss"
  bottom: "fc5"
  bottom: "label"
  top: "center_loss"
  param {
    lr_mult: 1
    decay_mult: 2 
  }
  center_loss_param {
    num_output: 1000 # 类别数
    center_filler {
      type: "xavier"
    }
  }
  loss_weight: 0.008 # 权重
}


############## softmax loss ###############
# Softmax Loss 需要再接一个全连接层
layer {
  name: "fc6"
  type: "InnerProduct"
  bottom: "fc5"
  top: "fc6"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 1000 # 类别数
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "softmax_loss"
  type: "SoftmaxWithLoss"
  bottom: "fc6"
  bottom: "label"
  top: "softmax_loss"
}

2. caffe.proto 中的定义

message LayerParameter {
    optional CenterLossParameter center_loss_param = 149;
}


message CenterLossParameter {
  optional uint32 num_output = 1; // The number of outputs for the layer 网络层输出,与类别数一致
  optional FillerParameter center_filler = 2; // The filler for the centers 
  // The first axis to be lumped into a single inner product computation;
  // all preceding axes are retained in the output.
  // May be negative to index from the end (e.g., -1 for the last axis).
  optional int32 axis = 3 [default = 1];
}

3. center_loss_layer.hpp

#ifndef CAFFE_CENTER_LOSS_LAYER_HPP_
#define CAFFE_CENTER_LOSS_LAYER_HPP_

#include <vector>

#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"

#include "caffe/layers/loss_layer.hpp"

namespace caffe {

template <typename Dtype>
class CenterLossLayer : public LossLayer<Dtype> {
 public:
  explicit CenterLossLayer(const LayerParameter& param)
      : LossLayer<Dtype>(param) {}
  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

  virtual inline const char* type() const { return "CenterLoss"; }
  virtual inline int ExactNumBottomBlobs() const { return 2; }
  virtual inline int ExactNumTopBlobs() const { return -1; }

 protected:
  virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top); // 前向传播 CPU 实现
  virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top); // 前向传播 GPU 实现
  virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom); // 反向传播 CPU 实现
  virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  //反向传播 GPU 实现

  int M_;
  int K_;
  int N_;

  Blob<Dtype> distance_;
  Blob<Dtype> variation_sum_;
};

}  // namespace caffe

#endif  // CAFFE_CENTER_LOSS_LAYER_HPP_

4. center_loss_layer.cpp - CPU 实现

#include <vector>

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

namespace caffe {

template <typename Dtype>
void CenterLossLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  const int num_output = this->layer_param_.center_loss_param().num_output();  
  N_ = num_output;
  const int axis = bottom[0]->CanonicalAxisIndex(
      this->layer_param_.center_loss_param().axis());
  // 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<Dtype>(center_shape));
    // fill the weights
    shared_ptr<Filler<Dtype> > center_filler(GetFiller<Dtype>(
        this->layer_param_.center_loss_param().center_filler()));
    center_filler->Fill(this->blobs_[0].get());

  }  // 参数初始化
  this->param_propagate_down_.resize(this->blobs_.size(), true);
}


template <typename Dtype>
void CenterLossLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& 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<Dtype>::Reshape(bottom, top);
  distance_.ReshapeLike(*bottom[0]);
  variation_sum_.ReshapeLike(*this->blobs_[0]);
}


template <typename Dtype>
void CenterLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  const Dtype* bottom_data = bottom[0]->cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  const Dtype* center = this->blobs_[0]->cpu_data();
  Dtype* distance_data = distance_.mutable_cpu_data();

  // the i-th distance_data
  for (int i = 0; i < M_; i++) {
    const int label_value = static_cast<int>(label[i]);
    // D(i,:) = X(i,:) - C(y(i),:)
    caffe_sub(K_, bottom_data + i * K_, center + label_value * K_, distance_data + i * K_);
  }
  Dtype dot = caffe_cpu_dot(M_ * K_, distance_.cpu_data(), distance_.cpu_data());
  Dtype loss = dot / M_ / Dtype(2);
  top[0]->mutable_cpu_data()[0] = loss;
}


template <typename Dtype>
void CenterLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down,
    const vector<Blob<Dtype>*>& 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();
    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());
    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_);
        }
      }
      caffe_axpy(K_, (Dtype)1./(count + (Dtype)1.), variation_sum_data + n * K_, center_diff + n * K_);
    }
  }
  // Gradient with respect to bottom data 
  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());
  }
  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

5. center_Loss_layer.cu - GPU 实现

#include <vector>

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

namespace caffe {

template <typename Dtype>
__global__ void Compute_distance_data_gpu(int nthreads, const int K, const Dtype* bottom,
          const Dtype* label, const Dtype* center, Dtype* distance) {
  CUDA_KERNEL_LOOP(index, nthreads) {
    int m = index / K;
    int k = index % K;
    const int label_value = static_cast<int>(label[m]);
    // distance(i) = x(i) - c_{y(i)}
    distance[index] = bottom[index] - center[label_value * K + k];
  }
}

template <typename Dtype>
__global__ void Compute_center_diff_gpu(int nthreads, const int M, const int K, 
        const Dtype* label, const Dtype* distance, Dtype* variation_sum, 
        Dtype* center_diff) {
  CUDA_KERNEL_LOOP(index, nthreads) {
    int count = 0;
    for (int m = 0; m < M; m++) {
      const int label_value = static_cast<int>(label[m]);
      if (label_value == index) {
        count++;
        for (int k = 0; k < K; k++) {
          variation_sum[index * K + k] -= distance[m * K + k];
        }
      }
    }
    for (int k = 0; k < K; k++) {
      center_diff[index * K + k] = variation_sum[index * K + k] /(count + (Dtype)1.);
    }
  }
}


template <typename Dtype>
void CenterLossLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  int nthreads = M_ * K_;
  Compute_distance_data_gpu<Dtype><<<CAFFE_GET_BLOCKS(nthreads),
      CAFFE_CUDA_NUM_THREADS>>>(nthreads, K_, bottom[0]->gpu_data(), bottom[1]->gpu_data(),
                                this->blobs_[0]->gpu_data(), distance_.mutable_gpu_data());
  Dtype dot;
  caffe_gpu_dot(M_ * K_, distance_.gpu_data(), distance_.gpu_data(), &dot);
  Dtype loss = dot / M_ / Dtype(2);
  top[0]->mutable_cpu_data()[0] = loss;
}

template <typename Dtype>
void CenterLossLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down,
    const vector<Blob<Dtype>*>& bottom) {
  int nthreads = N_;
  caffe_gpu_set(N_ * K_, (Dtype)0., variation_sum_.mutable_cpu_data());
  Compute_center_diff_gpu<Dtype><<<CAFFE_GET_BLOCKS(nthreads),
      CAFFE_CUDA_NUM_THREADS>>>(nthreads, M_, K_, bottom[1]->gpu_data(), distance_.gpu_data(), 
                                variation_sum_.mutable_cpu_data(), this->blobs_[0]->mutable_gpu_diff());

  if (propagate_down[0]) {
    caffe_gpu_scale(M_ * K_, top[0]->cpu_diff()[0] / M_, 
                             distance_.gpu_data(), bottom[0]->mutable_gpu_diff());
  }
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
}

INSTANTIATE_LAYER_GPU_FUNCS(CenterLossLayer);

}  // namespace caffe

6. 基于 Center Loss 的训练

  • 数据准备

    与基于 Softmax Loss 的分类问题的数据格式一致,即:

    img1 label1
    img2 label2
    img3 label3
    ...

    其中,label 从 0 开始.

    根据数据集 labels 的总数设置 CenterLossLayer 的 num_output.

  • 网络训练

    类似于分类问题的训练,进行网络训练即可.

7. 测试

基于训练的网络模型提取特征,计算相似度即可.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/oJiMoDeYe12345/article/details/78549988

智能推荐

信息检索的过去 当前 未来-------浅层分析报告_信息检索的未来发展-程序员宅基地

文章浏览阅读1.2k次。关键字:信息检索;信息的专业分工;专业化的信息垂直供应;信息的商品化;商品化信息的信息;信息加工融合搜索过去:信息少,我们只须到163这样的网站上发发邮件,看看新闻,浏览一下图片即可满足我们的需求。那时,信息少,上网叫冲浪。是个时髦新鲜的玩意。人们不需要关注太多,因为网络还很远。对生产,工作,学习,生活还产生不了多大的影响。当前:网络是必须的一个世界。它使得信息在秒级概念下传递。信..._信息检索的未来发展

POJ3259-JAVA语言描述-Bellman_Ford算法_poj3259java-程序员宅基地

文章浏览阅读739次。读懂题意真难,时间都浪费在理解题意上面了。然后,发现,,这又是一个水题!分分钟撸完了!!!!引用这里的解释吧我就不多加赘述了!给你们解释下输入案例数据也许会更清晰的哟!下面看代码,注释很详细!!若有bug,不足,望悉心指出,thanks!!!!import java.io.BufferedInputStream;import java.util.Scanner;/_poj3259java

ARM中断体系结构(以S3C2440为例)_svc模式 sys模式 irq模式-程序员宅基地

文章浏览阅读448次。本文参考韦东山嵌入式视频一、ARM体系CPU工作模式1、用户模式(usr)2、快速中断模式(fiq)3、中断模式(irq)4、管理模式(svc)5、数据访问终止模式(abt)6、系统模式(sys)7、未定义指令中止模式(und)①每种工作模式有不同的寄存器:一共有37个32位寄存器(以ARM920T CPU为例,在ARM状态下(ARM体系的CPU有两种工作状态)),②有不同的权限 :配合MMU使用③有不同的出发条件:例如上电后处于管理模式 发生中断进入irq模式等二、异常与中断1_svc模式 sys模式 irq模式

HTML+CSS+JavaScript+ServerSQL2019+IE浏览器实现食堂管理系统(点菜、查询、充值余等等)_html + css + javascript点餐系统-程序员宅基地

文章浏览阅读923次。然后会跳转到点餐界面,数据都是从数据库里调出来的,菜品,套餐,用户信息都是数据库中的表信息。我是一个大二的学生,课设选了一个食堂餐厅管理系统,但是时间有限,所以写的不是很好,随手分享一下,互相学习。点击提交订单,就会先判断是否登录,未登录就会提示你先登录,登录了则扣费并提示支付成功。然后就可以点餐了,前提是余额足够,不够也不行,会提示失败,需要充值。管理员还没来得及写,本来是想写一个菜品增删改查的,感兴趣的可以自己发挥。我没什么美感,所以界面做的不是很好看,请各位见谅,凑合着看。_html + css + javascript点餐系统

java 删除linkedlist链表中重复元素_java linkedlist中删除重复元素-程序员宅基地

文章浏览阅读5.5k次。题目:Given a sorted linked list, delete all duplicates such that each element appear only once.For example,Given 1->1->2, return 1->2.Given 1->1->2->3->3, return 1->2->3. 算法如下:/** * Definition for sin_java linkedlist中删除重复元素

kaptcha生成验证码_com.github.axet-程序员宅基地

文章浏览阅读1.5k次。Meven的pom.xml中加入 com.github.axet kaptcha 0.0.9Spring中声明

随便推点

Linux挂载U盘报错:mount: unknown filesystem type 'ntfs'-程序员宅基地

文章浏览阅读1.5k次。Linux挂载U盘报错:mount: unknown filesystem type 'ntfs'2017年03月29日 10:53:03m沉默01阅读数:9323更多个人分类:Linux版权声明:转载请标明博客地址http://blog.csdn.net/u010780613。 https://blog.csdn.net/u010780613/article/details/6..._unknown filesystem type 'ntfs

caffe代码阅读8: Data_layers的实现细节(各个数据读取层的实现细节) 2016.3.25-28_"data-layer=\"true"-程序员宅基地

文章浏览阅读1.4w次,点赞4次,收藏20次。Caffe中Layer类是所有神经网络层的基类,BaseDataLayer继承自该类,BasePrefetchingDataLayer继承自BaseDataLayer,DataLayer继承自BasePrefetchingDataLayer。有了上述几个基础的类之后,其他的类都是从这几个类进行派生。比如DummyDataLayer,HDF5Layer和HDF5OutputLayer都是直接继承自Layer。MemoryDataLayer则是继承自BaseDataLayer凡是涉及到直接读取数据文_"data-layer=\"true"

word转pdf出现空白页||去除PDF中的指定页_为什么转pdf后多了空白页-程序员宅基地

文章浏览阅读3.7k次。最近在搞毕业论文,一个事情很让人头大:明明只有51页的论文,可word右下角显示52页上网查了一下,大致原因可能是分节符或是奇偶页不同造成的,因为封面不能加页码,而且中英文的摘要页码和正文页码也要单独标记,可我的中英文摘要刚好是奇数页,3页,word会默认在奇数页后面补充空白页(应该是方便双面打印的吧)这样,我的中英文摘要就变成四页了,多的那一页在word中可能会显示出来,也可能不显示,但..._为什么转pdf后多了空白页

MFC中获取文件路径和获取文件路径_mfc获取文件路径不要文件名-程序员宅基地

文章浏览阅读2k次。一、获取文件路径二、获取文件夹路径_mfc获取文件路径不要文件名

关于Unity中Shader的使用-程序员宅基地

文章浏览阅读342次。在游戏的开发过程中,程序员不太会自己去写shader,因为写起来很麻烦,而且只有Unity会报错,编译器也没有什么提示。通常是拿别人的shader改一改,当然,程序员还是要能看懂和会一点shader Unity坐标系转换1: transform.localToWorldMatrix 局部转世界的矩阵;2: transfrom.worldToLocalMatrix 世界坐标转局部坐标矩..._unity resources下的shader

golang kite 环境搭建_c:\go\src\golang.org\x\sys\windows (from $goroot)-程序员宅基地

文章浏览阅读2.6k次。1、安装git2、直接导入第三方包:go get github.com/koding/kite3、然后会有提示:package golang.org/x/crypto/ssh/terminal: unrecognized import path "golang.org/x/crypto/ssh/terminal"4、这时候直接从git上clone:git clone ..._c:\go\src\golang.org\x\sys\windows (from $goroot)