1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【深度學(xué)習(xí)】高效使用Pytorch的6個(gè)技巧:為你的訓(xùn)練Pipeline提供強(qiáng)大動(dòng)力

        共 8835字,需瀏覽 18分鐘

         ·

        2020-09-17 05:44

        作者:Eugene Khvedchenya? ?編譯:ronghuaiyang

        導(dǎo)讀

        只報(bào)告的Top-1準(zhǔn)確率往往是不夠的。

        將train.py腳本轉(zhuǎn)換為具有一些附加特性的強(qiáng)大pipeline

        每一個(gè)深度學(xué)習(xí)項(xiàng)目的最終目標(biāo)都是為產(chǎn)品帶來價(jià)值。當(dāng)然,我們想要最好的模型。什么是“最好的” —— 取決于特定的用例,我將把這個(gè)討論放到這篇文章之外。我想談?wù)勅绾螐哪愕?strong>train.py腳本中得到最好的模型。

        在這篇文章中,我們將介紹以下技巧:

        1. 用高級框架代替自己寫的循環(huán)
        2. 使用另外的度量標(biāo)準(zhǔn)監(jiān)控訓(xùn)練的進(jìn)展
        3. 使用TensorBoard
        4. 使模型的預(yù)測可視化
        5. 使用Dict作為數(shù)據(jù)集和模型的返回值
        6. 檢測異常和解決數(shù)值的不穩(wěn)定性

        免責(zé)聲明:在下一節(jié)中,我將引用一些源代碼。大多數(shù)都是為[Catalyst](https://github.com/catalysts -team/catalyst)框架(20.08版)定制的,可以在pytorch-toolbelt中使用。

        不要重復(fù)造輪子

        建議1 — 利用PyTorch生態(tài)系統(tǒng)的高級訓(xùn)練框架

        PyTorch在從頭開始編寫訓(xùn)練循環(huán)時(shí)提供了極佳的靈活性和自由度。理論上,這為編寫任何訓(xùn)練邏輯提供了無限可能。在實(shí)踐中,你很少會(huì)為訓(xùn)練CycleGAN、distilling BERT或3D物體檢測從頭開始實(shí)現(xiàn)編寫訓(xùn)練循環(huán)。

        從頭編寫一個(gè)完整的訓(xùn)練循環(huán)是學(xué)習(xí)PyTorch基本原理的一個(gè)很好的方法。不過,我強(qiáng)烈建議你在掌握了一些知識(shí)之后,轉(zhuǎn)向高級框架。有很多選擇:Catalyst, PyTorch-LightningFast.AI, Ignite,以及其他。高級框架通過以下方式節(jié)省你的時(shí)間:

        • 提供經(jīng)過良好測試的訓(xùn)練循環(huán)
        • 支持配置文件
        • 支持多gpu和分布式訓(xùn)練
        • 管理檢查點(diǎn)/實(shí)驗(yàn)
        • 自動(dòng)記錄訓(xùn)練進(jìn)度

        從這些高級庫中獲得最大效果需要一些時(shí)間。然而,這種一次性的投資從長期來看是有回報(bào)的。

        優(yōu)點(diǎn)

        • 訓(xùn)練pipeline變得更小 —— 代碼越少 —— 出錯(cuò)的機(jī)會(huì)就越少。
        • 易于進(jìn)行實(shí)驗(yàn)管理。
        • 簡化分布式和混合精度訓(xùn)練。

        缺點(diǎn)

        • 通常,當(dāng)使用一個(gè)高級框架時(shí),我們必須在框架特定的設(shè)計(jì)原則和范例中編寫代碼。
        • 時(shí)間投資,學(xué)習(xí)額外的框架需要時(shí)間。

        給我看指標(biāo)

        建議2 —— 在訓(xùn)練期間查看其他指標(biāo)

        幾乎每一個(gè)用于在MNIST或CIFAR甚至ImageNet中對圖像進(jìn)行分類的快速啟動(dòng)示例項(xiàng)目都有一個(gè)共同點(diǎn) —— 它們在訓(xùn)練期間和訓(xùn)練之后都報(bào)告了一組最精簡的度量標(biāo)準(zhǔn)。通常情況下,包括Top-1和Top-5準(zhǔn)確度、錯(cuò)誤率、訓(xùn)練/驗(yàn)證損失,僅此而已。雖然這些指標(biāo)是必要的,但它只是冰山一角!

        現(xiàn)代圖像分類模型有數(shù)千萬個(gè)參數(shù)。你想只使用一個(gè)標(biāo)量值來計(jì)算它嗎?

        Top-1準(zhǔn)確率最好的CNN分類模型在泛化方面可能不是最好的。根據(jù)你的領(lǐng)域和需求,你可能希望保存具有最 false-positive/false-negative的模型,或者具有最高平均精度的模型。

        讓我給你一些建議,在訓(xùn)練過程中你可以記錄哪些數(shù)據(jù):

        • Grad-CAM heat-map —— 看看圖像的哪個(gè)部分對某一特定類的貢獻(xiàn)最大。

        可視化Grad-CAM heat-maps有助于識(shí)別模型是否基于真實(shí)病理或圖像偽影做出預(yù)測
        • Confusion Matrix — 顯示了對你的模型來說哪兩個(gè)類最具挑戰(zhàn)性。

        混淆矩陣揭示了一個(gè)模型對特定類型進(jìn)行不正確分類的頻率
        • Distribution of predictions — 讓你了解最優(yōu)決策邊界。

        該模型的negative和positive 預(yù)測的分布表明,有很大一部分?jǐn)?shù)據(jù)模型無法確定地分類
        • Minimum/Average/Maximum 跨所有層的梯度值,允許識(shí)別是否在模型中存在消失/爆炸的梯度或初始化不好的層。

        使用面板工具來監(jiān)控訓(xùn)練

        建議3 — 使用TensorBoard或任何其他解決方案來監(jiān)控訓(xùn)練進(jìn)度

        在訓(xùn)練模型時(shí),你可能最不愿意做的事情就是查看控制臺(tái)輸出。通過一個(gè)功能強(qiáng)大的儀表板,你可以在其中一次看到所有的度量標(biāo)準(zhǔn),這是檢查訓(xùn)練結(jié)果的更有效的方法。

        Tensorboard可以快速的檢查和比較你運(yùn)行的訓(xùn)練

        對于少量實(shí)驗(yàn)和非分布式環(huán)境,TensorBoard是一個(gè)黃金標(biāo)準(zhǔn)。自版本1.3以來,PyTorch就完全支持它,并提供了一組豐富的特性來管理試用版。還有一些更先進(jìn)的基于云的解決方案,比如Weights&Biases、[Alchemy](https://github.com/catalyst team/alchemy)和TensorBoard.dev,這些解決方案使得在多臺(tái)機(jī)器上監(jiān)控和比較訓(xùn)練變得更容易。

        當(dāng)使用Tensorboard時(shí),我通常記錄這樣一組指標(biāo):

        • 學(xué)習(xí)率和其他可能改變的優(yōu)化參數(shù)(動(dòng)量,重量衰減,等等)
        • 用于數(shù)據(jù)預(yù)處理和模型內(nèi)部的時(shí)間
        • 貫穿訓(xùn)練和驗(yàn)證的損失(每個(gè)batch和每個(gè)epoch的平均值)
        • 跨訓(xùn)練和驗(yàn)證的度量
        • 訓(xùn)練session的超參數(shù)最終值
        • 混淆矩陣,Precision-Recall曲線,AUC(如果適用)
        • 模型預(yù)測的可視化(如適用)

        一圖勝千言

        直觀地觀察模型的預(yù)測是非常重要的。有時(shí)訓(xùn)練數(shù)據(jù)是有噪聲的;有時(shí),模型會(huì)過擬合圖像的偽影。通過可視化最好的和最差的batch(基于損失或你感興趣的度量),你可以對模型執(zhí)行良好和糟糕的情況進(jìn)行有價(jià)值的洞察。

        建議5 — 可視化每個(gè)epoch中最好和最壞的batch。它可能會(huì)給你寶貴的見解。

        Catalyst用戶提示:這里是使用可視化回調(diào)的示例:https://github.com/BloodAxe/Catalyst-Inria-Segmentation-Example/blob/master/fit_predict.py#L258

        例如,在全球小麥檢測挑戰(zhàn)中,我們需要在圖像上檢測小麥頭。通過可視化最佳batch的圖片(基于mAP度量),我們看到模型在尋找小物體方面做得近乎完美。

        最佳模型預(yù)測的可視化顯示了模型在小物體上的良好表現(xiàn)

        相反,當(dāng)我們查看最差一批的第一個(gè)樣本時(shí),我們看到模型很難對大物體做出準(zhǔn)確的預(yù)測??梢暬治鰹槿魏螖?shù)據(jù)科學(xué)家都提供了寶貴的見解。

        最差模型預(yù)測的可視化揭示了模型在大物體上的性能很差

        查看最差的batch也有助于發(fā)現(xiàn)數(shù)據(jù)標(biāo)記中的錯(cuò)誤。通常情況下,貼錯(cuò)標(biāo)簽的樣本損失更大,因此會(huì)成為最差的batch。通過在每個(gè)epoch對最糟糕的batch做一個(gè)視覺檢查,你可以消除這些錯(cuò)誤:

        標(biāo)記錯(cuò)誤的例子。綠色像素表示true positives,紅色像素表示false negative。在這個(gè)示例中,ground-truth掩模標(biāo)在了它實(shí)際上不存在的位置上。

        使用Dict作為Dataset和Model的返回值

        建議4 — 如果你的模型返回一個(gè)以上的值,使用Dict來返回結(jié)果,不要使用tuple

        在復(fù)雜的模型中,返回多個(gè)輸出并不少見。例如,目標(biāo)檢測模型通常返回邊界框及其標(biāo)簽,在圖像分割CNN-s中,我們經(jīng)常返回中間層的mask進(jìn)行深度監(jiān)督,多任務(wù)學(xué)習(xí)最近也很常用。

        在許多開源實(shí)現(xiàn)中,我經(jīng)??吹竭@樣的東西:

        #?Bad?practice,?don't?return?tuple
        class?RetinaNet(nn.Module):
        ??...

        ??def?forward(self,?image):
        ????x?=?self.encoder(image)
        ????x?=?self.decoder(x)
        ????bboxes,?scores?=?self.head(x)
        ????return?bboxes,?scores

        ??...

        對于作者來說,我認(rèn)為這是一種非常糟糕的從模型返回結(jié)果的方法。下面是我推薦的替代方法:

        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?}

        ??...

        這個(gè)建議在某種程度上與“The Zen of Python”的設(shè)定產(chǎn)生了共鳴 —— “明確的比含蓄的更好”。遵循這一規(guī)則將使你的代碼更清晰、更容易維護(hù)。

        那么為什么我認(rèn)為第二種選擇更好呢?有幾個(gè)原因:

        • 返回值有一個(gè)顯式的名稱與它關(guān)聯(lián)。你不需要記住元組中元素的確切順序。
        • 如果你需要訪問返回的字典的一個(gè)特定元素,你可以通過它的名字來訪問。
        • 從模型中添加新的輸出不會(huì)破壞代碼。

        使用Dict,你甚至可以更改模型的行為,以按需返回額外的輸出。例如,這里有一個(gè)簡短的片段,演示了如何返回多個(gè)“主”輸出和兩個(gè)“輔助”輸出來進(jìn)行度量學(xué)習(xí):

        #?https://github.com/BloodAxe/Kaggle-2020-Alaska2/blob/master/alaska2/models/timm.py#L104

        def?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]?=?embedding
        ??if?self.arc_margin?is?not?None:
        ????result[OUTPUT_PRED_EMBEDDING_ARC_MARGIN]?=?self.arc_margin(embedding)

        ??return?result

        同樣的建議也適用于Dataset類。對于Cifar-10玩具示例,可以將圖像及其對應(yīng)的標(biāo)簽作為元組返回。但當(dāng)處理多任務(wù)或多輸入模型,你想從數(shù)據(jù)集返回Dict類型的樣本:

        #?https://github.com/BloodAxe/Kaggle-2020-Alaska2/blob/master/alaska2/dataset.py#L373
        class?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?=?bits

        ????def?__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

        當(dāng)你的代碼中有Dictionaries時(shí),你可以在任何地方使用名稱常量引用輸入/輸出。遵循這條規(guī)則將使你的訓(xùn)練管道非常清晰和容易遵循:

        #?https://github.com/BloodAxe/Kaggle-2020-Alaska2

        callbacks?+=?[
        ??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),
        ]

        在訓(xùn)練中檢測異常

        就像人類可以閱讀含有許多錯(cuò)誤的文本一樣,深度學(xué)習(xí)模型也可以在訓(xùn)練過程中出現(xiàn)錯(cuò)誤時(shí)學(xué)習(xí)“一些合理的東西”。作為一名開發(fā)人員,你要負(fù)責(zé)搜索異常并對其表現(xiàn)進(jìn)行推理。

        建議5 — 在訓(xùn)練期間使用 torch.autograd.detect_anomaly()查找算術(shù)異常

        如果你在訓(xùn)練過程中在損失/度量中看到NaNs或Inf,你的腦海中就會(huì)響起一個(gè)警報(bào)。它是你的管道中有問題的指示器。通常情況下,它可能由以下原因引起:

        • 模型或特定層的初始化不好(你可以通過觀察梯度大小來檢查哪些層)
        • 數(shù)學(xué)上不正確的運(yùn)算(負(fù)數(shù)的torch.sqrt(),非正數(shù)的torch.log(),等等)
        • 不當(dāng)使用torch.mean()torch.sum() 的reduction(zero-sized張量上的均值會(huì)得到nan,大張量上的sum容易導(dǎo)致溢出)
        • 在loss中使用x.sigmoid()(如果你需要在loss函數(shù)中使用概率,更好的方法是x.sigmoid().clamp(eps,1-eps )以防止梯度消失)
        • 在Adam-like的優(yōu)化器中的低epsilon值
        • 在使用fp16的訓(xùn)練的時(shí)候沒有使用動(dòng)態(tài)損失縮放

        為了找到你代碼中第一次出現(xiàn)Nan/Inf的確切位置,PyTorch提供了一個(gè)簡單易用的方法torch. autograde .detect_anomaly()

        import?torch

        def?main():
        ????torch.autograd.detect_anomaly()
        ????...
        ????#?Rest?of?the?training?code
        ???

        #?OR
        class?MyNumericallyUnstableLoss(nn.Module):
        ??def?forward(self,?input,?target):
        ????with?torch.autograd.set_detect_anomaly(True):
        ???????loss?=?input?*?target
        ???????return?loss

        將其用于調(diào)試目的,否則就禁用它,異常檢測會(huì)帶來計(jì)算開銷,并將訓(xùn)練速度降低10-15% 。


        END

        英文原文:https://towardsdatascience.com/efficient-pytorch-supercharging-training-pipeline-19a26265adae


        往期精彩回顧





        獲取一折本站知識(shí)星球優(yōu)惠券,復(fù)制鏈接直接打開:

        https://t.zsxq.com/662nyZF

        本站qq群1003271085。

        加入微信群請掃碼進(jìn)群(如果是博士或者準(zhǔn)備讀博士請說明):

        瀏覽 64
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产精品久久久久久免费 | 欧美成人免费无码区色情街野花 | 91在线无码精品秘 在线看 | 八重神子狂飙高清视频在线播放 | 国产精品午夜成人免费 | 天天弄天天干 | 国产孕妇孕交 | 艹屄视频在线观看 | 狠狠色噜噜狠狠狠狠 | 操逼逼的视频 |