請謹慎使用預訓練的深度學習模型
- 2019 年 11 月 23 日
- 筆記
作者:Cecelia Shao 編譯:ronghuaiyang
導讀
預訓練模型用起來非常容易,但是你是否忽略了可能影響模型性能的細節呢?
你運行過多少次下面的代碼:
import torchvision.models as models inception = models.inception_v3(pretrained=True)
或者是這個
from keras.applications.inception_v3 import InceptionV3 base_model = InceptionV3(weights='imagenet', include_top=False)
看起來使用這些預訓練的模型已經成為行業最佳實踐的新標準。畢竟,有一個經過大量數據和計算訓練的模型,你為什麼不利用呢?
預訓練模型萬歲!
利用預訓練的模型有幾個重要的好處:
- 合併超級簡單
- 快速實現穩定(相同或更好)的模型性能
- 不需要太多的標籤數據
- 遷移學習、預測和特徵提取的通用用例
NLP領域的進步也鼓勵使用預訓練的語言模型,如GPT和GPT-2、AllenNLP的ELMo、谷歌的BERT、Sebastian Ruder和Jeremy Howard的ULMFiT。
利用預訓練模型的一種常見技術是特徵提取,在此過程中檢索由預訓練模型生成的中間表示,並將這些表示用作新模型的輸入。通常假定這些最終的全連接層得到的是信息與解決新任務相關的。
每個人都參與其中
每一個主流框架,如Tensorflow,Keras,PyTorch,MXNet等,都提供了預先訓練好的模型,如Inception V3,ResNet,AlexNet等,帶有權重:
- Keras Applications
- PyTorch torchvision.models
- Tensorflow Official Models (and now TensorFlow Hubs)
- MXNet Model Zoo
- Fast.ai Applications

很簡單,是不是?
但是,這些benchmarks可以復現嗎?
這篇文章的靈感來自Curtis Northcutt,他是麻省理工學院計算機科學博士研究生。他的文章『Towards Reproducibility: Benchmarking Keras and PyTorch』 提出了幾個有趣的觀點:
resnet
結構在PyTorch中執行得更好,inception
結構在Keras中執行得更好- 在Keras應用程序上不能復現Keras Applications上的已發佈的基準測試,即使完全複製示例代碼也是如此。事實上,他們報告的準確率(截至2019年2月)通常高於實際的準確率。
- 當部署在服務器上或與其他Keras模型按順序運行時,一些預先訓練好的Keras模型會產生不一致或較低的精度。
- 使用batch normalization的Keras模型可能不可靠。對於某些模型,前向傳遞計算(假定梯度為off)仍然會導致在推理時權重發生變化。
你可能會想:這怎麼可能?這些不是相同的模型嗎?如果在相同的條件下訓練,它們不應該有相同的性能嗎?
並不是只有你這麼想,Curtis的文章也在Twitter上引發了一些反應:


關於這些差異的原因有一些有趣的見解:

了解(並信任)這些基準測試非常重要,因為它們允許你根據要使用的框架做出明智的決策,並且通常用作研究和實現的基線。
那麼,當你利用這些預先訓練好的模型時,需要注意什麼呢?
使用預訓練模型的注意事項
1、你的任務有多相似?你的數據有多相似?
對於你的新x射線數據集,你使用Keras Xception模型,你是不是期望0.945的驗證精度?首先,你需要檢查你的數據與模型所訓練的原始數據集(在本例中為ImageNet)有多相似。你還需要知道特徵是從何處(網絡的底部、中部或頂部)遷移的,因為任務相似性會影響模型性能。
閱讀CS231n — Transfer Learning and 『How transferable are features in deep neural networks?』
2、你如何預處理數據?
你的模型的預處理應該與原始模型相同。幾乎所有的torchvision模型都使用相同的預處理值。對於Keras模型,你應該始終為相應的模型級模塊使用 preprocess_input
函數。例如:
# VGG16 keras.applications.vgg16.preprocess_input # InceptionV3 keras.applications.inception_v3.preprocess_input #ResNet50 keras.applications.resnet50.preprocess_input
3、你的backend是什麼?
有一些關於HackerNews的傳言稱,將Keras的後端從Tensorflow更改為CNTK (Microsoft Cognitive toolkit)提高了性能。由於Keras是一個模型級庫,它不處理諸如張量積、卷積等較低級別的操作,所以它依賴於其他張量操作框架,比如TensorFlow後端和Theano後端。
Max Woolf提供了一個優秀的基準測試項目,發現CNTK和Tensorflow之間的準確性是相同的,但CNTK在LSTMs和多層感知(MLPs)方面更快,而Tensorflow在CNNs和embeddings方面更快。
Woolf的文章是2017年發表的,所以如果能得到一個更新的比較結果,其中還包括Theano和MXNet作為後端,那將是非常有趣的(儘管Theano現在已經被廢棄了)。
還有一些人聲稱,Theano的某些版本可能會忽略你的種子。
4、你的硬件是什麼?
你使用的是Amazon EC2 NVIDIA Tesla K80還是Google的NVIDIA Tesla P100?甚至可能是TPU??看看這些不同的pretrained模型的有用的基準參考資料。
- Apache MXNet』s GluonNLP 0.6:Closing the Gap in Reproducible Research with BERT
- Caleb Robinson』s 『How to reproduce ImageNet validation results』 (and of course, again, Curtis』 benchmarking post)
- DL Bench
- Stanford DAWNBench
- TensorFlow』s performance benchmarks
5、你的學習率是什麼?
在實踐中,你應該保持預訓練的參數不變(即,使用預訓練好的模型作為特徵提取器),或者用一個相當小的學習率來調整它們,以便不忘記原始模型中的所有內容。
6、在使用batch normalization或dropout等優化時,特別是在訓練模式和推理模式之間,有什麼不同嗎?
正如Curtis的帖子所說:
使用batch normalization的Keras模型可能不可靠。對於某些模型,前向傳遞計算(假定梯度為off)仍然會導致在推斷時權重發生變化。
但是為什麼會這樣呢?
Expedia的首席數據科學家Vasilis Vryniotis首先發現了Keras中的凍結batch normalization層的問題。
Keras當前實現的問題是,當凍結批處理規範化(BN)層時,它在訓練期間還是會繼續使用mini-batch的統計信息。我認為當BN被凍結時,更好的方法是使用它在訓練中學習到的移動平均值和方差。為什麼?由於同樣的原因,在凍結層時不應該更新mini-batch的統計數據:它可能導致較差的結果,因為下一層沒有得到適當的訓練。
Vasilis還引用了這樣的例子,當Keras模型從訓練模式切換到測試模式時,這種差異導致模型性能顯著下降(從100%下降到50%)。