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