关于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上面注释中的:
//LayerParameter next available layer-specific ID: 134 (last added: reshape_param)
然后增加Message:
message TripletLossParameter {
// margin for dissimilar pair
optional float margin = 1 [default = 1.0];
}
其中 margin就是定义triplet loss原理以及梯度推导所讲的alpha。
2.在./include/caffe/loss_layers.hpp中增加triplet loss layer的类的声明
具体解释见注释,主要的是定义了一些变量,用来在前传中存储中间计算结果,以便在反传的时候避免重复计算。
/**
* @brief Computes the triplet loss
*/
template <typename Dtype>
class TripletLossLayer : public LossLayer<Dtype> {
public:
explicit TripletLossLayer(const LayerParameter& param)
: LossLayer<Dtype>(param){}
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual inline int ExactNumBottomBlobs() const { return 4; }
virtual inline const char* type() const { return "TripletLoss"; }
/**
* Unlike most loss layers, in the TripletLossLayer we can backpropagate
* to the first three inputs.
*/
virtual inline bool AllowForceBackward(const int bottom_index) const {
return bottom_index != 3;
}
protected:
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
Blob<Dtype> diff_ap_; // cached for backward pass
Blob<Dtype> diff_an_; // cached for backward pass
Blob<Dtype> diff_pn_; // cached for backward pass
Blob<Dtype> diff_sq_ap_; // cached for backward pass
Blob<Dtype> diff_sq_an_; // tmp storage for gpu forward pass
Blob<Dtype> dist_sq_ap_; // cached for backward pass
Blob<Dtype> dist_sq_an_; // cach