caffe添加损失层PrecisionRecallLosslayer(一)

先就按照tangwei2014 学习了一下triplet loss。感谢tangwei博主

===============================================================================================================================

【前言】 
最近,learning to rank 的思想逐渐被应用到很多领域,比如google用来做人脸识别(faceNet),微软Jingdong Wang 用来做 person-reid 等等。learning to rank中其中重要的一个步骤就是找到一个好的similarity function,而triplet loss是用的非常广泛的一种。

【理解triplet】

这里写图片描述

如上图所示,triplet是一个三元组,这个三元组是这样构成的:从训练数据集中随机选一个样本,该样本称为Anchor,然后再随机选取一个和Anchor (记为x_a)属于同一类的样本和不同类的样本,这两个样本对应的称为Positive (记为x_p)和Negative (记为x_n),由此构成一个(Anchor,Positive,Negative)三元组。

【理解triplet loss】 
有了上面的triplet的概念, triplet loss就好理解了。针对三元组中的每个元素(样本),训练一个参数共享或者不共享的网络,得到三个元素的特征表达,分别记为:这里写图片描述 。triplet loss的目的就是通过学习,让x_a和x_p特征表达之间的距离尽可能小,而x_a和x_n的特征表达之间的距离尽可能大,并且要让x_a与x_n之间的距离和x_a与x_p之间的距离之间有一个最小的间隔这里写图片描述。公式化的表示就是:
这里写图片描述

对应的目标函数也就很清楚了: 
这里写图片描述 
这里距离用欧式距离度量,+表示[]内的值大于零的时候,取该值为损失,小于零的时候,损失为零。 
由目标函数可以看出:

  • 当x_a与x_n之间的距离 < x_a与x_p之间的距离加这里写图片描述时,[]内的值大于零,就会产生损失。
  • 当x_a与x_n之间的距离 >= x_a与x_p之间的距离加这里写图片描述时,损失为零。

【triplet loss 梯度推导】 
上述目标函数记为L。则当第i个triplet损失大于零的时候,仅就上述公式而言,有: 
这里写图片描述

【算法实现时候的提示】 
可以看到,对x_p和x_n特征表达的梯度刚好利用了求损失时候的中间结果,给的启示就是,如果在CNN中实现 triplet loss layer, 如果能够在前向传播中存储着两个中间结果,反向传播的时候就能避免重复计算。这仅仅是算法实现时候的一个Trick。

================================================================================================================

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. 1.在~/caffe/src/caffe/proto/caffe.proto中增加triplet loss layer的定义  
  2. 首先在message LayerParameter中追加 optional TripletLossParameter triplet_loss_param = 138;  
  3. 其次添加message TripletLossParameter类:  
  4.   
  5. message TripletLossParameter {  
  6.      // margin for dissimilar pair  
  7.     optional float margin = 1 [default = 1.0];   
  8. }  
  9.   
  10. 2.在./include/caffe/loss_layers.hpp中增加triplet loss layer的类的声明  
  11.   
  12. /** 
  13.  * @brief Computes the triplet loss 
  14.  */  
  15. template <typename Dtype>  
  16. class TripletLossLayer : public LossLayer<Dtype> {  
  17.  public:  
  18.   explicit TripletLossLayer(const LayerParameter& param)  
  19.       : LossLayer<Dtype>(param){}  
  20.   virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,  
  21.       const vector<Blob<Dtype>*>& top);  
  22.   
  23.   virtual inline int ExactNumBottomBlobs() const { return 4; }  
  24.   virtual inline const char* type() const { return "TripletLoss"; }  
  25.   /** 
  26.    * Unlike most loss layers, in the TripletLossLayer we can backpropagate 
  27.    * to the first three inputs. 
  28.    */  
  29.   virtual inline bool AllowForceBackward(const int bottom_index) const {  
  30.     return bottom_index != 3;  
  31.   }  
  32.   
  33.  protected:  
  34.   virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  35.       const vector<Blob<Dtype>*>& top);  
  36.   virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  37.       const vector<Blob<Dtype>*>& top);  
  38.   
  39.   virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,  
  40.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  41.   virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,  
  42.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  43.   
  44.   Blob<Dtype> diff_ap_;  // cached for backward pass  
  45.   Blob<Dtype> diff_an_;  // cached for backward pass  
  46.   Blob<Dtype> diff_pn_;  // cached for backward pass  
  47.   
  48.   Blob<Dtype> diff_sq_ap_;  // cached for backward pass  
  49.   Blob<Dtype> diff_sq_an_;  // tmp storage for gpu forward pass  
  50.   
  51.   Blob<Dtype> dist_sq_ap_;  // cached for backward pass  
  52.   Blob<Dtype> dist_sq_an_;  // cached for backward pass  
  53.   
  54.   Blob<Dtype> summer_vec_;  // tmp storage for gpu forward pass  
  55.   Blob<Dtype> dist_binary_;  // tmp storage for gpu forward pass  
  56. };  
  57.   
  58. 3. 在./src/caffe/layers/目录下新建triplet_loss_layer.cpp,实现类  
  59. 主要实现三个功能:  
  60. LayerSetUp:主要是做一些CHECK工作,然后根据bottom和top对类中的数据成员初始化。  
  61. Forward_cpu:前传,计算loss  
  62. Backward_cpu:反传,计算梯度。  
  63.   
  64. /* 
  65.  * triplet_loss_layer.cpp 
  66.  * 
  67.  *  Created on: Jun 2, 2015 
  68.  *      Author: tangwei 
  69.  */  
  70.   
  71. #include <algorithm>  
  72. #include <vector>  
  73.   
  74. #include "caffe/layer.hpp"  
  75. #include "caffe/loss_layers.hpp"  
  76. #include "caffe/util/io.hpp"  
  77. #include "caffe/util/math_functions.hpp"  
  78.   
  79. namespace caffe {  
  80.   
  81. template <typename Dtype>  
  82. void TripletLossLayer<Dtype>::LayerSetUp(  
  83.   const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {  
  84.   LossLayer<Dtype>::LayerSetUp(bottom, top);  
  85.   CHECK_EQ(bottom[0]->num(), bottom[1]->num());  
  86.   CHECK_EQ(bottom[1]->num(), bottom[2]->num());  
  87.   CHECK_EQ(bottom[0]->channels(), bottom[1]->channels());  
  88.   CHECK_EQ(bottom[1]->channels(), bottom[2]->channels());  
  89.   CHECK_EQ(bottom[0]->height(), 1);  
  90.   CHECK_EQ(bottom[0]->width(), 1);  
  91.   CHECK_EQ(bottom[1]->height(), 1);  
  92.   CHECK_EQ(bottom[1]->width(), 1);  
  93.   CHECK_EQ(bottom[2]->height(), 1);  
  94.   CHECK_EQ(bottom[2]->width(), 1);  
  95.   
  96.   CHECK_EQ(bottom[3]->channels(),1);  
  97.   CHECK_EQ(bottom[3]->height(), 1);  
  98.   CHECK_EQ(bottom[3]->width(), 1);  
  99.   
  100.   diff_ap_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  101.   diff_an_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  102.   diff_pn_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  103.   
  104.   diff_sq_ap_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  105.   diff_sq_an_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  106.   dist_sq_ap_.Reshape(bottom[0]->num(), 1, 1, 1);  
  107.   dist_sq_an_.Reshape(bottom[0]->num(), 1, 1, 1);  
  108.   // vector of ones used to sum along channels  
  109.   summer_vec_.Reshape(bottom[0]->channels(), 1, 1, 1);  
  110.   for (int i = 0; i < bottom[0]->channels(); ++i)  
  111.       summer_vec_.mutable_cpu_data()[i] = Dtype(1);  
  112.   dist_binary_.Reshape(bottom[0]->num(), 1, 1, 1);  
  113.     for (int i = 0; i < bottom[0]->num(); ++i)  
  114.         dist_binary_.mutable_cpu_data()[i] = Dtype(1);  
  115. }  
  116.   
  117. template <typename Dtype>  
  118. void TripletLossLayer<Dtype>::Forward_cpu(  
  119.     const vector<Blob<Dtype>*>& bottom,  
  120.     const vector<Blob<Dtype>*>& top) {  
  121.   int count = bottom[0]->count();  
  122.   const Dtype* sampleW = bottom[3]->cpu_data();  
  123.   caffe_sub(  
  124.       count,  
  125.       bottom[0]->cpu_data(),  // a  
  126.       bottom[1]->cpu_data(),  // p  
  127.       diff_ap_.mutable_cpu_data());  // a_i-p_i  
  128.   caffe_sub(  
  129.        count,  
  130.        bottom[0]->cpu_data(),  // a  
  131.        bottom[2]->cpu_data(),  // n  
  132.        diff_an_.mutable_cpu_data());  // a_i-n_i  
  133.   caffe_sub(  
  134.        count,  
  135.        bottom[1]->cpu_data(),  // p  
  136.        bottom[2]->cpu_data(),  // n  
  137.        diff_pn_.mutable_cpu_data());  // p_i-n_i  
  138.   const int channels = bottom[0]->channels();  
  139.   Dtype margin = this->layer_param_.triplet_loss_param().margin();  
  140.   
  141.   Dtype loss(0.0);  
  142.   for (int i = 0; i < bottom[0]->num(); ++i) {  
  143.     dist_sq_ap_.mutable_cpu_data()[i] = caffe_cpu_dot(channels,  
  144.         diff_ap_.cpu_data() + (i*channels), diff_ap_.cpu_data() + (i*channels));  
  145.     dist_sq_an_.mutable_cpu_data()[i] = caffe_cpu_dot(channels,  
  146.         diff_an_.cpu_data() + (i*channels), diff_an_.cpu_data() + (i*channels));  
  147.     Dtype mdist = sampleW[i]*std::max(margin + dist_sq_ap_.cpu_data()[i] - dist_sq_an_.cpu_data()[i], Dtype(0.0));  
  148.     loss += mdist;  
  149.     if(mdist==Dtype(0)){  
  150.         //dist_binary_.mutable_cpu_data()[i] = Dtype(0);  
  151.         //prepare for backward pass  
  152.         caffe_set(channels, Dtype(0), diff_ap_.mutable_cpu_data() + (i*channels));  
  153.         caffe_set(channels, Dtype(0), diff_an_.mutable_cpu_data() + (i*channels));  
  154.         caffe_set(channels, Dtype(0), diff_pn_.mutable_cpu_data() + (i*channels));  
  155.     }  
  156.   }  
  157.   loss = loss / static_cast<Dtype>(bottom[0]->num()) / Dtype(2);  
  158.   top[0]->mutable_cpu_data()[0] = loss;  
  159. }  
  160.   
  161. template <typename Dtype>  
  162. void TripletLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,  
  163.     const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {  
  164.   //Dtype margin = this->layer_param_.contrastive_loss_param().margin();  
  165.   const Dtype* sampleW = bottom[3]->cpu_data();  
  166.   for (int i = 0; i < 3; ++i) {  
  167.     if (propagate_down[i]) {  
  168.       const Dtype sign = (i < 2) ? -1 : 1;  
  169.       const Dtype alpha = sign * top[0]->cpu_diff()[0] /  
  170.           static_cast<Dtype>(bottom[i]->num());  
  171.       int num = bottom[i]->num();  
  172.       int channels = bottom[i]->channels();  
  173.       for (int j = 0; j < num; ++j) {  
  174.         Dtype* bout = bottom[i]->mutable_cpu_diff();  
  175.         if (i==0) {  // a  
  176.           //if(dist_binary_.cpu_data()[j]>Dtype(0)){  
  177.               caffe_cpu_axpby(  
  178.                   channels,  
  179.                   alpha*sampleW[j],  
  180.                   diff_pn_.cpu_data() + (j*channels),  
  181.                   Dtype(0.0),  
  182.                   bout + (j*channels));  
  183.           //}else{  
  184.           //  caffe_set(channels, Dtype(0), bout + (j*channels));  
  185.           //}  
  186.         } else if (i==1) {  // p  
  187.           //if(dist_binary_.cpu_data()[j]>Dtype(0)){  
  188.               caffe_cpu_axpby(  
  189.                   channels,  
  190.                   alpha*sampleW[j],  
  191.                   diff_ap_.cpu_data() + (j*channels),  
  192.                   Dtype(0.0),  
  193.                   bout + (j*channels));  
  194.           //}else{  
  195.           //      caffe_set(channels, Dtype(0), bout + (j*channels));  
  196.           //}  
  197.         } else if (i==2) {  // n  
  198.           //if(dist_binary_.cpu_data()[j]>Dtype(0)){  
  199.               caffe_cpu_axpby(  
  200.                   channels,  
  201.                   alpha*sampleW[j],  
  202.                   diff_an_.cpu_data() + (j*channels),  
  203.                   Dtype(0.0),  
  204.                   bout + (j*channels));  
  205.            //}else{  
  206.            //   caffe_set(channels, Dtype(0), bout + (j*channels));  
  207.            //}  
  208.         }  
  209.       } // for num  
  210.     } //if propagate_down[i]  
  211.   } //for i  
  212. }  
  213.   
  214. #ifdef CPU_ONLY  
  215. STUB_GPU(TripletLossLayer);  
  216. #endif  
  217.   
  218. INSTANTIATE_CLASS(TripletLossLayer);  
  219. REGISTER_LAYER_CLASS(TripletLoss);  
  220.   
  221. }  // namespace caffe  
  222.   
  223. 4.在./src/caffe/layers/目录下新建triplet_loss_layer.cu,实现GPU下的前传和反传  
  224.   
  225. /* 
  226.  * triplet_loss_layer.cu 
  227.  * 
  228.  *  Created on: Jun 2, 2015 
  229.  *      Author: tangwei 
  230.  */  
  231.   
  232. #include <algorithm>  
  233. #include <vector>  
  234.   
  235. #include "caffe/layer.hpp"  
  236. #include "caffe/util/io.hpp"  
  237. #include "caffe/util/math_functions.hpp"  
  238. #include "caffe/vision_layers.hpp"  
  239.   
  240. namespace caffe {  
  241.   
  242. template <typename Dtype>  
  243. void TripletLossLayer<Dtype>::Forward_gpu(  
  244.     const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {  
  245.   const int count = bottom[0]->count();  
  246.   caffe_gpu_sub(  
  247.       count,  
  248.       bottom[0]->gpu_data(),  // a  
  249.       bottom[1]->gpu_data(),  // p  
  250.       diff_ap_.mutable_gpu_data());  // a_i-p_i  
  251.   caffe_gpu_sub(  
  252.       count,  
  253.       bottom[0]->gpu_data(),  // a  
  254.       bottom[2]->gpu_data(),  // n  
  255.       diff_an_.mutable_gpu_data());  // a_i-n_i  
  256.   caffe_gpu_sub(  
  257.       count,  
  258.       bottom[1]->gpu_data(),  // p  
  259.       bottom[2]->gpu_data(),  // n  
  260.       diff_pn_.mutable_gpu_data());  // p_i-n_i  
  261.   
  262.   caffe_gpu_powx(  
  263.       count,  
  264.       diff_ap_.mutable_gpu_data(),  // a_i-p_i  
  265.       Dtype(2),  
  266.       diff_sq_ap_.mutable_gpu_data());  // (a_i-p_i)^2  
  267.   caffe_gpu_gemv(  
  268.       CblasNoTrans,  
  269.       bottom[0]->num(),  
  270.       bottom[0]->channels(),  
  271.       Dtype(1.0),                                         //alpha  
  272.       diff_sq_ap_.gpu_data(),  // (a_i-p_i)^2                // A  
  273.       summer_vec_.gpu_data(),                             // x  
  274.       Dtype(0.0),                                         //belta  
  275.       dist_sq_ap_.mutable_gpu_data());  // \Sum (a_i-p_i)^2  //y  
  276.   
  277.   caffe_gpu_powx(  
  278.         count,  
  279.         diff_an_.mutable_gpu_data(),  // a_i-n_i  
  280.         Dtype(2),  
  281.         diff_sq_an_.mutable_gpu_data());  // (a_i-n_i)^2  
  282.   caffe_gpu_gemv(  
  283.         CblasNoTrans,  
  284.         bottom[0]->num(),  
  285.         bottom[0]->channels(),  
  286.         Dtype(1.0),                                         //alpha  
  287.         diff_sq_an_.gpu_data(),  // (a_i-n_i)^2                // A  
  288.         summer_vec_.gpu_data(),                             // x  
  289.         Dtype(0.0),                                         //belta  
  290.         dist_sq_an_.mutable_gpu_data());  // \Sum (a_i-n_i)^2  //y  
  291.   
  292.   Dtype margin = this->layer_param_.triplet_loss_param().margin();  
  293.   Dtype loss(0.0);  
  294.   const Dtype* sampleW = bottom[3]->cpu_data();  
  295.   for (int i = 0; i < bottom[0]->num(); ++i) {  
  296.      loss += sampleW[i]*std::max(margin +dist_sq_ap_.cpu_data()[i]- dist_sq_an_.cpu_data()[i], Dtype(0.0));  
  297.   }  
  298.   loss = loss / static_cast<Dtype>(bottom[0]->num()) / Dtype(2);  
  299.   top[0]->mutable_cpu_data()[0] = loss;  
  300. }  
  301.   
  302. template <typename Dtype>  
  303. __global__ void CLLBackward(const int count, const int channels,  
  304.     const Dtype margin, const Dtype alpha, const Dtype* sampleW,  
  305.     const Dtype* diff, const Dtype* dist_sq_ap_, const Dtype* dist_sq_an_,  
  306.     Dtype *bottom_diff) {  
  307.   CUDA_KERNEL_LOOP(i, count) {  
  308.     int n = i / channels;  // the num index, to access dist_sq_ap_ and dist_sq_an_  
  309.     Dtype mdist(0.0);  
  310.     mdist = margin +dist_sq_ap_[n] - dist_sq_an_[n];  
  311.     if (mdist > 0.0) {  
  312.         bottom_diff[i] = alpha*sampleW[n]*diff[i];  
  313.     } else {  
  314.         bottom_diff[i] = 0;  
  315.     }  
  316.   }  
  317. }  
  318.   
  319. template <typename Dtype>  
  320. void TripletLossLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,  
  321.     const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {  
  322.   Dtype margin = this->layer_param_.triplet_loss_param().margin();  
  323.   const int count = bottom[0]->count();  
  324.   const int channels = bottom[0]->channels();  
  325.   
  326.   for (int i = 0; i < 3; ++i) {  
  327.     if (propagate_down[i]) {  
  328.       const Dtype sign = (i < 2) ? -1 : 1;  
  329.       const Dtype alpha = sign * top[0]->cpu_diff()[0] /  
  330.           static_cast<Dtype>(bottom[0]->num());  
  331.       if(i==0){  
  332.           // NOLINT_NEXT_LINE(whitespace/operators)  
  333.           CLLBackward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  334.               count, channels, margin, alpha,  
  335.               bottom[3]->gpu_data(),  
  336.               diff_pn_.gpu_data(),  // the cached eltwise difference between p and n  
  337.               dist_sq_ap_.gpu_data(),  // the cached square distance between a and p  
  338.               dist_sq_an_.gpu_data(),  // the cached square distance between a and n  
  339.               bottom[i]->mutable_gpu_diff());  
  340.           CUDA_POST_KERNEL_CHECK;  
  341.       }else if(i==1){  
  342.           // NOLINT_NEXT_LINE(whitespace/operators)  
  343.           CLLBackward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  344.               count, channels, margin, alpha,  
  345.               bottom[3]->gpu_data(),  
  346.               diff_ap_.gpu_data(),  // the cached eltwise difference between a and p  
  347.               dist_sq_ap_.gpu_data(),  // the cached square distance between a and p  
  348.               dist_sq_an_.gpu_data(),  // the cached square distance between a and n  
  349.               bottom[i]->mutable_gpu_diff());  
  350.           CUDA_POST_KERNEL_CHECK;  
  351.       }else if(i==2){  
  352.           // NOLINT_NEXT_LINE(whitespace/operators)  
  353.           CLLBackward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  354.               count, channels, margin, alpha,  
  355.               bottom[3]->gpu_data(),  
  356.               diff_an_.gpu_data(),  // the cached eltwise difference between a and n  
  357.               dist_sq_ap_.gpu_data(),  // the cached square distance between a and p  
  358.               dist_sq_an_.gpu_data(),  // the cached square distance between a and n  
  359.               bottom[i]->mutable_gpu_diff());  
  360.           CUDA_POST_KERNEL_CHECK;  
  361.   
  362.       }  
  363.     }  
  364.   }  
  365. }  
  366.   
  367. INSTANTIATE_LAYER_GPU_FUNCS(TripletLossLayer);  
  368.   
  369. }  // namespace caffe  
  370.   
  371. 5. 在./src/caffe/test/目录下增加test_triplet_loss_layer.cpp  
  372.   
  373. /* 
  374.  * test_triplet_loss_layer.cpp 
  375.  * 
  376.  *  Created on: Jun 3, 2015 
  377.  *      Author: tangwei 
  378.  */  
  379.   
  380. #include <algorithm>  
  381. #include <cmath>  
  382. #include <cstdlib>  
  383. #include <cstring>  
  384. #include <vector>  
  385.   
  386. #include "gtest/gtest.h"  
  387.   
  388. #include "caffe/blob.hpp"  
  389. #include "caffe/common.hpp"  
  390. #include "caffe/filler.hpp"  
  391. #include "caffe/vision_layers.hpp"  
  392.   
  393. #include "caffe/test/test_caffe_main.hpp"  
  394. #include "caffe/test/test_gradient_check_util.hpp"  
  395.   
  396. namespace caffe {  
  397.   
  398. template <typename TypeParam>  
  399. class TripletLossLayerTest : public MultiDeviceTest<TypeParam> {  
  400.   typedef typename TypeParam::Dtype Dtype;  
  401.   
  402.  protected:  
  403.   TripletLossLayerTest()  
  404.       : blob_bottom_data_i_(new Blob<Dtype>(512, 2, 1, 1)),  
  405.         blob_bottom_data_j_(new Blob<Dtype>(512, 2, 1, 1)),  
  406.         blob_bottom_data_k_(new Blob<Dtype>(512, 2, 1, 1)),  
  407.         blob_bottom_y_(new Blob<Dtype>(512, 1, 1, 1)),  
  408.         blob_top_loss_(new Blob<Dtype>()) {  
  409.     // fill the values  
  410.     FillerParameter filler_param;  
  411.     filler_param.set_min(-1.0);  
  412.     filler_param.set_max(1.0);  // distances~=1.0 to test both sides of margin  
  413.     UniformFiller<Dtype> filler(filler_param);  
  414.     filler.Fill(this->blob_bottom_data_i_);  
  415.     blob_bottom_vec_.push_back(blob_bottom_data_i_);  
  416.     filler.Fill(this->blob_bottom_data_j_);  
  417.     blob_bottom_vec_.push_back(blob_bottom_data_j_);  
  418.     filler.Fill(this->blob_bottom_data_k_);  
  419.     blob_bottom_vec_.push_back(blob_bottom_data_k_);  
  420.     for (int i = 0; i < blob_bottom_y_->count(); ++i) {  
  421.         blob_bottom_y_->mutable_cpu_data()[i] = caffe_rng_rand() % 2;  // 0 or 1  
  422.     }  
  423.     blob_bottom_vec_.push_back(blob_bottom_y_);  
  424.     blob_top_vec_.push_back(blob_top_loss_);  
  425.   }  
  426.   virtual ~TripletLossLayerTest() {  
  427.     delete blob_bottom_data_i_;  
  428.     delete blob_bottom_data_j_;  
  429.     delete blob_bottom_data_k_;  
  430.     delete blob_top_loss_;  
  431.   }  
  432.   
  433.   Blob<Dtype>* const blob_bottom_data_i_;  
  434.   Blob<Dtype>* const blob_bottom_data_j_;  
  435.   Blob<Dtype>* const blob_bottom_data_k_;  
  436.   Blob<Dtype>* const blob_bottom_y_;  
  437.   Blob<Dtype>* const blob_top_loss_;  
  438.   vector<Blob<Dtype>*> blob_bottom_vec_;  
  439.   vector<Blob<Dtype>*> blob_top_vec_;  
  440. };  
  441.   
  442. TYPED_TEST_CASE(TripletLossLayerTest, TestDtypesAndDevices);  
  443.   
  444. TYPED_TEST(TripletLossLayerTest, TestForward) {  
  445.   typedef typename TypeParam::Dtype Dtype;  
  446.   LayerParameter layer_param;  
  447.   TripletLossLayer<Dtype> layer(layer_param);  
  448.   layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_);  
  449.   layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_);  
  450.   // manually compute to compare  
  451.   const Dtype margin = layer_param.triplet_loss_param().margin();  
  452.   const int num = this->blob_bottom_data_i_->num();  
  453.   const int channels = this->blob_bottom_data_i_->channels();           
  454.   const Dtype *sampleW = this->blob_bottom_y_->cpu_data();  
  455.   
  456. Dtype loss(0);                                                                                                          
  457.   for (int i = 0; i < num; ++i) {  
  458.     Dtype dist_sq_ij(0);  
  459.     Dtype dist_sq_ik(0);  
  460.     for (int j = 0; j < channels; ++j) {  
  461.       Dtype diff_ij = this->blob_bottom_data_i_->cpu_data()[i*channels+j] -  
  462.           this->blob_bottom_data_j_->cpu_data()[i*channels+j];  
  463.       dist_sq_ij += diff_ij*diff_ij;  
  464.       Dtype diff_ik = this->blob_bottom_data_i_->cpu_data()[i*channels+j] -  
  465.           this->blob_bottom_data_k_->cpu_data()[i*channels+j];  
  466.       dist_sq_ik += diff_ik*diff_ik;  
  467.     }  
  468.     loss += sampleW[i]*std::max(Dtype(0.0), margin+dist_sq_ij-dist_sq_ik);  
  469.   }  
  470.   loss /= static_cast<Dtype>(num) * Dtype(2);  
  471.   EXPECT_NEAR(this->blob_top_loss_->cpu_data()[0], loss, 1e-6);  
  472. }  
  473.   
  474. TYPED_TEST(TripletLossLayerTest, TestGradient) {  
  475.   typedef typename TypeParam::Dtype Dtype;  
  476.   LayerParameter layer_param;  
  477.   TripletLossLayer<Dtype> layer(layer_param);  
  478.   layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_);  
  479.   GradientChecker<Dtype> checker(1e-2, 1e-2, 1701);  
  480.   // check the gradient for the first two bottom layers  
  481.   checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_,  
  482.       this->blob_top_vec_, 0);  
  483.   checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_,  
  484.       this->blob_top_vec_, 1);  
  485. }  
  486.   
  487. }  // namespace caffe  
  488.   
  489. 3.编译测试  
  490. 重新 make all 如果出错,检查代码语法错误。  
  491. make test  
  492. make runtest 如果成功,全是绿色的OK  否则会给出红色提示,就得看看是不是实现逻辑上出错了。  

==============================================================================================================================

然后是添加PrecisionRecallLosslayer,感谢一位中科院的朋友。

1、首先在caffe.proto文件中添加:

2、然后在所属层loss_layer.hpp中添加定义

3、然后添加改层~/caffe-add/src/caffe/layers/precision_recall_loss_layer.cpp的实现:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <algorithm>  
  2. #include <cfloat>  
  3. #include <cmath>  
  4. #include <vector>  
  5. #include <opencv2/opencv.hpp>  
  6.   
  7. #include "caffe/layer.hpp"  
  8. #include "caffe/util/io.hpp"  
  9. #include "caffe/util/math_functions.hpp"  
  10. #include "caffe/vision_layers.hpp"  
  11.   
  12. namespace caffe {  
  13.   
  14. template <typename Dtype>  
  15. void PrecisionRecallLossLayer<Dtype>::LayerSetUp(  
  16.   const vector<Blob<Dtype>*> &bottom, const vector<Blob<Dtype>*> &top) {  
  17.   LossLayer<Dtype>::LayerSetUp(bottom, top);  
  18. }  
  19.   
  20. template <typename Dtype>  
  21. void PrecisionRecallLossLayer<Dtype>::Reshape(  
  22.   const vector<Blob<Dtype>*> &bottom,  
  23.   const vector<Blob<Dtype>*> &top) {  
  24.   LossLayer<Dtype>::Reshape(bottom, top);  
  25.   loss_.Reshape(bottom[0]->num(), bottom[0]->channels(),  
  26.                 bottom[0]->height(), bottom[0]->width());  
  27.   
  28.   // Check the shapes of data and label  
  29.   CHECK_EQ(bottom[0]->num(), bottom[1]->num())  
  30.       << "The number of num of data and label should be same.";  
  31.   CHECK_EQ(bottom[0]->channels(), bottom[1]->channels())  
  32.       << "The number of channels of data and label should be same.";  
  33.   CHECK_EQ(bottom[0]->height(), bottom[1]->height())  
  34.       << "The heights of data and label should be same.";  
  35.   CHECK_EQ(bottom[0]->width(), bottom[1]->width())  
  36.       << "The width of data and label should be same.";  
  37. }  
  38.   
  39. template <typename Dtype>  
  40. void PrecisionRecallLossLayer<Dtype>::Forward_cpu(  
  41.   const vector<Blob<Dtype>*> &bottom, const vector<Blob<Dtype>*> &top) {  
  42.   const Dtype *data = bottom[0]->cpu_data();  
  43.   const Dtype *label = bottom[1]->cpu_data();  
  44.   const int num = bottom[0]->num();  
  45.   const int dim = bottom[0]->count() / num;  
  46.   const int channels = bottom[0]->channels();  
  47.   const int spatial_dim = bottom[0]->height() * bottom[0]->width();  
  48.   const int pnum =  
  49.     this->layer_param_.precision_recall_loss_param().point_num();  
  50.   top[0]->mutable_cpu_data()[0] = 0;  
  51.   for (int c = 0; c < channels; ++c) {  
  52.     Dtype breakeven = 0.0;  
  53.     Dtype prec_diff = 1.0;  
  54.     for (int p = 0; p <= pnum; ++p) {  
  55.       int true_positive = 0;  
  56.       int false_positive = 0;  
  57.       int false_negative = 0;  
  58.       int true_negative = 0;  
  59.       for (int i = 0; i < num; ++i) {  
  60.         const Dtype thresh = 1.0 / pnum * p;  
  61.         for (int j = 0; j < spatial_dim; ++j) {  
  62.           const Dtype data_value = data[i * dim + c * spatial_dim + j];  
  63.           const int label_value = (int)label[i * dim + c * spatial_dim + j];  
  64.           if (label_value == 1 && data_value >= thresh) {  
  65.             ++true_positive;  
  66.           }  
  67.           if (label_value == 0 && data_value >= thresh) {  
  68.             ++false_positive;  
  69.           }  
  70.           if (label_value == 1 && data_value < thresh) {  
  71.             ++false_negative;  
  72.           }  
  73.           if (label_value == 0 && data_value < thresh) {  
  74.             ++true_negative;  
  75.           }  
  76.         }  
  77.       }  
  78.       Dtype precision = 0.0;  
  79.       Dtype recall = 0.0;  
  80.       if (true_positive + false_positive > 0) {  
  81.         precision =  
  82.           (Dtype)true_positive / (Dtype)(true_positive + false_positive);  
  83.       } else if (true_positive == 0) {  
  84.         precision = 1.0;  
  85.       }  
  86.       if (true_positive + false_negative > 0) {  
  87.         recall =  
  88.           (Dtype)true_positive / (Dtype)(true_positive + false_negative);  
  89.       } else if (true_positive == 0) {  
  90.         recall = 1.0;  
  91.       }  
  92.       if (prec_diff > fabs(precision - recall)  
  93.           && precision > 0 && precision < 1  
  94.           && recall > 0 && recall < 1) {  
  95.         breakeven = precision;  
  96.         prec_diff = fabs(precision - recall);  
  97.       }  
  98.     }  
  99.     top[0]->mutable_cpu_data()[0] += 1.0 - breakeven;  
  100.   }  
  101.   top[0]->mutable_cpu_data()[0] /= channels;  
  102. }  
  103.   
  104. template <typename Dtype>  
  105. void PrecisionRecallLossLayer<Dtype>::Backward_cpu(  
  106.   const vector<Blob<Dtype>*> &top,  
  107.   const vector<bool> &propagate_down,  
  108.   const vector<Blob<Dtype>*> &bottom) {  
  109.   for (int i = 0; i < propagate_down.size(); ++i) {  
  110.     if (propagate_down[i]) { NOT_IMPLEMENTED; }  
  111.   }  
  112. }  
  113.   
  114. #ifdef CPU_ONLY  
  115. STUB_GPU(PrecisionRecallLossLayer);  
  116. #endif  
  117. INSTANTIATE_CLASS(PrecisionRecallLossLayer);  
  118. REGISTER_LAYER_CLASS(PrecisionRecallLoss);  
  119.   
  120. }  // namespace caffe  
4、继续添加gpu的设置~/caffe-add/src/caffe/layers/precision_recall_loss_layer.cu:
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <algorithm>  
  2. #include <cfloat>  
  3. #include <vector>  
  4.   
  5. #include "thrust/device_vector.h"  
  6.   
  7. #include "caffe/layer.hpp"  
  8. #include "caffe/util/math_functions.hpp"  
  9. #include "caffe/vision_layers.hpp"  
  10.   
  11. namespace caffe {  
  12.   
  13. template <typename Dtype>  
  14. void PrecisionRecallLossLayer<Dtype>::Forward_gpu(  
  15.   const vector<Blob<Dtype>*> &bottom, const vector<Blob<Dtype>*> &top) {  
  16.   Forward_cpu(bottom, top);  
  17. }  
  18. template <typename Dtype>  
  19. void PrecisionRecallLossLayer<Dtype>::Backward_gpu(  
  20.   const vector<Blob<Dtype>*> &top,  
  21.   const vector<bool> &propagate_down,  
  22.   const vector<Blob<Dtype>*> &bottom) {  
  23.   if (propagate_down[1]) {  
  24.     LOG(FATAL) << this->type()  
  25.                << " Layer cannot backpropagate to label inputs.";  
  26.   }  
  27.   if (propagate_down[0]) {  
  28.     Backward_cpu(top, propagate_down, bottom);  
  29.   }  
  30. }  
  31.   
  32. INSTANTIATE_LAYER_GPU_FUNCS(PrecisionRecallLossLayer);  
  33.   
  34. }  // namespace caffe  

5、通过简单的minst测试,修改训练配置文件:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ............  
  2. layer {  
  3.   name: "loss"  
  4.   type: "SoftmaxWithLoss"  
  5.   bottom: "ip2"  
  6.   bottom: "label"  
  7.   top: "loss"  
  8. }  
  9. layer {  
  10.   name: "precision_recall_loss"  
  11.   type: "PrecisionRecallLoss"  
  12.   bottom: "ip2"  
  13.   bottom: "label"  
  14.   top: "error_rate"  
  15.   include {  
  16.     phase: TEST  
  17.   }  
  18. }  
6、然后训练



  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值