參考鏈接:https://github.com/datawhalechina/thorough-pytorch
本task注重于pytorch在實際使用中的一些操作~較為實用
1.自定義損失函數(shù)
PyTorch在torch.nn模塊為我們提供了許多常用的損失函數(shù),比如:MSELoss,L1Loss搪锣,BCELoss...... 但是隨著深度學習的發(fā)展樱衷,出現(xiàn)了越來越多的非官方提供的Loss,比如DiceLoss鼓蜒,HuberLoss,SobolevLoss...... 這些Loss Function專門針對一些非通用的模型,PyTorch不能將他們全部添加到庫中去筏养,因此這些損失函數(shù)的實現(xiàn)則需要我們通過自定義損失函數(shù)來實現(xiàn)。另外常拓,在科學研究中渐溶,我們往往會提出全新的損失函數(shù)來提升模型的表現(xiàn),這時我們既無法使用PyTorch自帶的損失函數(shù)弄抬,也沒有相關的博客供參考茎辐,此時自己實現(xiàn)損失函數(shù)就顯得更為重要了。
1.1 以函數(shù)方式定義
1.2 以類方式定義
雖然以函數(shù)定義的方式很簡單,但是以類方式定義更加常用拖陆,在以類方式定義損失函數(shù)時弛槐,我們如果看每一個損失函數(shù)的繼承關系我們就可以發(fā)現(xiàn)Loss函數(shù)部分繼承自_loss, 部分繼承自_WeightedLoss, 而_WeightedLoss繼承自_loss,?_loss繼承自?nn.Module慕蔚。我們可以將其當作神經網絡的一層來對待丐黄,同樣地,我們的損失函數(shù)類就需要繼承自nn.Module類孔飒,下面以DiceLoss為例灌闺。
除此之外,常見的損失函數(shù)還有BCE-Dice Loss坏瞄,Jaccard/Intersection over Union (IoU) Loss桂对,F(xiàn)ocal Loss等。
Focal loss主要是為了解決one-stage目標檢測中正負樣本比例嚴重失衡的問題鸠匀。該損失函數(shù)降低了大量簡單負樣本在訓練中所占的權重蕉斜,也可理解為一種困難樣本挖掘。是 Kaiming 大神團隊在論文Focal Loss for Dense Object Detection?提出來的損失函數(shù)缀棍,利用它改善了圖像物體檢測的效果宅此。
2.動態(tài)調整學習率
學習率的選擇是深度學習中一個困擾人們許久的問題,學習速率設置過小爬范,會極大降低收斂速度父腕,增加訓練時間;學習率太大青瀑,可能導致參數(shù)在最優(yōu)解兩側來回振蕩璧亮。但是當我們選定了一個合適的學習率后,經過許多輪的訓練后斥难,可能會出現(xiàn)準確率震蕩或loss不再下降等情況枝嘶,說明當前學習率已不能滿足模型調優(yōu)的需求。此時我們就可以通過一個適當?shù)膶W習率衰減策略來改善這種現(xiàn)象哑诊,提高我們的精度群扶。這種設置方式在PyTorch中被稱為scheduler。
2.1 使用官方scheduler
在訓練神經網絡的過程中镀裤,學習率是最重要的超參數(shù)之一穷当,作為當前較為流行的深度學習框架,PyTorch已經在torch.optim.lr_scheduler為我們封裝好了一些動態(tài)調整學習率的方法供我們使用淹禾,如下面列出的這些scheduler馁菜。
關于如何使用這些動態(tài)調整學習率的策略,PyTorch官方也很人性化的給出了使用實例代碼铃岔,我們在使用官方給出的torch.optim.lr_scheduler時汪疮,需要將scheduler.step()放在optimizer.step()后面進行使用峭火。
2.2?自定義scheduler
雖然PyTorch官方給我們提供了許多的API,但是在實驗中也有可能碰到需要我們自己定義學習率調整策略的情況智嚷,而我們的方法是自定義函數(shù)adjust_learning_rate來改變param_group中l(wèi)r的值卖丸,在下面的敘述中會給出一個簡單的實現(xiàn)。
假設我們現(xiàn)在正在做實驗盏道,需要學習率每30輪下降為原來的1/10稍浆,假設已有的官方API中沒有符合我們需求的,那就需要自定義函數(shù)來實現(xiàn)學習率的改變猜嘱。
3.模型微調
參考鏈接:https://blog.csdn.net/qq_42250789/article/details/108832004
微調定義:?給定預訓練模型(Pre_trained model),基于模型進行微調(Fine Tune)衅枫。相對于從頭開始訓練(Training a model from scatch),微調為你省去大量計算資源和計算時間朗伶,提高了計算效率,甚至提高準確率弦撩。
預訓練模型:(1) 預訓練模型就是已經用數(shù)據(jù)集訓練好了的模型。(2) 現(xiàn)在我們常用的預訓練模型就是他人用常用模型论皆,比如VGG16/19益楼,Resnet等模型,并用大型數(shù)據(jù)集來做訓練集点晴,比如Imagenet, COCO等訓練好的模型參數(shù)感凤。 (3)? 正常情況下,我們常用的VGG16/19等網絡已經是他人調試好的優(yōu)秀網絡粒督,我們無需再修改其網絡結構陪竿。
不同數(shù)據(jù)集下使用微調:
數(shù)據(jù)集1 - 數(shù)據(jù)量少,但數(shù)據(jù)相似度非常高 - 在這種情況下坠陈,我們所做的只是修改最后幾層或最終的softmax圖層的輸出類別。
數(shù)據(jù)集2 - 數(shù)據(jù)量少捐康,數(shù)據(jù)相似度低 - 在這種情況下仇矾,我們可以凍結預訓練模型的初始層(比如k層),并再次訓練剩余的(n-k)層解总。由于新數(shù)據(jù)集的相似度較低贮匕,因此根據(jù)新數(shù)據(jù)集對較高層進行重新訓練具有重要意義。
數(shù)據(jù)集3? - 數(shù)據(jù)量大花枫,數(shù)據(jù)相似度低 - 在這種情況下刻盐,由于我們有一個大的數(shù)據(jù)集,我們的神經網絡訓練將會很有效劳翰。但是敦锌,由于我們的數(shù)據(jù)與用于訓練我們的預訓練模型的數(shù)據(jù)相比有很大不同。使用預訓練模型進行的預測不會有效佳簸。因此乙墙,最好根據(jù)你的數(shù)據(jù)從頭開始訓練神經網絡(Training from scatch)
數(shù)據(jù)集4? - 數(shù)據(jù)量大,數(shù)據(jù)相似度高 - 這是理想情況。在這種情況下听想,預訓練模型應該是最有效的腥刹。使用模型的最好方法是保留模型的體系結構和模型的初始權重。然后汉买,我們可以使用在預先訓練的模型中的權重來重新訓練該模型衔峰。
3.1 模型微調的流程
在源數(shù)據(jù)集(如ImageNet數(shù)據(jù)集)上預訓練一個神經網絡模型,即源模型蛙粘。
創(chuàng)建一個新的神經網絡模型垫卤,即目標模型。它復制了源模型上除了輸出層外的所有模型設計及其參數(shù)组题。我們假設這些模型參數(shù)包含了源數(shù)據(jù)集上學習到的知識葫男,且這些知識同樣適用于目標數(shù)據(jù)集。我們還假設源模型的輸出層跟源數(shù)據(jù)集的標簽緊密相關崔列,因此在目標模型中不予采用梢褐。
為目標模型添加一個輸出?小為?標數(shù)據(jù)集類別個數(shù)的輸出層,并隨機初始化該層的模型參數(shù)盈咳。
在目標數(shù)據(jù)集上訓練目標模型鱼响。我們將從頭訓練輸出層,而其余層的參數(shù)都是基于源模型的參數(shù)微調得到的。
3.2 使用已有模型結構
這里我們以torchvision中的常見模型為例,列出了如何在圖像分類任務中使用PyTorch提供的常見模型結構和參數(shù)晶密。對于其他任務和網絡結構,使用方式是類似的:
實例化網格:
傳遞pretrained參數(shù):通過True或者False來決定是否使用預訓練好的權重归苍,在默認狀態(tài)下pretrained = False摇展,意味著我們不使用預訓練得到的權重盯孙,當pretrained = True垄懂,意味著我們將使用在一些數(shù)據(jù)集上預訓練得到的權重桶蛔。
注意事項:
通常PyTorch模型的擴展為.pt或.pth碟婆,程序運行時會首先檢查默認路徑中是否有已經下載的模型權重,一旦權重被下載甥温,下次加載就不需要下載了。
一般情況下預訓練模型的下載會比較慢释涛,我們可以直接通過迅雷或者其他方式去?這里?查看自己的模型里面model_urls展融,然后手動下載,預訓練模型的權重在Linux和Mac的默認下載路徑是用戶根目錄下的.cache文件夾。在Windows下就是C:\Users\<username>\.cache\torch\hub\checkpoint。我們可以通過使用?torch.utils.model_zoo.load_url()設置權重的下載地址。
如果覺得麻煩,還可以將自己的權重下載下來放到同文件夾下,然后再將參數(shù)加載網絡扔涧。
self.model=models.resnet50(pretrained=False)
self.model.load_state_dict(torch.load('./model/resnet50-19c8e357.pth'))
如果中途強行停止下載的話湖雹,一定要去對應路徑下將權重文件刪除干凈鸽嫂,要不然可能會報錯纵装。
3.3 訓練特定層
在默認情況下,參數(shù)的屬性.requires_grad = True据某,如果我們從頭開始訓練或微調不需要注意這里橡娄。但如果我們正在提取特征并且只想為新初始化的層計算梯度,其他參數(shù)不進行改變癣籽。那我們就需要通過設置requires_grad = False來凍結部分層瀑踢。在PyTorch官方中提供了這樣一個例程。
在下面我們仍舊使用resnet18為例的將1000類改為4類才避,但是僅改變最后一層的模型參數(shù)橱夭,不改變特征提取的模型參數(shù);注意我們先凍結模型參數(shù)的梯度桑逝,再對模型輸出部分的全連接層進行修改棘劣,這樣修改后的全連接層的參數(shù)就是可計算梯度的。
之后在訓練過程中楞遏,model仍會進行梯度回傳茬暇,但是參數(shù)更新則只會發(fā)生在fc層。通過設定參數(shù)的requires_grad屬性寡喝,我們完成了指定訓練模型的特定層的目標糙俗,這對實現(xiàn)模型微調非常重要。
4. 半精度訓練
我們提到PyTorch時候预鬓,總會想到要用硬件設備GPU的支持巧骚,也就是“卡”。GPU的性能主要分為兩部分:算力和顯存格二,前者決定了顯卡計算的速度劈彪,后者則決定了顯卡可以同時放入多少數(shù)據(jù)用于計算。在可以使用的顯存數(shù)量一定的情況下顶猜,每次訓練能夠加載的數(shù)據(jù)更多(也就是batch size更大)沧奴,則也可以提高訓練效率。另外长窄,有時候數(shù)據(jù)本身也比較大(比如3D圖像滔吠、視頻等),顯存較小的情況下可能甚至batch size為1的情況都無法實現(xiàn)挠日。因此疮绷,合理使用顯存也就顯得十分重要。
我們觀察PyTorch默認的浮點數(shù)存儲方式用的是torch.float32肆资,小數(shù)點后位數(shù)更多固然能保證數(shù)據(jù)的精確性矗愧,但絕大多數(shù)場景其實并不需要這么精確灶芝,只保留一半的信息也不會影響結果郑原,也就是使用torch.float16格式唉韭。由于數(shù)位減了一半,因此被稱為“半精度”犯犁。
顯然半精度能夠減少顯存占用属愤,使得顯卡可以同時加載更多數(shù)據(jù)進行計算。本節(jié)會介紹如何在PyTorch中設置使用半精度計算酸役。
4.1?半精度訓練的設置
在PyTorch中使用autocast配置半精度訓練住诸,同時需要在下面三處加以設置:
注意:
半精度訓練主要適用于數(shù)據(jù)本身的size比較大(比如說3D圖像、視頻等)涣澡。當數(shù)據(jù)本身的size并不大時(比如手寫數(shù)字MNIST數(shù)據(jù)集的圖片尺寸只有28*28)贱呐,使用半精度訓練則可能不會帶來顯著的提升。