Fastai-学习器训练
模型訓練
簡介
在Fastai框架下,其實完成了前文所說的數據準備工作,就已經完成了深度網絡訓練的一半工作。剩下的就是學習器的構建以及訓練效果的分析,也就是模型訓練的部分。
學習器
在Fastai中,關于模型的構建并沒有具體的API,要想實現自定義模型需要通過PyTorch的接口實現(參考我PyTorch模型的博文),所以Fastai中模型都是基于預定義的一些模型,這些模型都在fastai.vision.models下,是對torchvision定義的一些模型結構的引用和完善。
所以可以看出,Fastai的主要思想就是基于遷移學習(Transfer Learning),具體可以查詢遷移學習的一些文章了解。總之,關于組合預定義的模型(如resnet,這些模型都是torchvision定義的,具體哪些可以自行查看)和數據集(DataBunch),然后投入訓練,Fastai提供了一個非常方便的工廠方法cnn_learner,它能夠自動初始化合適的預訓練模型并構建頂層結構以適應數據集。事實上,fastai.vision.learner最核心的兩個方法就是cnn_learner和unet_learner,它們都會返回一個fastai.vision.Learner對象,該對象包含訓練(fit)、預測(predict)等方法。
cnn_learner(data:DataBunch, # 傳入的數據集base_arch:Callable, # 要進行Finetune的主干網絡,接受`torch.nn.Model`的所有類型,包括自定義的cut:Union[int, Callable]=None, # 在那一層分割網絡pretrained:bool=True, # 是否使用預訓練模型,若使用則除頂層網絡都會被凍結lin_ftrs:Optional[Collection[int]]=None, # 添加頭部網絡中線性層特征數ps:Floats=0.5, # 添加頭部網絡中Dropout概率custom_head:Optional[Module]=None, # 自定義頭部網絡split_on:Union[Callable, Collection[ModuleList], NoneType]=None, # 主干網絡分組函數bn_final:bool=False, # 分類前是否bn層init='kaiming_normal_', # 頭部網絡參數初始化方法,默認kaiming初始化concat_pool:bool=True, # 連接池化層**kwargs:Any)該方法從數據data和模型base_arch中生成一個Learner對象,它會截斷原始模型(backbone,主干網絡)(該截斷默認在最后一個包含pooling層處分割)并在頂層添加線性分類層(head,頭部網絡),具體添加的結構可以查看官方文檔。該方法參數豐富是為了方便自定義結構,實際進行使用時,很多默認參數就是很合理的,不需要過多調整。關于模型結構,該鏈接提供了很多比較常用的PyTorch實現的模型結構。
至此,就創建了一個很實用的學習器,下面將研究具體的訓練過程。
訓練
Fastai中最核心的訓練方法為learn.fit()方法,很多demo中會提到learner.fit_one_cycle()方法,事實上這個方法在最新的Fastai中已經不建議使用了,它本質上就是fit方法添加OneCycleScheduler(one cycle策略)的回調組成的訓練方法,自己在fit中添加即可。
fit是整個Fastai最為核心的訓練函數,在fastai.basic_train模塊中定義,具體參數和說明如下。
fit(epochs:int, # 訓練輪次lr:Union[float, Collection[float], slice]=slice(None, 0.003, None), # 學習率wd:Floats=None, # 學習率衰減比例callbacks:Collection[Callback]=None) # 回調列表該函數表示在學習器上訓練模型,使用包含每輪學習率衰減的訓練方法,并添加一些回調函數。這里比較特殊的參數就是學習率,lr會被進一步處理為一個浮點型數組,數組長度和learner.layer_groups一致,用于不同深度的網絡層的差異化訓練,而根據不同的lr參數值會有不同的構造方式。
- 數值:返回的lr數組為全為lr值的數組;
- slice對象(含start和stop):返回一個等比序列,起始值和終止值如slice設定;
- slice對象(含stop):最后一個lr為stop,其余為stop/10。
例如,下面的一段代碼,就表示完整的數據讀入、學習器構建、訓練、驗證的過程。
ds = data.ImageDataBunch.from_folder("101_ObjectCategories/", valid_pct=0.2, size=128) learner_ = learner.cnn_learner(ds, models.resnet50, metrics=[metrics.accuracy]) learner_.fit(1)Jupyter環境下的輸出為下圖,一輪的訓練模型效果還是不錯的。
在上面的三行代碼中,在學習器構建的時候,使用了metrics參數,該參數表示訓練中使用的評估指標,上述代碼指定的為準確率。
metrics
常用的評估指標都封裝于fastai.metrics模塊下,它們接受模型輸出outputs和標簽targets作為輸入并計算相應指標值,訓練時提供的metrics會被封裝為回到,在每一輪訓練中使用,具體工作流程這里不多敘述,稍有點復雜。可以查閱文檔了解具體的指標,包括準確率、mse、r2得分等各類指標。
callbacks
訓練過程中難免需要進行一些特殊的操作,如及時停止陷入過擬合的模型、每個batch后進行學習率調整等等,這些操作被稱為回調(callbacks),封裝在fastai.callbacks模塊下,但是在fastai.callback模塊下封裝了一些回調的機制,如果不是想要了解Fastai的源碼實現的話,可以不做深入探究,它主要將訓練分為了多個階段,并在合適的階段通過回調處理器來進行回調操作。
下面介紹一些常用的回調,他們封裝于keras.callbacks中,以類的形式存在,使用時只需要實例化一個對象出來即可。
LRFinder OneCycleScheduler MixUpCallback CSVLogger GeneralScheduler MixedPrecision HookCallback RNNTrainer TerminateOnNaNCallback EarlyStoppingCallback SaveModelCallback ReduceLROnPlateauCallback PeakMemMetric StopAfterNBatches LearnerTensorboardWriter # train and basic_train Recorder ShowGraph BnFreeze GradientClipping上面的就是全部的回調方法(也可以自定義),下面具體說明幾個常用的。
Recorder(learn:Learner, add_time:bool=True, silent:bool=False)可以理解為一個記錄器,用于記錄學習器的狀態,Jupyter環境下訓練時輸出的表格就是該回調實現的,類似于Keras中的History,是默認添加的回調,可以通過learner.recoder獲取該對象。該對象有一系列的方法,比較實用的有recoder.plot()(繪制損失隨學習率變化曲線)、recoder.plot_losses(繪制訓練和驗證時的損失曲線)等。
lr_find(learn:Learner, start_lr:Floats=1e-07, end_lr:Floats=10, num_it:int=100, stop_div:bool=True, wd:float=None)這是fastai.train中定義的函數,通過訓練若干個batch繪制學習率曲線找到較為合適的學習率(上下界可以指定),也會進行訓練的控制(如停止訓練)。主要通過fastai.callbacks.LRFinder類實現,將其加入回調即可。
OneCycleScheduler(learn:Learner, lr_max:float, moms:Floats=(0.95, 0.85), div_factor:float=25.0, pct_start:float=0.3, final_div:float=None, tot_epochs:int=None, start_epoch:int=None)按照著名的one cycle策略進行學習率的調整,可以設置一個cycle的epoch數等參數。
除此之外,還有很多實用的回調函數,這里不一一分析,可以查閱文檔。
下面的代碼就是添加了一個one cycle回調后的訓練學習率變化的代碼和學習率變化曲線(通過learner.recoder.pplot_lr())繪制。
from fastai.vision import data, learner, models from fastai import metrics from fastai import callbacksds = data.ImageDataBunch.from_folder("101_ObjectCategories/", valid_pct=0.2, size=128) learner_ = learner.cnn_learner(ds, models.resnet50, metrics=[metrics.accuracy]) one_cycle = callbacks.OneCycleScheduler(learner_, lr_max=0.1) learner_.fit(10, lr=3e-4, callbacks=[one_cycle, ])推理
學習器訓練完成了,當然就要用于實際的推理中,關于學習器的推理(預測)設計了諸多API,常用的有如下幾種。
單個數據推理
learn.predict(data)來獲得單個數據的推理結果,如執行print(learner_.predict(learner_.data.train_ds[0][0]))會對訓練集第一個圖片進行預測,結果是個三元組,(類別名,類別索引,網絡輸出向量)。
批量數據推理
learn.pred_batch(ds)對一批數據進行推理預測,返回一批數據的網絡輸出,本例就是(64, 101)的張量輸出。
數據集推理(訓練集或者測試集)
get_preds(ds_type:DatasetType=<DatasetType.Valid: 2>, # 指定推理數據集類型activ:Module=None, # with_loss:bool=False, # 是否返回lossn_batch:Optional[int]=None, # 批處理尺寸pbar:Union[MasterBar, ProgressBar, NoneType]=None)指定with_loss后返回三個值,分別表示輸出向量、標簽索引、損失值,不設定with_loss則只輸出前兩者。
數據集推理(指標)
通過learner.validate(dl, callbacks, metrics)對任意數據集生成的數據加載器進行結果推理(用于計算指標值,如損失和準確率等)。
例如對驗證集計算默認指標使用learner_.validate(learner_.data.valid_dl)就可以了。也可以通過learner.show_results(ds_type, rows)對數據集進行抽樣推理并可視化。
解釋器
Fastai實現了非常豐富的結果解釋器模塊,在每個application下都有具體實現,fastai.vision.interpret中就是視覺方面的具體實現。主要由ClassificationInterpretation(該類在fastai.train模塊下)、SegmentationInterpretation等解釋器類構成。
這些類含有from_learner()方法用于從學習器創建解釋器,也可以通過learn.interpret()來獲得解釋器,這種方法獲得的解釋器依據learner類型進行創建。
分類解釋器使用較多,它的具體文檔可以查閱。它有很多常用的方法,舉例如下。
interpreter.top_losses(k)會返回損失最大的k個損失值和數據下標。interpreter.plot_top_losses(k)對損失最大的k個圖像可視化。
interpreter.confusion_matrix()計算驗證集上的混淆矩陣,可以修改數據集。同時interpreter.plot_confusion_matrix()表示繪制混淆矩陣。
模型的保存與加載
分為參數保存和整個模型的保存,后者通過export()和load_learner()方法實現,使用較少,主要是保存模型參數。
learner.save(file:PathLikeOrBinaryStream=None, # 文件路徑return_path:bool=False, # 是否返回路徑字符串with_opt:bool=True) # 是否保存優化器及其參數若file參數是相對路徑,則會使用learner.path作為目錄,創建models文件夾后存放權重文件。
相應的,構造完成learner后調用load方法就可以加載模型參數了。
learner.load(file:PathLikeOrBinaryStream=None, device:torch.device=None, strict:bool=True,with_opt:bool=None, purge:bool=False, remove_module:bool=False)至此,模型訓練的整個內容就完成了。
補充說明
本文主要講解Fastai框架下學習器的構建、訓練、推理分析、保存和加載等操作,更多請了解官方文檔,具體代碼開源于我的Github,歡迎star或者fork。
總結
以上是生活随笔為你收集整理的Fastai-学习器训练的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Fastai-数据准备
- 下一篇: Fastai-竞赛实战