caffe加层

yunmingzhang17  和caffe官网 都有介绍添加层,但是不是很详细,我就简单实现一下这个加层,新手学习,请多多指教。  

 

This is a post outlining the steps you need to take to create your own layer in CAFFE, a popular framework for writing convolutional neural networks. The post focuses on the latest version of CAFE as of Jan 2015.

NOTES:

  • I use $CAFFEROOT and /caffe/ interchangeably, this is simply the root directory of the caffe installation.

A general and slightly outdated tutorial can be found here (https://github.com/BVLC/caffe/wiki/Development).

  1. Create the definition a new class in one of the .hpp files located in $CAFFEROOT/include/caffe/ . In my case, I am writing a customized convolution layer. As a result, I modify thevision_layers.hpp to add a definition of myConvLayer.
  2. Next we need to create a myConvLayer.cpp file in the following path $CAFFEROOT/src/caffe/myConvLayer.cpp .
    1. Implement the virtual methods required of the class. In my case, I needed to implement the required “LayerSetUp”, “Reshape”,”ForwardCPU” and “BackwardCPU”.
  3. Choose a name for your layer and write it in caffe/src/caffe/proto/caffe.proto
    1. Find a message called LayerParameter
    2. Find the latest unoccupied number, there should be a comment above the message declaration saying “the next available ID when you create….”, use the smallestUnoccupiedNumber
    3. Add your layer to the LayerType enum, for example, I add “MYCONVOLUTIONLAYER = 38”
  4. If you have completed step 1 and step 2, you should be able to just compile the entire CAFFE directory fine. The next steps will require you to actually write a network and run it to get the protobuf set up right. To do this, I recommend simply use an existing network. I chose MNIST LENET and replaced the convolution layer in (/caffe/examples/mnist_modified/lenet_train_test.protxt). To get it to run with my own set up, I
    1. Created a modified directory(mint_modified) that copies minist in examples.
    2. Change the lent_solver.prototxt to use my own file. CAFFE used hardcoded path, when it should have used relative path to find the training configuration set up.
      1. TYPE = MYCONVOLUTION (depending on your declaration in the protobuf file in the previous step)
    3. Once you are done getting your own layer running within an existing network, it will crash immediately because we haven’t worked on getting
  5. Dealing with protobuf and layer_factory
    1. Now you should see an error massage saying “unknown type 38” from a file called “layer_factory.cpp”. You can find the file at caffe/src/caffe/layer_factory.cpp. The error message tells you that currently CAFFE cannot recognize the parameter specified in the protobuf file “myconvolution”. To do this, you simply need to add a new case statement at the end of “layer_factory.cpp” file.
    2.   case LayerParameter_LayerType_MYCONVOLUTION:return new MyConvolutionLayer<Dtype>(param);
    3. This statement tells the system to use layer_factory to create the class whenever that parameter is being read
  6. The last part is to make sure that your own layers is using the parameters that you want.
    1. An interesting note here is that the parameter has no fixed paring. The way it is specified in protobuf file for example, is nesting a parameter type within a layer type. As a result, you can switch the parameters among different layers. That is I could have used the original convolution_parameter inside MyConvolution layer.
    2. To use my own set of parameter, I went back to caffe/src/caffe/proto/caffe.proto file
      1. Define a new parameter type
        1. “myconvolution_param = 42”
      2. Define a new message class
        1. MyConvolutionPoolingParameter { optional uint32 num_output =1; …. }
      3. Then go back to the lenet_train_test.protxt file and set your layer to use the my convolution parameter in myconvolutionpooling layer.
        1. An example layers { name:’myconv1′ type:MYCONVOLUTION; ….. myconvolution_param { num_output: 20 kernel_size ….}}
      4. One last step is modifying the $CAFFEROOT/src/caffe/myConvLayer.cpp to use the my convolution_param. You can access the parameters by coding             “ConvolutionPoolingParameter convpool_param =                                                    this->layer_param_.convolutionpooling_param();”

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

先就按照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


  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


  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


  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


  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、然后训练



yunmingzhang17  和caffe官网 都有介绍添加层,但是不是很详细,我就简单实现一下这个加层,新手学习,请多多指教。  

 

This is a post outlining the steps you need to take to create your own layer in CAFFE, a popular framework for writing convolutional neural networks. The post focuses on the latest version of CAFE as of Jan 2015.

NOTES:

  • I use $CAFFEROOT and /caffe/ interchangeably, this is simply the root directory of the caffe installation.

A general and slightly outdated tutorial can be found here (https://github.com/BVLC/caffe/wiki/Development).

  1. Create the definition a new class in one of the .hpp files located in $CAFFEROOT/include/caffe/ . In my case, I am writing a customized convolution layer. As a result, I modify thevision_layers.hpp to add a definition of myConvLayer.
  2. Next we need to create a myConvLayer.cpp file in the following path $CAFFEROOT/src/caffe/myConvLayer.cpp .
    1. Implement the virtual methods required of the class. In my case, I needed to implement the required “LayerSetUp”, “Reshape”,”ForwardCPU” and “BackwardCPU”.
  3. Choose a name for your layer and write it in caffe/src/caffe/proto/caffe.proto
    1. Find a message called LayerParameter
    2. Find the latest unoccupied number, there should be a comment above the message declaration saying “the next available ID when you create….”, use the smallestUnoccupiedNumber
    3. Add your layer to the LayerType enum, for example, I add “MYCONVOLUTIONLAYER = 38”
  4. If you have completed step 1 and step 2, you should be able to just compile the entire CAFFE directory fine. The next steps will require you to actually write a network and run it to get the protobuf set up right. To do this, I recommend simply use an existing network. I chose MNIST LENET and replaced the convolution layer in (/caffe/examples/mnist_modified/lenet_train_test.protxt). To get it to run with my own set up, I
    1. Created a modified directory(mint_modified) that copies minist in examples.
    2. Change the lent_solver.prototxt to use my own file. CAFFE used hardcoded path, when it should have used relative path to find the training configuration set up.
      1. TYPE = MYCONVOLUTION (depending on your declaration in the protobuf file in the previous step)
    3. Once you are done getting your own layer running within an existing network, it will crash immediately because we haven’t worked on getting
  5. Dealing with protobuf and layer_factory
    1. Now you should see an error massage saying “unknown type 38” from a file called “layer_factory.cpp”. You can find the file at caffe/src/caffe/layer_factory.cpp. The error message tells you that currently CAFFE cannot recognize the parameter specified in the protobuf file “myconvolution”. To do this, you simply need to add a new case statement at the end of “layer_factory.cpp” file.
    2.   case LayerParameter_LayerType_MYCONVOLUTION:return new MyConvolutionLayer<Dtype>(param);
    3. This statement tells the system to use layer_factory to create the class whenever that parameter is being read
  6. The last part is to make sure that your own layers is using the parameters that you want.
    1. An interesting note here is that the parameter has no fixed paring. The way it is specified in protobuf file for example, is nesting a parameter type within a layer type. As a result, you can switch the parameters among different layers. That is I could have used the original convolution_parameter inside MyConvolution layer.
    2. To use my own set of parameter, I went back to caffe/src/caffe/proto/caffe.proto file
      1. Define a new parameter type
        1. “myconvolution_param = 42”
      2. Define a new message class
        1. MyConvolutionPoolingParameter { optional uint32 num_output =1; …. }
      3. Then go back to the lenet_train_test.protxt file and set your layer to use the my convolution parameter in myconvolutionpooling layer.
        1. An example layers { name:’myconv1′ type:MYCONVOLUTION; ….. myconvolution_param { num_output: 20 kernel_size ….}}
      4. One last step is modifying the $CAFFEROOT/src/caffe/myConvLayer.cpp to use the my convolution_param. You can access the parameters by coding             “ConvolutionPoolingParameter convpool_param =                                                    this->layer_param_.convolutionpooling_param();”

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

先就按照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


  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


  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


  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


  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、然后训练



猜你喜欢

转载自blog.csdn.net/qq_31511955/article/details/78029941