踩坑:pytorch中eval模式下結果遠差於train模式

首先,eval模式和train模式得到不同的結果是正常的。我的模型中,eval模式和train模式不同之處在於Batch Normalization和Dropout。Dropout比較簡單,在train時會丟棄一部分連接,在eval時則不會。Batch Normalization,在train時不僅使用了當前batch的均值和方差,也使用了歷史batch統計上的均值和方差,並做一個加權平均(momentum參數)。在test時,由於此時batchsize不一定一致,因此不再使用當前batch的均值和方差,僅使用歷史訓練時的統計值。

我出bug的現象是,train模式下可以收斂,但一旦在測試中切換到了eval模式,結果就很差。如果在測試中仍沿用train模式,反而可以得到不錯的結果。爲了確保是程序bug而不是算法本身就不適合於預測,我在測試時再次使用了訓練集,正常情況下此時應發生過擬合,正確率一定會很高,然而eval模式下正確率仍然很低。參照網上的一些說法(Performance highly degraded when eval() is activated in the test phase
),我調大了batchsize,降低了BN層的momentum,檢查了是否存在不同層使用相同BN層的bug,均不見效。有一種方法說應在BN層設置track_running_stats爲False,它雖然帶來了好的效果,但實際上它只不過是不用eval模式,切回train模式罷了,所以也不對。

學習了在訓練過程中,如何將BN層中統計的均值和方差輸出。即在forward()中,

# bn是一個BN層,torch.nn.batch_normalization(...)
print(bn.running_mean)
print(bn.running_var)

同時學習瞭如何輸出一個Tensor自身的均值和方差,即

# x是一個Tensor,dims是需要計算的維度
print(x.cpu().detach().numpy().mean(dims)
print(x.cpu().detach().numpy().var(dims)

觀察每一層的輸出結果,發現出現了很大的方差,才猛然意識到自己的輸入數據沒有做歸一化(事後想想也確實如此,畢竟模型和訓練方法都是github上參考別人的,出錯概率很小;反而是自己寫的DataSet部分,其實是最容易出錯的)。給模型加上歸一化後,eval和train的結果就沒有問題了。

再次驗證了我的觀點:越是玄學的問題,越是傻逼的bug。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章