前言
模型訓(xùn)練過(guò)程中可能由于網(wǎng)絡(luò)問(wèn)題、或者服務(wù)器斷開(kāi)等問(wèn)題導(dǎo)致模型訓(xùn)練意外出現(xiàn)中斷,或者是由于自己主動(dòng)中斷訓(xùn)練等各種情況。
這時(shí)候就需要斷點(diǎn)續(xù)訓(xùn),即接著之前已經(jīng)訓(xùn)練好的weights.pt和epochs重新開(kāi)始訓(xùn)練。還需要訓(xùn)練日志也重新續(xù)接上,好在wandb等訓(xùn)練可視化的軟件中接著之前的訓(xùn)練過(guò)程開(kāi)始訓(xùn)練。
接下來(lái)我以自己出現(xiàn)的斷點(diǎn)續(xù)訓(xùn)情況進(jìn)行描述和解決步驟的說(shuō)明。
【出現(xiàn)模型訓(xùn)練中斷的環(huán)境情況說(shuō)明】: 自己的電腦通過(guò)pycharm連接上學(xué)校的服務(wù)器,由于服務(wù)器需要通過(guò)內(nèi)網(wǎng)(即校園網(wǎng))進(jìn)行登錄連接,而校園網(wǎng)由于各種不穩(wěn)定情況或者晚上十二點(diǎn)偶爾就會(huì)關(guān)閉或者斷開(kāi)
(學(xué)校傻缺,人為的制造bug)等原因斷開(kāi)連接,導(dǎo)致服務(wù)器(XShell軟件通過(guò)ssh連接服務(wù)器)斷聯(lián),從而pycharm連接的服務(wù)器解釋器出現(xiàn)斷開(kāi)連接,訓(xùn)練過(guò)程中斷。
【注】: YOLOv5,YOLOv7代碼十分相似(你懂的),所以操作互通。
斷點(diǎn)續(xù)訓(xùn)
1. 更改train.py文件的參數(shù)
將下圖中的 –resume 參數(shù)的 default=False 設(shè)置為 True。這一步是將解釋器中的斷點(diǎn)續(xù)訓(xùn)設(shè)置為True(即進(jìn)行斷點(diǎn)續(xù)訓(xùn)),如果是從頭開(kāi)始訓(xùn)練就不需要更改這個(gè)參數(shù)值。
2. 清理數(shù)據(jù)集中的datasets.cache緩存
以 YOLOv7 訓(xùn)練為例,我用的訓(xùn)練集是VOC0712。在之前的訓(xùn)練中會(huì)出現(xiàn)datasets.cache緩存,如果不清理的話,YOLOv7斷點(diǎn)續(xù)訓(xùn)會(huì)失?。╕OLOv7在每次訓(xùn)練開(kāi)始的時(shí)候都要清除上一次訓(xùn)練的數(shù)據(jù)集緩存,不然都會(huì)出現(xiàn)訓(xùn)練失敗的情況)。清理完緩存,在斷點(diǎn)續(xù)訓(xùn)開(kāi)始的時(shí)候,會(huì)重新生成數(shù)據(jù)集索引。
(YOLOv5沒(méi)試過(guò),不知道會(huì)不會(huì)出現(xiàn)這種情況,如果不會(huì)的話這一步跳過(guò))
3. 斷點(diǎn)續(xù)訓(xùn)
在Terminal中輸入訓(xùn)練指令即可重新開(kāi)始訓(xùn)練,如下圖所示。
需要注意的是斷點(diǎn)續(xù)訓(xùn)需要調(diào)用之前斷開(kāi)的訓(xùn)練時(shí)的 last.pt 權(quán)重文件,即將斷訓(xùn)前最后一次epochs的 pt權(quán)重文件(last.pt) 作為預(yù)訓(xùn)練權(quán)重輸入到接下來(lái)要訓(xùn)練的網(wǎng)絡(luò)中,剩下而指令還用你自己的模型之前訓(xùn)練的指令就行。這里我為了方便,已經(jīng)將一些指令提前寫(xiě)入到文件當(dāng)中,所以傳入指令的時(shí)候大部分指令都已經(jīng)省略。
【注】: 這里強(qiáng)調(diào)一下,我這里的指令是我自己訓(xùn)練時(shí)候單機(jī)多卡的指令,在這里只是給出一個(gè)參照。
你自己斷點(diǎn)續(xù)訓(xùn)的時(shí)候,輸入的指令(一臺(tái)機(jī)器一張GPU)應(yīng)該是 <你自己之前訓(xùn)練時(shí)的指令 + (–weights …指令)>
其中的 -m torch.distributed.launch --nproc_per_node 2 、–device 0,1 這兩個(gè)指令是用來(lái) 單機(jī)多卡 訓(xùn)練的,一張GPU的機(jī)器不需要這兩個(gè)指令。 對(duì)照從零開(kāi)始的Usage 和 斷點(diǎn)續(xù)訓(xùn)的 Usage,可以看出我就在斷點(diǎn)續(xù)訓(xùn)的指令中比初始訓(xùn)練指令多添加了一個(gè)權(quán)重的指令。
總結(jié):簡(jiǎn)單方法 – (直接指令操作)
- 第一步:把你之前訓(xùn)練終止的文件夾名稱改成exp(或者exp最高)。具體原因不清楚,反正不改成exp會(huì)報(bào)錯(cuò)。
- 第二步:在原來(lái)訓(xùn)練指令的基礎(chǔ)上添加斷點(diǎn)續(xù)訓(xùn)指令。
斷點(diǎn)續(xù)訓(xùn)指令: 原來(lái)的指令 --resume --weights 斷點(diǎn)續(xù)訓(xùn)權(quán)重地址
【例如】:
- 原先的訓(xùn)練指令: python -m torch.distributed.launch --nproc_per_node=2 train.py --device 0,1 --adam --batch-size 4 --workers 2 --name yolov7
- 斷點(diǎn)續(xù)訓(xùn)指令: python -m torch.distributed.launch --nproc_per_node=2 train.py --device 0,1 --adam --batch-size 4 --workers 2 --name yolov7 --resume --weights ./runs/train/exp/weights/last.pt
- Terminal中的輸出信息
1. 輸入訓(xùn)練指令
2. 斷點(diǎn)續(xù)訓(xùn)開(kāi)始
3. wandb情況
4. 斷點(diǎn)續(xù)訓(xùn)情況
這里可以看出,斷點(diǎn)續(xù)訓(xùn)開(kāi)始之前網(wǎng)絡(luò)會(huì)重新cache一下train、val。epochs會(huì)沿著之前訓(xùn)練中斷的地方重新開(kāi)始訓(xùn)練。
注意細(xì)節(jié)
1. exp問(wèn)題
盡量保證斷點(diǎn)續(xù)訓(xùn)的 exp 是最last的,否則會(huì)出現(xiàn)一些莫名其妙的東西。也就是說(shuō)斷點(diǎn)續(xù)訓(xùn)的exp(如果runs/train中有多個(gè)exp,例如exp1、exp2、exp3等等)要保證是最后一個(gè)生成的,如果不是的話最好吧需要續(xù)訓(xùn)的exp之后的exp轉(zhuǎn)移到其他地方或者刪除(比如需要續(xù)訓(xùn)exp2,就要移除掉項(xiàng)目中exp2之后的exp3、expn等等后面所有其他訓(xùn)練結(jié)果。exp1需不需要移除我沒(méi)試過(guò),有興趣的朋友可以試一下)。
2. 訓(xùn)練過(guò)程可視化軟件問(wèn)題
我用的是 wandb 可視化軟件,斷點(diǎn)續(xù)訓(xùn)的話不會(huì)產(chǎn)生與續(xù)訓(xùn)前結(jié)果重疊問(wèn)題。但是群里有朋友反映他斷點(diǎn)續(xù)訓(xùn) Tensorboard 可視化會(huì)出現(xiàn)重疊混亂等問(wèn)題。
這里不太清楚是不是可視化軟件的問(wèn)題,有興趣的朋友可以測(cè)試一下。具體情況如下圖所示。
- Tensorboard斷點(diǎn)續(xù)訓(xùn)
如上圖所示,在40個(gè)epochs的時(shí)候多次使用斷點(diǎn)續(xù)訓(xùn),Tensorboard出現(xiàn)可視化混亂的情況。
原因可能是中斷之后又重新運(yùn)行,tensorboard沒(méi)有清理文件,導(dǎo)致多個(gè)日志混雜在一起。
- wandb斷點(diǎn)續(xù)訓(xùn)
從上圖可以看出,wandb在176個(gè)epochs的時(shí)候出現(xiàn)斷點(diǎn),接下來(lái)斷點(diǎn)續(xù)訓(xùn)177個(gè)epochs連接上了之前的訓(xùn)練結(jié)果。從 System欄 中可以看出,在16h之后曲線有一個(gè)突然下降,這時(shí)候就是模型訓(xùn)練斷開(kāi),GPU Memory釋放,GPU Temp溫度下降;之后斷點(diǎn)續(xù)訓(xùn)開(kāi)始,曲線接著之前的訓(xùn)練結(jié)果繼續(xù)開(kāi)始運(yùn)行。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-449965.html
【附】:YOLOv7中 train.py訓(xùn)練參數(shù)設(shè)置信息
這里附上 YOLOv7 中 train.py 中的訓(xùn)練參數(shù)信息,可以作為對(duì)照。防止出現(xiàn)看完文章操作流程后,對(duì)訓(xùn)練參數(shù)指令傳入部分如何寫(xiě)還是模糊的情況發(fā)生。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-449965.html
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--weights', type=str, default='', help='initial weights path')
parser.add_argument('--cfg', type=str, default='cfg/training/yolov7.yaml', help='model.yaml path')
parser.add_argument('--data', type=str, default='data/VOC.yaml', help='data.yaml path')
parser.add_argument('--hyp', type=str, default='data/hyp.scratch.p5.yaml', help='hyperparameters path')
parser.add_argument('--epochs', type=int, default=300)
parser.add_argument('--batch-size', type=int, default=32, help='total batch size for all GPUs')
parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes')
# 去除resize后因補(bǔ)灰產(chǎn)生的冗余信息,使補(bǔ)灰邊縮減到圖片下采樣32倍的最小倍數(shù)(即在長(zhǎng)邊resize成640后,盡量減少補(bǔ)灰邊的長(zhǎng)度,同時(shí)還能整除32)
parser.add_argument('--rect', action='store_true', help='rectangular training')
# 斷點(diǎn)續(xù)訓(xùn)
parser.add_argument('--resume', nargs='?', const=True, default=True, help='resume most recent training')
parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
parser.add_argument('--notest', action='store_true', help='only test final epoch')
parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check')
parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters')
parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
parser.add_argument('--cache-images', action='store_true', help='cache images for faster training')
parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%')
parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer')
parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')
parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers')
parser.add_argument('--project', default='runs/train', help='save to project/name')
parser.add_argument('--entity', default=None, help='W&B entity')
parser.add_argument('--name', default='exp', help='save to project/name')
parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
parser.add_argument('--quad', action='store_true', help='quad dataloader')
parser.add_argument('--linear-lr', action='store_true', help='linear LR')
parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')
parser.add_argument('--upload_dataset', action='store_true', help='Upload dataset as W&B artifact table')
parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval for W&B')
parser.add_argument('--save_period', type=int, default=-1, help='Log model after every "save_period" epoch')
parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used')
parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone of yolov7=50, first3=0 1 2')
parser.add_argument('--v5-metric', action='store_true', help='assume maximum recall as 1.0 in AP calculation')
opt = parser.parse_args()
到了這里,關(guān)于【DL系列】YOLOv5、YOLOv7斷點(diǎn)續(xù)訓(xùn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!