Caffe 训练时loss等于87.3365且保持不变的原因及解决方法
如題,在caffe訓練時,遇到這個特殊的數字之后,loss會一直就是這個數字。
網上雖然有很多針對這個問題調參的trick,但少有詳細的分析,因此,有必要研究一下caffe的源代碼。
softmax的公式為
其中x為softmax前一層的輸出
softmax的loss計算公式也很簡單,就是對softmax之后預測的概率做對數似然函數
其中y是label,若類別數為N,則y為N維。對于單label情況,N維中只有一維為1,其他為零,計算loss時僅需考慮label中非零那一維即可(實際使用中單label用一個數字記錄)
此時
loss=?log(P{k==label})loss=?log(P{k==label})
在softmax_loss_layer.cpp的原碼中,就是由label的非零維直接計算loss的 loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],Dtype(FLT_MIN)));
loss的最大值由FLT_MIN得到,FLT_MIN定義為1.17549435E-38F,這個數字的自然對數正好就是
-87.3356,算loss時需要取負值,結果就能了87.3356。
**這說明softmax計算得到概率值出現了零(由于float類型所能表示的最小數值是10?3810?38,比這個值還小的無法表示,只能是零)
而softmax是用指數函數計算的,指數函數的值都是大于零的。因此,我們有理由相信,計算過程中出現了float溢出等異常,出現了inf,nan等異常數值導致softmax輸出為零
最后我們發現,當softmax之前的feature值過大時,由于softmax先求指數,會超出float數據范圍,成為inf。inf與其他任何數值的和都是inf,softmax在做除法時任何正常范圍的數值除以inf都會變為0。然后求loss時log一下就出現了87.3356這樣的值。**
以下是模擬訓練的loss代碼,觀察feature數值范圍對loss的影響:
#include <iostream> #include <math.h> #include <float.h>using namespace std;int main() {float f[] = {100, 20};cout << "feature: " << f[0] << ", " << f[1] << endl;float f_exp[] = {expf(f[0]), expf(f[1])};cout << "exp: " << f_exp[0] << ", " << f_exp[1] << endl;float sum = f_exp[0] + f_exp[1];cout << "sum: " << sum << endl;float softmax[] = {f_exp[0]/sum, f_exp[1]/sum};cout << "softmax: " << softmax[0] << ", " << softmax[1] << endl;float loss[] = {-log(max(softmax[0], FLT_MIN)), -log(max(softmax[1], FLT_MIN))};cout << "loss: " << loss[0] << ", " << loss[1] << endl;return 0; }解決方法:
知道了原因,解決時就能對癥下藥。總體上看,softmax輸入的feature由兩部分計算得到:一部分是輸入數據,另部分是各層權重參數。
1、觀察數據中是否有異常樣本或異常label導致數據讀取異常
2、調小初始化權重,以便使softmax輸入的feature盡可能變小
3、降低學習率,這樣就能減小權重參數的波動范圍,從而減小權重變大的可能性。這條也是網上出現較多的方法。
4、如果有BN(batch normalization)層,finetune時最好不要凍結BN的參數,否則數據分布不一致時很容易使輸出值變的很大。
總結
以上是生活随笔為你收集整理的Caffe 训练时loss等于87.3365且保持不变的原因及解决方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python以什么表示代码层次_pyth
- 下一篇: 计算机主机配置有哪些,电脑主机配置清单有