pytorch 模型可视化_【深度学习】高效使用Pytorch的6个技巧:为你的训练Pipeline提供强大动力...
作者:Eugene Khvedchenya? ?編譯:ronghuaiyang
導讀只報告模型的Top-1準確率往往是不夠的。
將train.py腳本轉換為具有一些附加特性的強大pipeline每一個深度學習項目的最終目標都是為產品帶來價值。當然,我們想要最好的模型。什么是“最好的” —— 取決于特定的用例,我將把這個討論放到這篇文章之外。我想談談如何從你的train.py腳本中得到最好的模型。
在這篇文章中,我們將介紹以下技巧:
免責聲明:在下一節中,我將引用一些源代碼。大多數都是為[Catalyst](https://github.com/catalysts -team/catalyst)框架(20.08版)定制的,可以在pytorch-toolbelt中使用。
不要重復造輪子
建議1 — 利用PyTorch生態系統的高級訓練框架
PyTorch在從頭開始編寫訓練循環時提供了極佳的靈活性和自由度。理論上,這為編寫任何訓練邏輯提供了無限可能。在實踐中,你很少會為訓練CycleGAN、distilling BERT或3D物體檢測從頭開始實現編寫訓練循環。
從頭編寫一個完整的訓練循環是學習PyTorch基本原理的一個很好的方法。不過,我強烈建議你在掌握了一些知識之后,轉向高級框架。有很多選擇:Catalyst, PyTorch-Lightning, Fast.AI, Ignite,以及其他。高級框架通過以下方式節省你的時間:
- 提供經過良好測試的訓練循環
- 支持配置文件
- 支持多gpu和分布式訓練
- 管理檢查點/實驗
- 自動記錄訓練進度
從這些高級庫中獲得最大效果需要一些時間。然而,這種一次性的投資從長期來看是有回報的。
優點
- 訓練pipeline變得更小 —— 代碼越少 —— 出錯的機會就越少。
- 易于進行實驗管理。
- 簡化分布式和混合精度訓練。
缺點
- 通常,當使用一個高級框架時,我們必須在框架特定的設計原則和范例中編寫代碼。
- 時間投資,學習額外的框架需要時間。
給我看指標
建議2 —— 在訓練期間查看其他指標
幾乎每一個用于在MNIST或CIFAR甚至ImageNet中對圖像進行分類的快速啟動示例項目都有一個共同點 —— 它們在訓練期間和訓練之后都報告了一組最精簡的度量標準。通常情況下,包括Top-1和Top-5準確度、錯誤率、訓練/驗證損失,僅此而已。雖然這些指標是必要的,但它只是冰山一角!
現代圖像分類模型有數千萬個參數。你想只使用一個標量值來計算它嗎?
Top-1準確率最好的CNN分類模型在泛化方面可能不是最好的。根據你的領域和需求,你可能希望保存具有最 false-positive/false-negative的模型,或者具有最高平均精度的模型。
讓我給你一些建議,在訓練過程中你可以記錄哪些數據:
- Grad-CAM heat-map —— 看看圖像的哪個部分對某一特定類的貢獻最大。
- Confusion Matrix — 顯示了對你的模型來說哪兩個類最具挑戰性。
- Distribution of predictions — 讓你了解最優決策邊界。
- Minimum/Average/Maximum 跨所有層的梯度值,允許識別是否在模型中存在消失/爆炸的梯度或初始化不好的層。
使用面板工具來監控訓練
建議3 — 使用TensorBoard或任何其他解決方案來監控訓練進度
在訓練模型時,你可能最不愿意做的事情就是查看控制臺輸出。通過一個功能強大的儀表板,你可以在其中一次看到所有的度量標準,這是檢查訓練結果的更有效的方法。
Tensorboard可以快速的檢查和比較你運行的訓練對于少量實驗和非分布式環境,TensorBoard是一個黃金標準。自版本1.3以來,PyTorch就完全支持它,并提供了一組豐富的特性來管理試用版。還有一些更先進的基于云的解決方案,比如Weights&Biases、[Alchemy](https://github.com/catalyst team/alchemy)和TensorBoard.dev,這些解決方案使得在多臺機器上監控和比較訓練變得更容易。
當使用Tensorboard時,我通常記錄這樣一組指標:
- 學習率和其他可能改變的優化參數(動量,重量衰減,等等)
- 用于數據預處理和模型內部的時間
- 貫穿訓練和驗證的損失(每個batch和每個epoch的平均值)
- 跨訓練和驗證的度量
- 訓練session的超參數最終值
- 混淆矩陣,Precision-Recall曲線,AUC(如果適用)
- 模型預測的可視化(如適用)
一圖勝千言
直觀地觀察模型的預測是非常重要的。有時訓練數據是有噪聲的;有時,模型會過擬合圖像的偽影。通過可視化最好的和最差的batch(基于損失或你感興趣的度量),你可以對模型執行良好和糟糕的情況進行有價值的洞察。
建議5 — 可視化每個epoch中最好和最壞的batch。它可能會給你寶貴的見解。
Catalyst用戶提示:這里是使用可視化回調的示例:https://github.com/BloodAxe/Catalyst-Inria-Segmentation-Example/blob/master/fit_predict.py#L258
例如,在全球小麥檢測挑戰中,我們需要在圖像上檢測小麥頭。通過可視化最佳batch的圖片(基于mAP度量),我們看到模型在尋找小物體方面做得近乎完美。
最佳模型預測的可視化顯示了模型在小物體上的良好表現相反,當我們查看最差一批的第一個樣本時,我們看到模型很難對大物體做出準確的預測。可視化分析為任何數據科學家都提供了寶貴的見解。
最差模型預測的可視化揭示了模型在大物體上的性能很差查看最差的batch也有助于發現數據標記中的錯誤。通常情況下,貼錯標簽的樣本損失更大,因此會成為最差的batch。通過在每個epoch對最糟糕的batch做一個視覺檢查,你可以消除這些錯誤:
標記錯誤的例子。綠色像素表示true positives,紅色像素表示false negative。在這個示例中,ground-truth掩模標在了它實際上不存在的位置上。使用Dict作為Dataset和Model的返回值
建議4 — 如果你的模型返回一個以上的值,使用Dict來返回結果,不要使用tuple
在復雜的模型中,返回多個輸出并不少見。例如,目標檢測模型通常返回邊界框及其標簽,在圖像分割CNN-s中,我們經常返回中間層的mask進行深度監督,多任務學習最近也很常用。
在許多開源實現中,我經常看到這樣的東西:
#?Bad?practice,?don't?return?tupleclass?RetinaNet(nn.Module):??...def?forward(self,?image):
????x?=?self.encoder(image)
????x?=?self.decoder(x)
????bboxes,?scores?=?self.head(x)return?bboxes,?scores
??...
對于作者來說,我認為這是一種非常糟糕的從模型返回結果的方法。下面是我推薦的替代方法:
class?RetinaNet(nn.Module):??RETINA_NET_OUTPUT_BBOXES?=?"bboxes"
??RETINA_NET_OUTPUT_SCORES?=?"scores"
??...def?forward(self,?image):
????x?=?self.encoder(image)
????x?=?self.decoder(x)
????bboxes,?scores?=?self.head(x)return?{?RETINA_NET_OUTPUT_BBOXES:?bboxes,?
?????????????RETINA_NET_OUTPUT_SCORES:?scores?}
??...
這個建議在某種程度上與“The Zen of Python”的設定產生了共鳴 —— “明確的比含蓄的更好”。遵循這一規則將使你的代碼更清晰、更容易維護。
那么為什么我認為第二種選擇更好呢?有幾個原因:
- 返回值有一個顯式的名稱與它關聯。你不需要記住元組中元素的確切順序。
- 如果你需要訪問返回的字典的一個特定元素,你可以通過它的名字來訪問。
- 從模型中添加新的輸出不會破壞代碼。
使用Dict,你甚至可以更改模型的行為,以按需返回額外的輸出。例如,這里有一個簡短的片段,演示了如何返回多個“主”輸出和兩個“輔助”輸出來進行度量學習:
#?https://github.com/BloodAxe/Kaggle-2020-Alaska2/blob/master/alaska2/models/timm.py#L104def?forward(self,?**kwargs):??x?=?kwargs[self.input_key]
??x?=?self.rgb_bn(x)
??x?=?self.encoder.forward_features(x)
??embedding?=?self.pool(x)
??result?=?{
????OUTPUT_PRED_MODIFICATION_FLAG:?self.flag_classifier(self.drop(embedding)),
????OUTPUT_PRED_MODIFICATION_TYPE:?self.type_classifier(self.drop(embedding)),
??}if?self.need_embedding:
????result[OUTPUT_PRED_EMBEDDING]?=?embeddingif?self.arc_margin?is?not?None:
????result[OUTPUT_PRED_EMBEDDING_ARC_MARGIN]?=?self.arc_margin(embedding)return?result
同樣的建議也適用于Dataset類。對于Cifar-10玩具示例,可以將圖像及其對應的標簽作為元組返回。但當處理多任務或多輸入模型,你想從數據集返回Dict類型的樣本:
#?https://github.com/BloodAxe/Kaggle-2020-Alaska2/blob/master/alaska2/dataset.py#L373class?TrainingValidationDataset(Dataset):def?__init__(????????self,
????????images:?Union[List,?np.ndarray],
????????targets:?Optional[Union[List,?np.ndarray]],
????????quality:?Union[List,?np.ndarray],
????????bits:?Optional[Union[List,?np.ndarray]],
????????transform:?Union[A.Compose,?A.BasicTransform],
????????features:?List[str],
????):"""
????????:param?obliterate?-?Augmentation?that?destroys?embedding.
????????"""if?targets?is?not?None:if?len(images)?!=?len(targets):raise?ValueError(f"Size?of?images?and?targets?does?not?match:?{len(images)}?{len(targets)}")
????????self.images?=?images
????????self.targets?=?targets
????????self.transform?=?transform
????????self.features?=?features
????????self.quality?=?quality
????????self.bits?=?bitsdef?__len__(self):return?len(self.images)def?__repr__(self):return?f"TrainingValidationDataset(len={len(self)},?targets_hist={np.bincount(self.targets)},?qf={np.bincount(self.quality)},?features={self.features})"def?__getitem__(self,?index):
????????image_fname?=?self.images[index]try:
????????????image?=?cv2.imread(image_fname)if?image?is?None:raise?FileNotFoundError(image_fname)except?Exception?as?e:
????????????print("Cannot?read?image?",?image_fname,?"at?index",?index)
????????????print(e)
????????qf?=?self.quality[index]
????????data?=?{}
????????data["image"]?=?image
????????data.update(compute_features(image,?image_fname,?self.features))
????????data?=?self.transform(**data)
????????sample?=?{INPUT_IMAGE_ID_KEY:?os.path.basename(self.images[index]),?INPUT_IMAGE_QF_KEY:?int(qf)}if?self.bits?is?not?None:#?OK
????????????sample[INPUT_TRUE_PAYLOAD_BITS]?=?torch.tensor(self.bits[index],?dtype=torch.float32)if?self.targets?is?not?None:
????????????target?=?int(self.targets[index])
????????????sample[INPUT_TRUE_MODIFICATION_TYPE]?=?target
????????????sample[INPUT_TRUE_MODIFICATION_FLAG]?=?torch.tensor([target?>?0]).float()for?key,?value?in?data.items():if?key?in?self.features:
????????????????sample[key]?=?tensor_from_rgb_image(value)return?sample
當你的代碼中有Dictionaries時,你可以在任何地方使用名稱常量引用輸入/輸出。遵循這條規則將使你的訓練管道非常清晰和容易遵循:
#?https://github.com/BloodAxe/Kaggle-2020-Alaska2callbacks?+=?[
??CriterionCallback(
????input_key=INPUT_TRUE_MODIFICATION_FLAG,
????output_key=OUTPUT_PRED_MODIFICATION_FLAG,
????criterion_key="bce"
??),
??CriterionCallback(
????input_key=INPUT_TRUE_MODIFICATION_TYPE,
????output_key=OUTPUT_PRED_MODIFICATION_TYPE,
????criterion_key="ce"
??),
??CompetitionMetricCallback(
????input_key=INPUT_TRUE_MODIFICATION_FLAG,
????output_key=OUTPUT_PRED_MODIFICATION_FLAG,
????prefix="auc",
????output_activation=binary_logits_to_probas,
????class_names=class_names,
??),
??OutputDistributionCallback(
??????input_key=INPUT_TRUE_MODIFICATION_FLAG,
??????output_key=OUTPUT_PRED_MODIFICATION_FLAG,
??????output_activation=binary_logits_to_probas,
??????prefix="distribution/binary",
??),
??BestMetricCheckpointCallback(
????target_metric="auc",?
????target_metric_minimize=False,?
????save_n_best=3),
]
在訓練中檢測異常
就像人類可以閱讀含有許多錯誤的文本一樣,深度學習模型也可以在訓練過程中出現錯誤時學習“一些合理的東西”。作為一名開發人員,你要負責搜索異常并對其表現進行推理。建議5 — 在訓練期間使用 torch.autograd.detect_anomaly()查找算術異常
如果你在訓練過程中在損失/度量中看到NaNs或Inf,你的腦海中就會響起一個警報。它是你的管道中有問題的指示器。通常情況下,它可能由以下原因引起:
- 模型或特定層的初始化不好(你可以通過觀察梯度大小來檢查哪些層)
- 數學上不正確的運算(負數的torch.sqrt(),非正數的torch.log(),等等)
- 不當使用torch.mean()和torch.sum() 的reduction(zero-sized張量上的均值會得到nan,大張量上的sum容易導致溢出)
- 在loss中使用x.sigmoid()(如果你需要在loss函數中使用概率,更好的方法是x.sigmoid().clamp(eps,1-eps )以防止梯度消失)
- 在Adam-like的優化器中的低epsilon值
- 在使用fp16的訓練的時候沒有使用動態損失縮放
為了找到你代碼中第一次出現Nan/Inf的確切位置,PyTorch提供了一個簡單易用的方法torch. autograde .detect_anomaly():
import?torchdef?main():????torch.autograd.detect_anomaly()
????...#?Rest?of?the?training?code#?ORclass?MyNumericallyUnstableLoss(nn.Module):def?forward(self,?input,?target):with?torch.autograd.set_detect_anomaly(True):
???????loss?=?input?*?targetreturn?loss
將其用于調試目的,否則就禁用它,異常檢測會帶來計算開銷,并將訓練速度降低10-15% 。
—END—英文原文:https://towardsdatascience.com/efficient-pytorch-supercharging-training-pipeline-19a26265adae
往期精彩回顧
適合初學者入門人工智能的路線及資料下載
機器學習及深度學習筆記等資料打印
機器學習在線手冊
深度學習筆記專輯
《統計學習方法》的代碼復現專輯
AI基礎下載
機器學習的數學基礎專輯
獲取一折本站知識星球優惠券,復制鏈接直接打開:
https://t.zsxq.com/662nyZF
本站qq群1003271085。
加入微信群請掃碼進群(如果是博士或者準備讀博士請說明):
總結
以上是生活随笔為你收集整理的pytorch 模型可视化_【深度学习】高效使用Pytorch的6个技巧:为你的训练Pipeline提供强大动力...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 模板模式_Java模板模式(T
- 下一篇: python索引例子_Python实现带