close

知乎—吵雞凶鴨OvO 侵刪

原文 https://zhuanlan.zhihu.com/p/446812760
本篇文章將介紹神經網絡訓練過程中的三個必備技能:使用預訓練權重、凍結訓練和斷點恢復,巧妙運用這三個技巧可以很有效地提高網絡的訓練效率和效果。

01




引言
If I have seen further, it is by standing on the shoulders of giants.
遷移學習在計算機視覺領域中是一種很流行的方法,因為它可以建立精確的模型,耗時更短。利用遷移學習,不是從零開始學習,而是從之前解決各種問題時學到的模式開始。這樣,我們就可以利用以前的學習成果,避免從零開始。

02




使用預訓練權重
在計算機視覺領域中,遷移學習通常是通過使用預訓練模型來表示的。預訓練模型是在大型基準數據集上訓練的模型,用於解決相似的問題。由於訓練這種模型的計算成本較高,因此,導入已發布的成果並使用相應的模型是比較常見的做法。例如,在目標檢測任務中,首先要利用主幹神經網絡進行特徵提取,這裡使用的backbone一般就是VGG、ResNet等神經網絡,因此在訓練一個目標檢測模型時,可以使用這些神經網絡的預訓練權重來將backbone的參數初始化,這樣在一開始就能提取到比較有效的特徵。
可能大家會有疑問,預訓練權重是針對他們數據集訓練得到的,如果是訓練自己的數據集還能用嗎?預訓練權重對於不同的數據集是通用的,因為特徵是通用的。一般來講,從0開始訓練效果會很差,因為權值太過隨機,特徵提取效果不明顯。對於目標檢測模型來說,一般不從0開始訓練,至少會使用主幹部分的權值,雖然有些論文提到了可以不用預訓練,但這主要是因為他們的數據集比較大而且他們的調參能力很強。如果從0開始訓練,網絡在前幾個epoch的Loss可能會非常大,並且多次訓練得到的訓練結果可能相差很大,因為權重初始化太過隨機。
PyTorch提供了state_dict()和load_state_dict()兩個方法用來保存和加載模型參數,前者將模型參數保存為字典形式,後者將字典形式的模型參數載入到模型當中。下面是使用預訓練權重(加載預訓練模型)的代碼,其中model_path就是預訓練權重文件的路徑:

# 第一步:讀取當前模型參數model_dict = model.state_dict()# 第二步:讀取預訓練模型pretrained_dict = torch.load(model_path, map_location = device)pretrained_dict = {k: v for k, v in pretrained_dict.items() if np.shape(model_dict[k]) == np.shape(v)}# 第三步:使用預訓練的模型更新當前模型參數model_dict.update(pretrained_dict)# 第四步:加載模型參數model.load_state_dict(model_dict)
但是,使用load_state_dict()加載模型參數時,要求保存的模型參數鍵值類型和模型完全一致,一旦我們對模型結構做了些許修改,就會出現類似unexpected key module.xxx.weight問題。比如在目標檢測模型中,如果修改了主幹特徵提取網絡,只要不是直接替換為現有的其它神經網絡,基本上預訓練權重是不能用的,要麼就自己判斷權值里卷積核的shape然後去匹配,要麼就只能利用這個主幹網絡在諸如ImageNet這樣的數據集上訓練一個自己的預訓練模型;如果修改的是後面的neck或者是head的話,前面的backbone的預訓練權重還是可以用的。下面是權值匹配的示例代碼,把不匹配的直接pass了:

model_dict = model.state_dict()pretrained_dict = torch.load(model_path, map_location=device)temp = {}for k, v in pretrained_dict.items(): try: if np.shape(model_dict[k]) == np.shape(v): temp[k]=v except: passmodel_dict.update(temp)

03




凍結訓練
凍結訓練其實也是遷移學習的思想,在目標檢測任務中用得十分廣泛。因為目標檢測模型里,主幹特徵提取部分所提取到的特徵是通用的,把backbone凍結起來訓練可以加快訓練效率,也可以防止權值被破壞。在凍結階段,模型的主幹被凍結了,特徵提取網絡不發生改變,占用的顯存較小,僅對網絡進行微調。在解凍階段,模型的主幹不被凍結了,特徵提取網絡會發生改變,占用的顯存較大,網絡所有的參數都會發生改變。舉個例子,如果在解凍階段設置batch_size為4,那麼在凍結階段有可能可以把batch_size設置到8。下面是進行凍結訓練的示例代碼,假設前50個epoch凍結,後50個epoch解凍:

# 凍結階段訓練參數,learning_rate和batch_size可以設置大一點Init_Epoch = 0Freeze_Epoch = 50Freeze_batch_size = 8Freeze_lr = 1e-3# 解凍階段訓練參數,learning_rate和batch_size設置小一點UnFreeze_Epoch = 100Unfreeze_batch_size = 4Unfreeze_lr = 1e-4# 可以加一個變量控制是否進行凍結訓練Freeze_Train = True# 凍結一部分進行訓練batch_size = Freeze_batch_sizelr = Freeze_lrstart_epoch = Init_Epochend_epoch = Freeze_Epochif Freeze_Train: for param in model.backbone.parameters(): param.requires_grad = False# 解凍後訓練batch_size = Unfreeze_batch_sizelr = Unfreeze_lrstart_epoch = Freeze_Epochend_epoch = UnFreeze_Epochif Freeze_Train: for param in model.backbone.parameters(): param.requires_grad = True
如果不進行凍結訓練,一定要注意參數設置,注意上述代碼中凍結階段和解凍階段的learning_rate和batch_size是不一樣的,另外起始epoch和結束epoch也要重新調整一下。如果是從0開始訓練模型(不使用預訓練權重),那麼一定不能進行凍結訓練。

04




斷點恢復
在上面凍結訓練和解凍訓練的代碼里設置了不同的batch_size,前者是8後者是4,有可能凍結訓練的時候顯存是夠用的,結果解凍後顯存不足了,這個時候需要重新把解凍訓練階段的batch_size調得更小一點。但是網絡才訓練了凍結階段的50個epoch,backbone參數還是用的預訓練權重呢,網絡效果肯定不夠好。難道要前功盡棄重新開始訓練?這時候就要使用斷點恢復技術了。其實斷點恢復的思想很簡單,就是把網絡初始設置的model_path改為出錯前保存好的權值文件,然後調整一下起始epoch和終止epoch即可,比如在前面提到的這種情況里,在第51個epoch報了錯,那麼可以把model_path修改為第50個epoch訓練結束後保存的權值文件,然後把起始epoch調整成50就可以了。
斷點恢復的應用範圍非常非常廣。最常見的情況就是代碼跑到一半因為某些原因中斷了(比如電腦突然死機重啟這種不可抗力因素),又不想從頭重新跑,那麼就可以利用斷點恢復訓練的方法,這樣可以節省不少時間。再比如,一個非常常見的情況,假如一開始設置了100個epoch,結果模型訓練結束時,Loss還呈現下降的趨勢,也就是模型還沒有收斂,這種現象有可能就是epoch設置小了,所以可以把第100個epoch訓練得到的權值文件當做初始權值文件再訓練幾個epoch看看,避免重新設置epoch從頭訓練。
當然,想要執行斷點恢復首先需要把每個epoch得到的權值文件保存起來,這樣才能修改model_path重新加載。斷點恢復和常規的模型保存加載的區別其實就是epoch也要修改一下而已。保存權重可以用以下方法:

torch.save(model.state_dict(),"你要保存到的路徑")

05




預訓練和微調
最後再來總結一下預訓練和微調,這是兩個非常重要的概念,其實也很好理解。舉個栗子是最能直觀理解的。
假如我們現在要搭建一個網絡模型來完成一個圖像分類的任務,首先我們需要把網絡的參數進行初始化,然後在訓練網絡的過程中不斷對參數進行調整,直到網絡的損失越來越小。在訓練過程中,一開始初始化的參數會不斷變化,如果結果已經滿意了,那我們就可以把訓練好的模型參數保存下來,以便訓練好的模型可以在下次執行類似任務的時候獲得比較好的效果。這個過程就是預訓練(Pre-Training)。
假如在完成上面的模型訓練後,我們又接到另一個類似的圖像分類任務,這時我們就可以直接使用之前保存下來的模型參數作為這一次任務的初始化參數,然後在訓練過程中依據結果不斷進行修改,這個過程就是微調(Fine-Tuning)。
我們使用的神經網絡越深,就需要越多的樣本來進行訓練,否則就很容易出現過擬合現象。比如我們想訓練一個識別貓的模型,但是自己標註數據精力有限只標了100張,這時就可以考慮ImageNet數據集,可以在ImageNet上訓練一個模型,然後使用該模型作為類似任務的初始化或特徵提取器,這樣既節省了時間和計算資源,又能很快地達到較好的效果。當然,採用預訓練+微調也不是絕對有效的,上面識別貓的例子可以這樣做是因為ImageNet里有貓的圖像,所以可以認為是一個類似的數據集,如果是識別癌細胞的話,效果可能就不是那麼好了。關於預訓練和微調是有很多策略的,經驗也很重要。

猜您喜歡:

超110篇!CVPR 2021最全GAN論文匯總梳理!

超100篇!CVPR 2020最全GAN論文梳理匯總!

拆解組新的GAN:解耦表徵MixNMatch

StarGAN第2版:多域多樣性圖像生成

附下載 |《可解釋的機器學習》中文版

附下載 |《TensorFlow 2.0 深度學習算法實戰》

附下載 |《計算機視覺中的數學方法》分享

《基於深度學習的表面缺陷檢測方法綜述》

《零樣本圖像分類綜述: 十年進展》

《基於深度神經網絡的少樣本學習綜述》


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()