? 先給出參考的GitHub鏈接:https://github.com/eriklindernoren/PyTorch-YOLOv3
? 其實(shí)在readme中已經(jīng)有詳細(xì)的訓(xùn)練自定義數(shù)據(jù)集教程宇姚,我記錄一下自己在配置過(guò)程中遇到的問題闸拿,以供自己復(fù)習(xí)
配置自定義數(shù)據(jù)集詳細(xì)過(guò)程
? 一開始我是計(jì)劃先下載coco數(shù)據(jù)集针肥,跑一下yolov3,但是考慮到數(shù)據(jù)集本身比較大福贞,而且跟我的工作沒有什么直接關(guān)系撩嚼,如果是想跑通程序的話,還不如直接跑自己的數(shù)據(jù)集挖帘,遇到什么問題就直接解決完丽。
? 我當(dāng)前的數(shù)據(jù)集是行駛證和身份證,對(duì)于數(shù)據(jù)集的生成方法我會(huì)在后續(xù)補(bǔ)充拇舀,現(xiàn)在得到的就是可以用來(lái)訓(xùn)練的格式逻族,都放在data/custom
目錄中,結(jié)構(gòu)如下:
? 其中
images
目錄下存放的都是圖片骄崩,這就不多說(shuō)了聘鳞,labels
目錄中存放的是每張圖片對(duì)應(yīng)的標(biāo)簽薄辅,需要注意的是:標(biāo)簽的文件名和圖片的文件名一一對(duì)應(yīng),例如:first_sheet_01_1.txt對(duì)應(yīng)first_sheet_01_1.jpg抠璃。labels
的目錄結(jié)構(gòu)如下:? 那么 first_sheet_01_1.txt 里面是什么呢站楚?每一行代表一個(gè)標(biāo)注框的標(biāo)簽:
類別id + 標(biāo)注框中心x坐標(biāo) + 標(biāo)注框中心y坐標(biāo) + 標(biāo)注框?qū)挾?+ 標(biāo)注框高度
,需要注意的是:1搏嗡、這五個(gè)數(shù)據(jù)以空格間隔窿春;2、后四個(gè)數(shù)據(jù)都在 [0,1] 范圍采盒,整張圖片為1旧乞;3、類別id起始下標(biāo)是0磅氨。如下圖所示(我的數(shù)據(jù)集類別只有一類尺栖,所以第一列都是0):? classes.names
這個(gè)文件中存的是每個(gè)類別的名稱,上文提到了我的數(shù)據(jù)集類別是一烦租,需要注意的是:最后務(wù)必有一行空行延赌,否則在validation的時(shí)候會(huì)報(bào)錯(cuò):IndexError: list index out of range
原因在于: About a line in train.py: ap_table += [[c, class_names[c], "%.5f" % AP[i]]]
(解決該問題的參考鏈接:https://github.com/eriklindernoren/PyTorch-YOLOv3/issues/283),所以內(nèi)容如下:
其實(shí)遇到這個(gè)問題的本質(zhì)是數(shù)組越界左权,那么另一種解決方案就是在取值的時(shí)候取到正確的范圍就行皮胡,參考的解決方法如下:https://github.com/eriklindernoren/PyTorch-YOLOv3/issues/492
? 接下來(lái)就是
train.txt
這個(gè)文件,其實(shí)這個(gè)文件我是在生成圖片的時(shí)候一起生成的赏迟。因?yàn)樾枰?code>train.txt和valid.txt
這兩個(gè)文件,而且里面的格式都是一樣的蠢棱,我就懶得再寫代碼去分割锌杀,其實(shí)這樣不好,能用代碼解決的事情泻仙,就不要手動(dòng)去做糕再,以后我得多加注意了。那么我是怎么做的呢玉转?這兩個(gè)文件存放的都是圖片的相對(duì)路徑突想,我就固定data/custom/images/
,再加上文件名究抓,train.txt
中的內(nèi)容如下(valid.txt
中格式也一樣猾担,只不過(guò)每一行中最后的文件名不一樣):運(yùn)行 train.py 前補(bǔ)充
? 上述步驟完成之后,還得生成yolov3-custom.cfg
文件(這一步我也是之后才發(fā)覺的刺下,論認(rèn)真看readme的重要性绑嘹!)。怎么生成這個(gè)文件呢橘茉?步驟如下:
$ cd config/ # Navigate to config dir
$ bash create_custom_model.sh <num-classes> # Will create custom model 'yolov3-custom.cfg'
其中<num-classes>
是類別數(shù)量工腋,我的數(shù)據(jù)集是一個(gè)類別姨丈,就寫1(不需要輸入'<'和'>')。
報(bào)錯(cuò)(花絮)
? 在運(yùn)行train.py
代碼的時(shí)候遇到一些報(bào)錯(cuò)擅腰,與其稱之為報(bào)錯(cuò)蟋恬,還不如稱之為花絮,為什么呢趁冈?那我就把實(shí)際情況重現(xiàn)一下:
TypeError: Caught TypeError in DataLoader worker process 0.
遇到這個(gè)問題的時(shí)候我就開始找博客筋现,看看有沒有解決方案(“其實(shí)你遇到的情況別人肯定也遇到過(guò)”,我很感謝我的師兄在我遇到問題的時(shí)候熱心地幫我解決箱歧,他跟我說(shuō)的這句話我會(huì)一直記得)矾飞。不出意外地看到了一樣地報(bào)錯(cuò)問題,總共有兩篇博客呀邢,當(dāng)我仔細(xì)看洒沦,這兩位博主也是在運(yùn)行PyTorch-YOLOv3這個(gè)項(xiàng)目,列一下兩篇博客地鏈接:https://blog.csdn.net/weixin_45093926/article/details/103330105
https://blog.csdn.net/qinglingLS/article/details/104411589
看到解決方案后我就立馬按他們的方法去試呀价淌,結(jié)果可想而知申眼,因?yàn)橐呀?jīng)說(shuō)了是花絮,所以我還是沒有解決問題蝉衣。
解決問題的思路
? 那我該怎么解決我的問題呢括尸?上文也提到了,我遇到報(bào)錯(cuò)的第一選擇是去搜博客病毡,沒錯(cuò)濒翻,那么我就借此機(jī)會(huì)整理一下我解決問題的思路:
- 以報(bào)錯(cuò)提示為關(guān)鍵詞去搜博客
- 去GitHub項(xiàng)目的 issues 搜 報(bào)錯(cuò)提示
- Google搜 報(bào)錯(cuò)提示
報(bào)錯(cuò)提示是最根本的原因,但是可能不是最直接的原因啦膜。但是我按以上三個(gè)步驟一步步做下來(lái)還是沒有解決問題(通常以上三個(gè)步驟就可以解決我目前遇到的問題)有送。那怎么辦?因?yàn)楫?dāng)時(shí)已經(jīng)凌晨?jī)牲c(diǎn)多了僧家,雖然很想把這個(gè)問題解決了雀摘,但是身體不允許啊,于是我就關(guān)電腦去睡覺八拱。但是躺在床上的我輾轉(zhuǎn)反側(cè)怎么也睡不著阵赠,我就在回憶我今天用到的Linux命令,打算稍微記一下肌稻,以后用起來(lái)順手一點(diǎn)清蚀。事情的轉(zhuǎn)折點(diǎn)來(lái)了!5破肌轧铁!當(dāng)我回想 cp 命令的時(shí)候(我數(shù)據(jù)集是另一個(gè)項(xiàng)目生成的,數(shù)據(jù)集就是通過(guò) cp 命令復(fù)制到data/custom/images/
目錄)旦棉,我猛地想起齿风,我的labels
目錄中還沒復(fù)制药薯,也就是說(shuō):因?yàn)镻yTorch-YOLOv3項(xiàng)目中沒有自定義數(shù)據(jù)集的標(biāo)簽,所以導(dǎo)致TypeError: Caught TypeError in DataLoader worker process 0.
這不是明擺著的花絮嘛救斑,我當(dāng)時(shí)躺在床上分析了一下之后童本,認(rèn)定出錯(cuò)的原因就在這了,其他環(huán)節(jié)都沒問題脸候。第二天醒來(lái)復(fù)制了標(biāo)簽之后穷娱,果然運(yùn)行成功。
Warning
? 看到控制臺(tái)出現(xiàn)Warning运沦,我有一點(diǎn)點(diǎn)強(qiáng)迫癥泵额,就記錄一下解決方案,Warning如下:
UserWarning: indexing with dtype torch.uint8 is now deprecated, please use a dtype torch.bool instead
? 這已經(jīng)很明顯提示我們了:需要將int8轉(zhuǎn)換為bool携添,我就按上述解決方案的步驟嫁盲,這次我選擇了第二步:去GitHub項(xiàng)目的 issues 搜 報(bào)錯(cuò)提示。很快就找到了解決方法烈掠,鏈接如下:https://github.com/eriklindernoren/PyTorch-YOLOv3/issues/283
在utils/utils.py
的第279行之后插入以下代碼:
obj_mask=obj_mask.bool() # convert int8 to bool
noobj_mask=noobj_mask.bool() #convert int8 to bool
完美運(yùn)行羞秤!
2020-05-26補(bǔ)充
? 每次訓(xùn)練時(shí),每張圖片必須包含所有類別左敌,即classes.names
這個(gè)文件中有幾個(gè)類別瘾蛋,訓(xùn)練集中每張圖片必須包含所有類別,否則會(huì)報(bào)錯(cuò):RuntimeError: CUDA error: device-side assert triggered