DeepLearning(基於caffe)實戰專案(8)--修改caffe原始碼從新增loss(層)函式開始
在caffe中摸爬滾打了一個多月了,修改caffe原始碼,早就想練練手了,loss層是一個比較獨立的一個層,而且可以仿照caffe給的樣例進行新增,難度會稍微小點。caffe自帶了十種loss層(contrastive、euclidean、hinge、multinomial_logistic、sigmoid_cross_entropy、smooth_L1、smooth_L1_ohem、softmax、softmax_ohem、infogain)
詳細見:http://blog.csdn.net/sihailongwang/article/details/72657637
公式含義推薦:http://blog.csdn.net/u012177034/article/details/52144325
接下來,就是自己新增一個新的loss(層)函數了,我打算新增:Absolute loss
第一步:在caffe.proto增加對應的LayerParameter message
optional AbsoluteLossParameter Absolute_loss_param = 151;
message AbsoluteLossParameter
{
optional float dis = 1 [default = 1];
}
第二步:在./include/caffe/layers/下增加相應的layer的宣告
#ifndef CAFFE_ABSOLUTE_LOSS_LAYER_HPP_ #define CAFFE_ABSOLUTE_LOSS_LAYER_HPP_ #include <vector> #include "caffe/blob.hpp" #include "caffe/layer.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/layers/loss_layer.hpp" namespace caffe { template <typename Dtype> class AbsoluteLossLayer : public LossLayer<Dtype> { public: explicit AbsoluteLossLayer(const LayerParameter& param) : LossLayer<Dtype>(param), dis_() {} virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); virtual inline const char* type() const { return "AbsoluteLoss"; } virtual inline bool AllowForceBackward(const int bottom_index) const { return true; } protected: /// @copydoc AbsoluteLossLayer 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> dis_; }; } // namespace caffe #endif // CAFFE_EUCLIDEAN_LOSS_LAYER_HPP_ #endif // CAFFE_EUCLIDEAN_LOSS_LAYER_HPP_
第三步:在./src/caffe/util/math_functions.cpp/下增加“絕對值求和”模板函式
說明:因為AbsoluteLoss需要絕對值求和,所以在math_fuction.cpp中需要增加一個“絕對值”模板函式(與此同時,我驚喜的發現了BLAS、CBLAS)
/********************************************************************************************************************
TIPS:科普一下什麼是BLAS/CBLAS
Basic Linear Algebra Subprograms,即基礎線性代數子程式庫,裡邊擁有大量的已經編好的關於線性代數運算的程式,主要用於向量和矩陣的計算的高效能數學庫,本身是由Fortran編寫的,為了方便C/C++程式使用,就有了BLAS的C介面庫CBLAS,詳細列表:http://www.netlib.org/blas/
/********************************************************************************************************************
//--------------------------add------------------------------------------
template <>
float caffe_cpu_asum<float>(const int n, const float* x) {
return cblas_sasum(n, x, 1); //sum of absolute values
}
template <>
double caffe_cpu_asum<double>(const int n, const double* x) {
return cblas_dasum(n, x, 1); //sum of absolute values
}
template <typename Dtype>
Dtype caffe_cpu_abs_sum(const int n, const Dtype* x) {
return caffe_cpu_asum(n, x);
}
template
float caffe_cpu_asum<float>(const int n, const float* x);
template
double caffe_cpu_asum<double>(const int n, const double* x);
//-------------------------add-------------------------------------------
第四步:在./src/caffe/layers/下增加相應layer的CPU/GPU實現檔案
CPU版本(absolute_loss_layer.cpp):
#include <vector>
#include "caffe/layers/absolute_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"
namespace caffe {
template <typename Dtype>
void AbsoluteLossLayer<Dtype>::Reshape(
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
LossLayer<Dtype>::Reshape(bottom, top); //在LossLayer 中定義
CHECK_EQ(bottom[0]->count(1), bottom[1]->count(1)) //保證輸入維度相同
<< "Inputs must have the same dimension.";
dis_.ReshapeLike(*bottom[0]); //Blob 型別的diff_用來存放兩個bottom的差,和bottom具有相同的
}
template <typename Dtype>
void AbsoluteLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
int count = bottom[0]->count(); //總共有count個featuremap
caffe_sub(
count,
bottom[0]->cpu_data(),
bottom[1]->cpu_data(),
dis_.mutable_cpu_data()); //diff_ = bottom[0] - bottom[1]
Dtype loss_param = this->layer_param_.absolute_loss_param().dis();
Dtype abs_sum = caffe_cpu_abs_sum(count,dis_.cpu_data());
//Dtype dot = caffe_cpu_abs_sum()(count, diff_.cpu_data(), dis_.cpu_data());
Dtype loss = loss_param * abs_sum / bottom[0]->num();
top[0]->mutable_cpu_data()[0] = loss;
}
template <typename Dtype>
void AbsoluteLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
for (int i = 0; i < 2; ++i) {
if (propagate_down[i]) {
//對於輸入的label bottom propagate_dowm為0
const Dtype sign = (i == 0) ? 1 : -1;
const Dtype alpha = sign * top[0]->cpu_diff()[0] / bottom[i]->num();
caffe_cpu_axpby(
bottom[i]->count(), // count
alpha, // alpha
dis_.cpu_data(), // a
Dtype(0), // beta
bottom[i]->mutable_cpu_diff()); // b
} //bottom[i]->mutable_cpu_diff()) = alpha*dis_.cpu_data()
}
}
#ifdef CPU_ONLY
STUB_GPU(AbsoluteLossLayer);
#endif
INSTANTIATE_CLASS(AbsoluteLossLayer);
REGISTER_LAYER_CLASS(AbsoluteLoss);
} // namespace caffe
GPU版本(absolute_loss_layer.cu):#include <vector>
#include "caffe/layers/absolute_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"
namespace caffe {
template <typename Dtype>
void AbsoluteLossLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
int count = bottom[0]->count(); //總共有count個featuremap
caffe_gpu_sub(
count,
bottom[0]->gpu_data(),
bottom[1]->gpu_data(),
dis_.mutable_gpu_data());
Dtype loss_param = this->layer_param_.
Dtype abs_sum;
caffe_gpu_asum(count, dis_.gpu_data(), &abs_sum);
Dtype loss = loss_param * abs_sum/ bottom[0]->num();
top[0]->mutable_cpu_data()[0] = loss;
}
template <typename Dtype>
void AbsoluteLossLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
for (int i = 0; i < 2; ++i) {
if (propagate_down[i]) {
const Dtype sign = (i == 0) ? 1 : -1;
const Dtype alpha = sign * top[0]->cpu_diff()[0] / bottom[i]->num();
caffe_gpu_axpby(
bottom[i]->count(), // count
alpha, // alpha
dis_.gpu_data(), // a
Dtype(0), // beta
bottom[i]->mutable_gpu_diff()); // b
}
}
}
INSTANTIATE_LAYER_GPU_FUNCS(AbsoluteLossLayer);
} // namespace caffe
第五步:用vs開啟caffe,進行編譯,編譯成功後,恭喜你,功力又上升一個段位,哈哈
1.修改../windows/libcaffe下的兩個檔案:libcaffe.vcxproj和libcaffe.vcxproj.filters
libcaffe.vcxproj增加:
<ClCompile Include="..\..\src\caffe\layers\absolute_loss_layer.cpp" />
<ClInclude Include="..\..\include\caffe\layers\absolute_loss_layer.hpp" />
<CudaCompile Include="..\..\src\caffe\layers\absolute_loss_layer.cu" />
libcaffe.vcxproj.filter增加:<ClInclude Include="..\..\include\caffe\layers\absolute_loss_layer.hpp">
<Filter>include\layers</Filter>
</ClInclude>
<CudaCompile Include="..\..\src\caffe\layers\absolute_loss_layer.cu">
<Filter>cu\layers</Filter>
</CudaCompile>
<ClCompile Include="..\..\src\caffe\layers\absolute_loss_layer.cpp">
<Filter>src\layers</Filter>
</ClCompile>
2.開啟caffe.sln,再進行重新生成新的解決方案,編譯通過後,恭喜你功力又升一級!