caffe源码分析:softmax_layer.cpp softmax_loss_layer.cpp
本文僅分析了softmax_layer.cpp 和 softmax_loss_layer.cpp兩個文件中的forward函數,backward函數有待補充。
1、softmax_layer.cpp
softmax function
設有m個已標記樣本,σ(z)=(σ1(z),σ2(z),...,σm(z))定義:
其中, σi(z)是loss層的輸入; zi=WTix+bi,表示第i類的線性預測結果, WTi為權重, bi為偏置值。
帶入softmax進行計算其實就是先對每一個zi取exponential變為非負,然后除以所有項之和進行歸一化。
在softmax_layer.cpp中,可以將forward函數比較直觀的表現為以下形式:
hθ(x(i))=???????p(y(i)=1|x(i);θ)p(y(i)=2|x(i);θ)?p(y(i)=k|x(i);θ)???????=1∑kl=1eθTjx(i)????????eθT1x(i)eθT2x(i)?eθTkx(i)????????
在 softmax.cpp中 forward函數代碼: template <typename Dtype> void SoftmaxLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top) {const Dtype* bottom_data = bottom[0]->cpu_data();Dtype* top_data = top[0]->mutable_cpu_data();Dtype* scale_data = scale_.mutable_cpu_data();int channels = bottom[0]->shape(softmax_axis_);int dim = bottom[0]->count() / outer_num_;caffe_copy(bottom[0]->count(), bottom_data, top_data);// We need to subtract the max to avoid numerical issues, compute the exp,// and then normalize.for (int i = 0; i < outer_num_; ++i) {// initialize scale_data to the first planecaffe_copy(inner_num_, bottom_data + i * dim, scale_data);for (int j = 0; j < channels; j++) {for (int k = 0; k < inner_num_; k++) {scale_data[k] = std::max(scale_data[k],bottom_data[i * dim + j * inner_num_ + k]);}}// subtractioncaffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels, inner_num_,1, -1., sum_multiplier_.cpu_data(), scale_data, 1., top_data);// exponentiationcaffe_exp<Dtype>(dim, top_data, top_data);// sum after expcaffe_cpu_gemv<Dtype>(CblasTrans, channels, inner_num_, 1.,top_data, sum_multiplier_.cpu_data(), 0., scale_data);// divisionfor (int j = 0; j < channels; j++) {caffe_div(inner_num_, top_data, scale_data, top_data);top_data += inner_num_;}} }
代碼不多,針對Line 21至Line 32分析如下:
1、//division
top_data=top_data/scale_data;
top_data=top_data+inner_num_;
2、//sum after exp
scale_data=top_data*sum_multiplier_.cpu_data()
分析:求和,每一層各自求和放到scale_data中
3、//exponentiation
top_data=exp(top_data)
分析:比較直觀,能看出是在exponentiation。函數caffe_exp()的第一個參數是dim,那么應該是對K維列向量做exp
4、//subtraction
通過矩陣相乘的方式來計算,有channels層的top_data,每層元素減去該層的最大值
2、softmax_loss_layer.cpp
softmax loss function
根據上面講到的softmax函數,假設x屬于第i類,我們要最大似然化σi(z),通常使用negtive log-likelihood ,也就是要最小化?log(oy)的值。
loss function:
其中, 1{y(i)=j}為示性函數。
在 softmax_loss_layer.cpp中forward函數代碼: template <typename Dtype> void SoftmaxWithLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {// The forward pass computes the softmax prob values.softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);const Dtype* prob_data = prob_.cpu_data();//定義了一個指針指向最初的可能值const Dtype* label = bottom[1]->cpu_data();//原始的labelint dim = prob_.count() / outer_num_;//輸入圖像類的個數int count = 0;Dtype loss = 0;for (int i = 0; i < outer_num_; ++i) {//outer_num_=batch_sizefor (int j = 0; j < inner_num_; j++) {//inner_num_的存在可解決多標簽問題,對于單一標簽問題inner_num_=1const int label_value = static_cast<int>(label[i * inner_num_ + j]);//對于多標簽問題還不是很理解,在單一標簽問題中inner_num_=1,那么label[i * inner_num_ + j]表示第i * inner_num_ + j個輸入圖像的標簽值,label[i * inner_num_ + j]一定屬于[0,輸入圖像類別數-1]if (has_ignore_label_ && label_value == ignore_label_) {continue;}DCHECK_GE(label_value, 0);DCHECK_LT(label_value, prob_.shape(softmax_axis_));loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],Dtype(FLT_MIN)));//對于單標簽問題,每張圖像經過計算后都會輸出一個dim×1大小的矩陣(列向量),矩陣中的第k個值表示該圖像屬于第k類的概率;prob_data[i * dim + label_value * inner_num_ + j]表示第i個輸入圖像屬于第label_value的概率。++count;}}if (normalize_) {top[0]->mutable_cpu_data()[0] = loss / count;} else {top[0]->mutable_cpu_data()[0] = loss / outer_num_;}if (top.size() == 2) {top[1]->ShareData(prob_);} }
總結
以上是生活随笔為你收集整理的caffe源码分析:softmax_layer.cpp softmax_loss_layer.cpp的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: eclipse lombok插件安装_你
- 下一篇: 更改putty字体颜色