如何在caffe中增加layer以及caffe中triplet loss layer的实现

关于triplet loss的原理,目标函数和梯度推导在上一篇博客中已经讲过了,具体见:triplet loss原理以及梯度推导,这篇博文主要是讲caffe下实现triplet loss,编程菜鸟,如果有写的不优化的地方,欢迎指出。


1.如何在caffe中增加新的layer

新版的caffe中增加新的layer,变得轻松多了,概括说来,分四步:
1)在./src/caffe/proto/caffe.proto 中增加 对应layer的paramter message;
2)在./include/caffe/***layers.hpp中增加该layer的类的声明,***表示有common_layers.hpp, data_layers.hpp, neuron_layers.hpp, vision_layers.hpp 和loss_layers.hpp等;
3)在./src/caffe/layers/目录下新建.cpp和.cu文件,进行类实现。
4)在./src/caffe/gtest/中增加layer的测试代码,对所写的layer前传和反传进行测试,测试还包括速度。
最后一步很多人省了,或者没意识到,但是为保证代码正确,建议还是严格进行测试,磨刀不误砍柴功。

2.caffe中实现triplet loss layer


1.caffe.proto中增加triplet loss layer的定义

首先在message LayerParameter中追加 optional TripletLossParameter triplet_loss_param = 138; 其中138是我目前LayerParameter message中现有元素的个数,具体是多少,可以看LayerParameter message上面注释中的:
[cpp]  view plain copy
  1. //LayerParameter next available layer-specific ID: 134 (last added: reshape_param)  
然后增加Message:
[html]  view plain copy
  1. message TripletLossParameter {  
  2.      // margin for dissimilar pair  
  3.     optional float margin = 1 [default = 1.0];   
  4. }  
其中 margin就是定义 triplet loss原理以及梯度推导所讲的alpha。

2.在./include/caffe/loss_layers.hpp中增加triplet loss layer的类的声明

具体解释见注释,主要的是定义了一些变量,用来在前传中存储中间计算结果,以便在反传的时候避免重复计算。

[cpp]  view plain copy
  1. /** 
  2.  * @brief Computes the triplet loss 
  3.  */  
  4. template <typename Dtype>  
  5. class TripletLossLayer : public LossLayer<Dtype> {  
  6.  public:  
  7.   explicit TripletLossLayer(const LayerParameter& param)  
  8.       : LossLayer<Dtype>(param){}  
  9.   virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,  
  10.       const vector<Blob<Dtype>*>& top);  
  11.   
  12.   virtual inline int ExactNumBottomBlobs() const { return 4; }  
  13.   virtual inline const char* type() const { return "TripletLoss"; }  
  14.   /** 
  15.    * Unlike most loss layers, in the TripletLossLayer we can backpropagate 
  16.    * to the first three inputs. 
  17.    */  
  18.   virtual inline bool AllowForceBackward(const int bottom_index) const {  
  19.     return bottom_index != 3;  
  20.   }  
  21.   
  22.  protected:  
  23.   virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  24.       const vector<Blob<Dtype>*>& top);  
  25.   virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  26.       const vector<Blob<Dtype>*>& top);  
  27.   
  28.   virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,  
  29.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  30.   virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,  
  31.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  32.   
  33.   Blob<Dtype> diff_ap_;  // cached for backward pass  
  34.   Blob<Dtype> diff_an_;  // cached for backward pass  
  35.   Blob<Dtype> diff_pn_;  // cached for backward pass  
  36.   
  37.   Blob<Dtype> diff_sq_ap_;  // cached for backward pass  
  38.   Blob<Dtype> diff_sq_an_;  // tmp storage for gpu forward pass  
  39.   
  40.   Blob<Dtype> dist_sq_ap_;  // cached for backward pass  
  41.   Blob<Dtype> dist_sq_an_;  // cached for backward pass  
  42.   
  43.   Blob<Dtype> summer_vec_;  // tmp storage for gpu forward pass  
  44.   Blob<Dtype> dist_binary_;  // tmp storage for gpu forward pass  
  45. };  

3. 在./src/caffe/layers/目录下新建triplet_loss_layer.cpp,实现类

主要实现三个功能:
LayerSetUp:主要是做一些CHECK工作,然后根据bottom和top对类中的数据成员初始化。
Forward_cpu:前传,计算loss
Backward_cpu:反传,计算梯度。
[cpp]  view plain copy
  1. /* 
  2.  * triplet_loss_layer.cpp 
  3.  * 
  4.  *  Created on: Jun 2, 2015 
  5.  *      Author: tangwei 
  6.  */  
  7.   
  8. #include <algorithm>  
  9. #include <vector>  
  10.   
  11. #include "caffe/layer.hpp"  
  12. #include "caffe/loss_layers.hpp"  
  13. #include "caffe/util/io.hpp"  
  14. #include "caffe/util/math_functions.hpp"  
  15.   
  16. namespace caffe {  
  17.   
  18. template <typename Dtype>  
  19. void TripletLossLayer<Dtype>::LayerSetUp(  
  20.   const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {  
  21.   LossLayer<Dtype>::LayerSetUp(bottom, top);  
  22.   CHECK_EQ(bottom[0]->num(), bottom[1]->num());  
  23.   CHECK_EQ(bottom[1]->num(), bottom[2]->num());  
  24.   CHECK_EQ(bottom[0]->channels(), bottom[1]->channels());  
  25.   CHECK_EQ(bottom[1]->channels(), bottom[2]->channels());  
  26.   CHECK_EQ(bottom[0]->height(), 1);  
  27.   CHECK_EQ(bottom[0]->width(), 1);  
  28.   CHECK_EQ(bottom[1]->height(), 1);  
  29.   CHECK_EQ(bottom[1]->width(), 1);  
  30.   CHECK_EQ(bottom[2]->height(), 1);  
  31.   CHECK_EQ(bottom[2]->width(), 1);  
  32.   
  33.   CHECK_EQ(bottom[3]->channels(),1);  
  34.   CHECK_EQ(bottom[3]->height(), 1);  
  35.   CHECK_EQ(bottom[3]->width(), 1);  
  36.   
  37.   diff_ap_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  38.   diff_an_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  39.   diff_pn_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  40.   
  41.   diff_sq_ap_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  42.   diff_sq_an_.Reshape(bottom[0]->num(), bottom[0]->channels(), 1, 1);  
  43.   dist_sq_ap_.Reshape(bottom[0]->num(), 1, 1, 1);  
  44.   dist_sq_an_.Reshape(bottom[0]->num(), 1, 1, 1);  
  45.   // vector of ones used to sum along channels  
  46.   summer_vec_.Reshape(bottom[0]->channels(), 1, 1, 1);  
  47.   for (int i = 0; i < bottom[0]->channels(); ++i)  
  48.       summer_vec_.mutable_cpu_data()[i] = Dtype(1);  
  49.   dist_binary_.Reshape(bottom[0]->num(), 1, 1, 1);  
  50.     for (int i = 0; i < bottom[0]->num(); ++i)  
  51.         dist_binary_.mutable_cpu_data()[i] = Dtype(1);  
  52. }  
  53.   
  54. template <typename Dtype>  
  55. void TripletLossLayer<Dtype>::Forward_cpu(  
  56.     const vector<Blob<Dtype>*>& bottom,  
  57.     const vector<Blob<Dtype>*>& top) {  
  58.   int count = bottom[0]->count();  
  59.   const Dtype* sampleW = bottom[3]->cpu_data();  
  60.   caffe_sub(  
  61.       count,  
  62.       bottom[0]->cpu_data(),  // a  
  63.       bottom[1]->cpu_data(),  // p  
  64.       diff_ap_.mutable_cpu_data());  // a_i-p_i  
  65.   caffe_sub(  
  66.        count,  
  67.        bottom[0]->cpu_data(),  // a  
  68.        bottom[2]->cpu_data(),  // n  
  69.        diff_an_.mutable_cpu_data());  // a_i-n_i  
  70.   caffe_sub(  
  71.        count,  
  72.        bottom[1]->cpu_data(),  // p  
  73.        bottom[2]->cpu_data(),  // n  
  74.        diff_pn_.mutable_cpu_data());  // p_i-n_i  
  75.   const int channels = bottom[0]->channels();  
  76.   Dtype margin = this->layer_param_.triplet_loss_param().margin();  
  77.   
  78.   Dtype loss(0.0);  
  79.   for (int i = 0; i < bottom[0]->num(); ++i) {  
  80.     dist_sq_ap_.mutable_cpu_data()[i] = caffe_cpu_dot(channels,  
  81.         diff_ap_.cpu_data() + (i*channels), diff_ap_.cpu_data() + (i*channels));  
  82.     dist_sq_an_.mutable_cpu_data()[i] = caffe_cpu_dot(channels,  
  83.         diff_an_.cpu_data() + (i*channels), diff_an_.cpu_data() + (i*channels));  
  84.     Dtype mdist = sampleW[i]*std::max(margin + dist_sq_ap_.cpu_data()[i] - dist_sq_an_.cpu_data()[i], Dtype(0.0));  
  85.     loss += mdist;  
  86.     if(mdist==Dtype(0)){  
  87.         //dist_binary_.mutable_cpu_data()[i] = Dtype(0);  
  88.         //prepare for backward pass  
  89.         caffe_set(channels, Dtype(0), diff_ap_.mutable_cpu_data() + (i*channels));  
  90.         caffe_set(channels, Dtype(0), diff_an_.mutable_cpu_data() + (i*channels));  
  91.         caffe_set(channels, Dtype(0), diff_pn_.mutable_cpu_data() + (i*channels));  
  92.     }  
  93.   }  
  94.   loss = loss / static_cast<Dtype>(bottom[0]->num()) / Dtype(2);  
  95.   top[0]->mutable_cpu_data()[0] = loss;  
  96. }  
  97.   
  98. template <typename Dtype>  
  99. void TripletLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,  
  100.     const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {  
  101.   //Dtype margin = this->layer_param_.contrastive_loss_param().margin();  
  102.   const Dtype* sampleW = bottom[3]->cpu_data();  
  103.   for (int i = 0; i < 3; ++i) {  
  104.     if (propagate_down[i]) {  
  105.       const Dtype sign = (i < 2) ? -1 : 1;  
  106.       const Dtype alpha = sign * top[0]->cpu_diff()[0] /  
  107.           static_cast<Dtype>(bottom[i]->num());  
  108.       int num = bottom[i]->num();  
  109.       int channels = bottom[i]->channels();  
  110.       for (int j = 0; j < num; ++j) {  
  111.         Dtype* bout = bottom[i]->mutable_cpu_diff();  
  112.         if (i==0) {  // a  
  113.           //if(dist_binary_.cpu_data()[j]>Dtype(0)){  
  114.               caffe_cpu_axpby(  
  115.                   channels,  
  116.                   alpha*sampleW[j],  
  117.                   diff_pn_.cpu_data() + (j*channels),  
  118.                   Dtype(0.0),  
  119.                   bout + (j*channels));  
  120.           //}else{  
  121.           //  caffe_set(channels, Dtype(0), bout + (j*channels));  
  122.           //}  
  123.         } else if (i==1) {  // p  
  124.           //if(dist_binary_.cpu_data()[j]>Dtype(0)){  
  125.               caffe_cpu_axpby(  
  126.                   channels,  
  127.                   alpha*sampleW[j],  
  128.                   diff_ap_.cpu_data() + (j*channels),  
  129.                   Dtype(0.0),  
  130.                   bout + (j*channels));  
  131.           //}else{  
  132.           //      caffe_set(channels, Dtype(0), bout + (j*channels));  
  133.           //}  
  134.         } else if (i==2) {  // n  
  135.           //if(dist_binary_.cpu_data()[j]>Dtype(0)){  
  136.               caffe_cpu_axpby(  
  137.                   channels,  
  138.                   alpha*sampleW[j],  
  139.                   diff_an_.cpu_data() + (j*channels),  
  140.                   Dtype(0.0),  
  141.                   bout + (j*channels));  
  142.            //}else{  
  143.            //   caffe_set(channels, Dtype(0), bout + (j*channels));  
  144.            //}  
  145.         }  
  146.       } // for num  
  147.     } //if propagate_down[i]  
  148.   } //for i  
  149. }  
  150.   
  151. #ifdef CPU_ONLY  
  152. STUB_GPU(TripletLossLayer);  
  153. #endif  
  154.   
  155. INSTANTIATE_CLASS(TripletLossLayer);  
  156. REGISTER_LAYER_CLASS(TripletLoss);  
  157.   
  158. }  // namespace caffe  

4.在./src/caffe/layers/目录下新建triplet_loss_layer.cu,实现GPU下的前传和反传

在GPU下实现前传和反传
[cpp]  view plain copy
  1. /* 
  2.  * triplet_loss_layer.cu 
  3.  * 
  4.  *  Created on: Jun 2, 2015 
  5.  *      Author: tangwei 
  6.  */  
  7.   
  8. #include <algorithm>  
  9. #include <vector>  
  10.   
  11. #include "caffe/layer.hpp"  
  12. #include "caffe/util/io.hpp"  
  13. #include "caffe/util/math_functions.hpp"  
  14. #include "caffe/vision_layers.hpp"  
  15.   
  16. namespace caffe {  
  17.   
  18. template <typename Dtype>  
  19. void TripletLossLayer<Dtype>::Forward_gpu(  
  20.     const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {  
  21.   const int count = bottom[0]->count();  
  22.   caffe_gpu_sub(  
  23.       count,  
  24.       bottom[0]->gpu_data(),  // a  
  25.       bottom[1]->gpu_data(),  // p  
  26.       diff_ap_.mutable_gpu_data());  // a_i-p_i  
  27.   caffe_gpu_sub(  
  28.       count,  
  29.       bottom[0]->gpu_data(),  // a  
  30.       bottom[2]->gpu_data(),  // n  
  31.       diff_an_.mutable_gpu_data());  // a_i-n_i  
  32.   caffe_gpu_sub(  
  33.       count,  
  34.       bottom[1]->gpu_data(),  // p  
  35.       bottom[2]->gpu_data(),  // n  
  36.       diff_pn_.mutable_gpu_data());  // p_i-n_i  
  37.   
  38.   caffe_gpu_powx(  
  39.       count,  
  40.       diff_ap_.mutable_gpu_data(),  // a_i-p_i  
  41.       Dtype(2),  
  42.       diff_sq_ap_.mutable_gpu_data());  // (a_i-p_i)^2  
  43.   caffe_gpu_gemv(  
  44.       CblasNoTrans,  
  45.       bottom[0]->num(),  
  46.       bottom[0]->channels(),  
  47.       Dtype(1.0),                                         //alpha  
  48.       diff_sq_ap_.gpu_data(),  // (a_i-p_i)^2                // A  
  49.       summer_vec_.gpu_data(),                             // x  
  50.       Dtype(0.0),                                         //belta  
  51.       dist_sq_ap_.mutable_gpu_data());  // \Sum (a_i-p_i)^2  //y  
  52.   
  53.   caffe_gpu_powx(  
  54.         count,  
  55.         diff_an_.mutable_gpu_data(),  // a_i-n_i  
  56.         Dtype(2),  
  57.         diff_sq_an_.mutable_gpu_data());  // (a_i-n_i)^2  
  58.   caffe_gpu_gemv(  
  59.         CblasNoTrans,  
  60.         bottom[0]->num(),  
  61.         bottom[0]->channels(),  
  62.         Dtype(1.0),                                         //alpha  
  63.         diff_sq_an_.gpu_data(),  // (a_i-n_i)^2                // A  
  64.         summer_vec_.gpu_data(),                             // x  
  65.         Dtype(0.0),                                         //belta  
  66.         dist_sq_an_.mutable_gpu_data());  // \Sum (a_i-n_i)^2  //y  
  67.   
  68.   Dtype margin = this->layer_param_.triplet_loss_param().margin();  
  69.   Dtype loss(0.0);  
  70.   const Dtype* sampleW = bottom[3]->cpu_data();  
  71.   for (int i = 0; i < bottom[0]->num(); ++i) {  
  72.      loss += sampleW[i]*std::max(margin +dist_sq_ap_.cpu_data()[i]- dist_sq_an_.cpu_data()[i], Dtype(0.0));  
  73.   }  
  74.   loss = loss / static_cast<Dtype>(bottom[0]->num()) / Dtype(2);  
  75.   top[0]->mutable_cpu_data()[0] = loss;  
  76. }  
  77.   
  78. template <typename Dtype>  
  79. __global__ void CLLBackward(const int count, const int channels,  
  80.     const Dtype margin, const Dtype alpha, const Dtype* sampleW,  
  81.     const Dtype* diff, const Dtype* dist_sq_ap_, const Dtype* dist_sq_an_,  
  82.     Dtype *bottom_diff) {  
  83.   CUDA_KERNEL_LOOP(i, count) {  
  84.     int n = i / channels;  // the num index, to access dist_sq_ap_ and dist_sq_an_  
  85.     Dtype mdist(0.0);  
  86.     mdist = margin +dist_sq_ap_[n] - dist_sq_an_[n];  
  87.     if (mdist > 0.0) {  
  88.         bottom_diff[i] = alpha*sampleW[n]*diff[i];  
  89.     } else {  
  90.         bottom_diff[i] = 0;  
  91.     }  
  92.   }  
  93. }  
  94.   
  95. template <typename Dtype>  
  96. void TripletLossLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,  
  97.     const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {  
  98.   Dtype margin = this->layer_param_.triplet_loss_param().margin();  
  99.   const int count = bottom[0]->count();  
  100.   const int channels = bottom[0]->channels();  
  101.   
  102.   for (int i = 0; i < 3; ++i) {  
  103.     if (propagate_down[i]) {  
  104.       const Dtype sign = (i < 2) ? -1 : 1;  
  105.       const Dtype alpha = sign * top[0]->cpu_diff()[0] /  
  106.           static_cast<Dtype>(bottom[0]->num());  
  107.       if(i==0){  
  108.           // NOLINT_NEXT_LINE(whitespace/operators)  
  109.           CLLBackward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  110.               count, channels, margin, alpha,  
  111.               bottom[3]->gpu_data(),  
  112.               diff_pn_.gpu_data(),  // the cached eltwise difference between p and n  
  113.               dist_sq_ap_.gpu_data(),  // the cached square distance between a and p  
  114.               dist_sq_an_.gpu_data(),  // the cached square distance between a and n  
  115.               bottom[i]->mutable_gpu_diff());  
  116.           CUDA_POST_KERNEL_CHECK;  
  117.       }else if(i==1){  
  118.           // NOLINT_NEXT_LINE(whitespace/operators)  
  119.           CLLBackward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  120.               count, channels, margin, alpha,  
  121.               bottom[3]->gpu_data(),  
  122.               diff_ap_.gpu_data(),  // the cached eltwise difference between a and p  
  123.               dist_sq_ap_.gpu_data(),  // the cached square distance between a and p  
  124.               dist_sq_an_.gpu_data(),  // the cached square distance between a and n  
  125.               bottom[i]->mutable_gpu_diff());  
  126.           CUDA_POST_KERNEL_CHECK;  
  127.       }else if(i==2){  
  128.           // NOLINT_NEXT_LINE(whitespace/operators)  
  129.           CLLBackward<Dtype><<<CAFFE_GET_BLOCKS(count), CAFFE_CUDA_NUM_THREADS>>>(  
  130.               count, channels, margin, alpha,  
  131.               bottom[3]->gpu_data(),  
  132.               diff_an_.gpu_data(),  // the cached eltwise difference between a and n  
  133.               dist_sq_ap_.gpu_data(),  // the cached square distance between a and p  
  134.               dist_sq_an_.gpu_data(),  // the cached square distance between a and n  
  135.               bottom[i]->mutable_gpu_diff());  
  136.           CUDA_POST_KERNEL_CHECK;  
  137.   
  138.       }  
  139.     }  
  140.   }  
  141. }  
  142.   
  143. INSTANTIATE_LAYER_GPU_FUNCS(TripletLossLayer);  
  144.   
  145. }  // namespace caffe  

5. 在./src/caffe/test/目录下增加test_triplet_loss_layer.cpp

[cpp]  view plain copy
  1. /* 
  2.  * test_triplet_loss_layer.cpp 
  3.  * 
  4.  *  Created on: Jun 3, 2015 
  5.  *      Author: tangwei 
  6.  */  
  7.   
  8. #include <algorithm>  
  9. #include <cmath>  
  10. #include <cstdlib>  
  11. #include <cstring>  
  12. #include <vector>  
  13.   
  14. #include "gtest/gtest.h"  
  15.   
  16. #include "caffe/blob.hpp"  
  17. #include "caffe/common.hpp"  
  18. #include "caffe/filler.hpp"  
  19. #include "caffe/vision_layers.hpp"  
  20.   
  21. #include "caffe/test/test_caffe_main.hpp"  
  22. #include "caffe/test/test_gradient_check_util.hpp"  
  23.   
  24. namespace caffe {  
  25.   
  26. template <typename TypeParam>  
  27. class TripletLossLayerTest : public MultiDeviceTest<TypeParam> {  
  28.   typedef typename TypeParam::Dtype Dtype;  
  29.   
  30.  protected:  
  31.   TripletLossLayerTest()  
  32.       : blob_bottom_data_i_(new Blob<Dtype>(512, 2, 1, 1)),  
  33.         blob_bottom_data_j_(new Blob<Dtype>(512, 2, 1, 1)),  
  34.         blob_bottom_data_k_(new Blob<Dtype>(512, 2, 1, 1)),  
  35.         blob_bottom_y_(new Blob<Dtype>(512, 1, 1, 1)),  
  36.         blob_top_loss_(new Blob<Dtype>()) {  
  37.     // fill the values  
  38.     FillerParameter filler_param;  
  39.     filler_param.set_min(-1.0);  
  40.     filler_param.set_max(1.0);  // distances~=1.0 to test both sides of margin  
  41.     UniformFiller<Dtype> filler(filler_param);  
  42.     filler.Fill(this->blob_bottom_data_i_);  
  43.     blob_bottom_vec_.push_back(blob_bottom_data_i_);  
  44.     filler.Fill(this->blob_bottom_data_j_);  
  45.     blob_bottom_vec_.push_back(blob_bottom_data_j_);  
  46.     filler.Fill(this->blob_bottom_data_k_);  
  47.     blob_bottom_vec_.push_back(blob_bottom_data_k_);  
  48.     for (int i = 0; i < blob_bottom_y_->count(); ++i) {  
  49.         blob_bottom_y_->mutable_cpu_data()[i] = caffe_rng_rand() % 2;  // 0 or 1  
  50.     }  
  51.     blob_bottom_vec_.push_back(blob_bottom_y_);  
  52.     blob_top_vec_.push_back(blob_top_loss_);  
  53.   }  
  54.   virtual ~TripletLossLayerTest() {  
  55.     delete blob_bottom_data_i_;  
  56.     delete blob_bottom_data_j_;  
  57.     delete blob_bottom_data_k_;  
  58.     delete blob_top_loss_;  
  59.   }  
  60.   
  61.   Blob<Dtype>* const blob_bottom_data_i_;  
  62.   Blob<Dtype>* const blob_bottom_data_j_;  
  63.   Blob<Dtype>* const blob_bottom_data_k_;  
  64.   Blob<Dtype>* const blob_bottom_y_;  
  65.   Blob<Dtype>* const blob_top_loss_;  
  66.   vector<Blob<Dtype>*> blob_bottom_vec_;  
  67.   vector<Blob<Dtype>*> blob_top_vec_;  
  68. };  
  69.   
  70. TYPED_TEST_CASE(TripletLossLayerTest, TestDtypesAndDevices);  
  71.   
  72. TYPED_TEST(TripletLossLayerTest, TestForward) {  
  73.   typedef typename TypeParam::Dtype Dtype;  
  74.   LayerParameter layer_param;  
  75.   TripletLossLayer<Dtype> layer(layer_param);  
  76.   layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_);  
  77.   layer.Forward(this->blob_bottom_vec_, this->blob_top_vec_);  
  78.   // manually compute to compare  
  79.   const Dtype margin = layer_param.triplet_loss_param().margin();  
  80.   const int num = this->blob_bottom_data_i_->num();  
  81.   const int channels = this->blob_bottom_data_i_->channels();  
  82.   Dtype loss(0);  
  83.   for (int i = 0; i < num; ++i) {  
  84.     Dtype dist_sq_ij(0);  
  85.     Dtype dist_sq_ik(0);  
  86.     for (int j = 0; j < channels; ++j) {  
  87.       Dtype diff_ij = this->blob_bottom_data_i_->cpu_data()[i*channels+j] -  
  88.           this->blob_bottom_data_j_->cpu_data()[i*channels+j];  
  89.       dist_sq_ij += diff_ij*diff_ij;  
  90.       Dtype diff_ik = this->blob_bottom_data_i_->cpu_data()[i*channels+j] -  
  91.           this->blob_bottom_data_k_->cpu_data()[i*channels+j];  
  92.       dist_sq_ik += diff_ik*diff_ik;  
  93.     }  
  94.     loss += std::max(Dtype(0.0), margin+dist_sq_ij-dist_sq_ik);  
  95.   }  
  96.   loss /= static_cast<Dtype>(num) * Dtype(2);  
  97.   EXPECT_NEAR(this->blob_top_loss_->cpu_data()[0], loss, 1e-6);  
  98. }  
  99.   
  100. TYPED_TEST(TripletLossLayerTest, TestGradient) {  
  101.   typedef typename TypeParam::Dtype Dtype;  
  102.   LayerParameter layer_param;  
  103.   TripletLossLayer<Dtype> layer(layer_param);  
  104.   layer.SetUp(this->blob_bottom_vec_, this->blob_top_vec_);  
  105.   GradientChecker<Dtype> checker(1e-2, 1e-2, 1701);  
  106.   // check the gradient for the first two bottom layers  
  107.   checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_,  
  108.       this->blob_top_vec_, 0);  
  109.   checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_,  
  110.       this->blob_top_vec_, 1);  
  111. }  
  112.   
  113. }  // namespace caffe  

3.编译测试

重新 make all 如果出错,检查代码语法错误。
make test
make runtest 如果成功,全是绿色的OK  否则会给出红色提示,就得看看是不是实现逻辑上出错了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值