【數(shù)據(jù)競(jìng)賽】從0梳理1場(chǎng)CV缺陷檢測(cè)賽事!
一、布匹缺陷檢測(cè)比賽分析
1. 賽題背景
去年的廣東工業(yè)大賽已入選到全球人工智能技術(shù)大賽熱身賽,大賽聚焦布匹疵點(diǎn)智能檢測(cè),要求選手研究開(kāi)發(fā)高效可靠的計(jì)算機(jī)視覺(jué)算法,提升布匹疵點(diǎn)檢驗(yàn)的準(zhǔn)確度,降低對(duì)大量人工的依賴(lài),提升布樣疵點(diǎn)質(zhì)檢的效果和效率。
比賽地址:https://tianchi.aliyun.com/competition/entrance/531864/introduction
2. 比賽要求
要求算法既要檢測(cè)布匹是否包含疵點(diǎn),又要給出疵點(diǎn)具體的位置和類(lèi)別,既考察疵點(diǎn)檢出能力、也考察疵點(diǎn)定位和分類(lèi)能力。
3. 評(píng)估指標(biāo)
賽題分?jǐn)?shù)計(jì)算方式:0.2ACC+0.8mAP
ACC:是有瑕疵或無(wú)瑕疵的分類(lèi)指標(biāo),考察瑕疵檢出能力。
其中提交結(jié)果name字段中出現(xiàn)過(guò)的測(cè)試圖片均認(rèn)為有瑕疵,未出現(xiàn)的測(cè)試圖片認(rèn)為是無(wú)瑕疵。
mAP:參照PASCALVOC的評(píng)估標(biāo)準(zhǔn)計(jì)算瑕疵的mAP值。
4. 提交說(shuō)明
平臺(tái)采用了基于GPU計(jì)算資源的提交鏡像的方式,將本地代碼打包成鏡像提交,推送至阿里云容器鏡像倉(cāng)庫(kù)后,在天池提交頁(yè)面中輸入鏡像地址、用戶(hù)名和倉(cāng)庫(kù)密碼。由比賽平臺(tái)拉取鏡像運(yùn)行, 運(yùn)行結(jié)束即可在成績(jī)頁(yè)面查詢(xún)運(yùn)行日志及評(píng)測(cè)結(jié)果。
二、比賽數(shù)據(jù)分析
1. 數(shù)據(jù)大小
數(shù)據(jù)大小
官方一共提供了9576張圖片用于訓(xùn)練其中有瑕疵圖片5913張,無(wú)瑕疵圖片3663張
瑕疵類(lèi)別共有34個(gè)類(lèi)別,在最終提交結(jié)果上對(duì)一些相似類(lèi)別進(jìn)行了合并后,共分為15個(gè)瑕疵類(lèi)別。圖片尺寸:4096 * 1696。
2. 比賽難點(diǎn)
種類(lèi)較多,且數(shù)據(jù)分布不均 缺陷形狀具有極端的長(zhǎng)寬比 圖片尺寸較大,部分缺陷尺寸小,小目標(biāo)問(wèn)題。
三、快速實(shí)現(xiàn)比賽Baseline
完整代碼已開(kāi)源 或后臺(tái)回復(fù) 缺陷檢測(cè) 下載
開(kāi)源地址:https://github.com/datawhalechina/team-learning-cv/tree/master/DefectDetection
視頻講解:https://www.bilibili.com/video/BV1dK4y1Q7dc
1. 開(kāi)源框架選擇
任務(wù)分析
此次任務(wù)是布匹瑕疵檢測(cè),首先考慮的應(yīng)該是目標(biāo)檢測(cè)框架。當(dāng)前目標(biāo)檢測(cè)主要分為one-stage和two-stage兩種類(lèi)型,以YOLO,SSD等框架為代表的one-stage速度快,以Faster-RCNN為代表的two-stage框架精度高?;诒敬稳蝿?wù)時(shí)間有限制在1小時(shí)內(nèi),因此采用單階段YOLOV5的方案
環(huán)境配置
# pip install -U -r requirements.txt
#Output:
Cython
numpy==1.17
opencv-python
torch>=1.4
matplotlib
pillow
tensorboard
PyYAML>=5.3
torchvision
scipy
tqdm
訓(xùn)練設(shè)置
$ python train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64
yolov5m 40
yolov5l 24
yolov5x 16
測(cè)試設(shè)置
$ python detcet.py --source ./inference/images/ --weights yolov5s.pt --conf 0.4
2. 數(shù)據(jù)預(yù)處理
數(shù)據(jù)格式轉(zhuǎn)換
代碼詳見(jiàn)convertTrainLabel.py ,部分代碼及分析如下
#讀取比賽數(shù)據(jù)標(biāo)簽文件
josn_path = "./train_data/guangdong1_round2_train2_20191004_Annotations/Annotations/anno_train.json"
image_path = "./train_data/guangdong1_round2_train2_20191004_images/defect/"
with open(josn_path, 'r') as f:
temps = tqdm(json.loads(f.read()))
for temp in temps:
name = temp["name"].split('.')[0]
path = os.path.join(image_path, name, temp["name"])
im = cv2.imread(path)
sp = im.shape
image_h, image_w = sp[0], sp[1]
x_l, y_l, x_r, y_r = temp["bbox"]
#獲取標(biāo)簽對(duì)應(yīng)的類(lèi)別一共15種
if temp["defect_name"]=="沾污":
defect_name = '0'
elif temp["defect_name"]=="錯(cuò)花":
defect_name = '1'
.......
#標(biāo)注格式轉(zhuǎn)換 江都區(qū)并存入列表
x_center = (x_l + x_r)/(2*image_w)
y_center = (y_l + y_r)/(2*image_h)
w = (x_r - x_l)/(image_w)
h = (y_r - y_l)/(image_h)
name_list.append(temp["name"])
c_list.append(defect_name)
image_h_list.append(image_w)
image_w_list.append(image_h)
x_center_list.append(x_center)
y_center_list.append(y_center)
w_list.append(w)
h_list.append(h)
.....
#讀取列表 list 數(shù)據(jù),并劃分訓(xùn)練集和驗(yàn)證集
index = list(set(name_list))
print(len(index))
for fold in [0]:
val_index = index[len(index) * fold // 5:len(index) * (fold + 1) // 5]
print(len(val_index))
for num, name in enumerate(name_list):
print(c_list[num], x_center_list[num], y_center_list[num], w_list[num], h_list[num])
row = [c_list[num], x_center_list[num], y_center_list[num], w_list[num], h_list[num]]
if name in val_index:
path2save = 'val/'
else:
path2save = 'train/'
#數(shù)據(jù)寫(xiě)入 yolov5文件格式
if not os.path.exists('convertor/fold{}/labels/'.format(fold) + path2save):
os.makedirs('convertor/fold{}/labels/'.format(fold) + path2save)
with open('convertor/fold{}/labels/'.format(fold) + path2save + name.split('.')[0] + ".txt", 'a+') as f:
for data in row:
f.write('{} '.format(data))
f.write('\n')
if not os.path.exists('convertor/fold{}/images/{}'.format(fold, path2save)):
os.makedirs('convertor/fold{}/images/{}'.format(fold, path2save))
sh.copy(os.path.join(image_path, name.split('.')[0], name),
'convertor/fold{}/images/{}/{}'.format(fold, path2save, name))
3. 模型訓(xùn)練
數(shù)據(jù)路徑設(shè)置:編輯一個(gè)數(shù)據(jù)路徑文件夾yaml文件
例如:data/coco128.yaml
# train and val datasets (image directory or *.txt file with image paths)
train: ./process_data/images/train/
val: ./process_data/images/val/
# number of classes
nc: 15
# class names
names: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12','13', '14', '15']
模型文件選擇:yolov5x.yaml, yolov5m.yaml, yolov5l.yaml yolov5s.yaml文件
可以選擇合適的模型文件,從左到右精度下降,但是速率增大
nc: 15 # number of classes
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
anchors:
- [116,90, 156,198, 373,326] # P5/32
- [30,61, 62,45, 59,119] # P4/16
- [10,13, 16,30, 33,23] # P3/8
backbone:
# [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, BottleneckCSP, [128]],
...........
模型訓(xùn)練
$ python train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64
yolov5m 40
yolov5l 24
yolov5x 16
4. 測(cè)試模型并生成結(jié)果
將detect.py的輸出結(jié)果的格式修改成提交結(jié)果的格式
#將輸出結(jié)果的格式變成比賽需要提交的格式,并存入list,方便后面寫(xiě)入result.json文件中
if save_json:
name = os.path.split(txt_path)[-1]
print(name)
x1, y1, x2, y2 = float(xyxy[0]), float(xyxy[1]), float(xyxy[2]), float(xyxy[3])
bbox = [x1, y1, x2, y2]
img_name = name
conf = float(conf)
#add solution remove other
result.append(
{'name': img_name+'.jpg', 'category': int(cls+1), 'bbox': bbox,
'score': conf})
print("result: ", {'name': img_name+'.jpg', 'category': int(cls+1), 'bbox': bbox,'score': conf})
#寫(xiě)入result.json文件中
if save_json:
if not os.path.exists(save_dir):
os.makedirs(save_dir)
with open(os.path.join(save_dir, "result.json"), 'w') as fp:
json.dump(result, fp, indent=4, ensure_ascii=False)
最后就是docker生成鏡像,并提交鏡像,至此就實(shí)現(xiàn)了比賽的Baseline了
四、改進(jìn)思路
在實(shí)現(xiàn)比賽的Baseline后,可以說(shuō)是完成了第一步,后面如果想要獲取好的成績(jī)就需要我們根據(jù)比賽的任務(wù),比賽的難點(diǎn)。進(jìn)行調(diào)整方案,修改網(wǎng)絡(luò),修改策略。
前面我們提到該布匹缺陷檢測(cè)任務(wù)的難點(diǎn)主要有:
數(shù)據(jù)種類(lèi)分布不均勻 缺陷具有極端的長(zhǎng)寬比 小目標(biāo)問(wèn)題
1. 數(shù)據(jù)種類(lèi)分布不均勻
解決思路:
過(guò)采樣種類(lèi)較少的樣本 數(shù)據(jù)擴(kuò)增:在訓(xùn)練方面,除了常規(guī)的數(shù)據(jù)增強(qiáng)之外,我們觀察到原始的標(biāo)注存在不準(zhǔn)確的情況,為了使網(wǎng)絡(luò)適應(yīng)這種不確定性,我們?cè)谟?xùn)練時(shí)隨機(jī)對(duì)原始的標(biāo)注框進(jìn)行了抖動(dòng),是網(wǎng)絡(luò)能夠?qū)W習(xí)這種不確定性
2. 缺陷具有極端的長(zhǎng)寬比
解決思路:
anchor 設(shè)置:考慮到樣本的長(zhǎng)寬比差異較大,通過(guò)聚類(lèi)分析可以發(fā)現(xiàn),原始的anchor并不能滿(mǎn)足當(dāng)前任務(wù)的需要,通過(guò)增加anchor數(shù)目,提高檢測(cè)性能。 可變形卷積:增強(qiáng)特征提取能力,提高檢測(cè)性能 方法:在 backbone結(jié)構(gòu)的最后一個(gè)block采用可變形卷積核 優(yōu)點(diǎn):可變形卷積能夠計(jì)算每個(gè)點(diǎn)的偏移,從最合適的地方取特征進(jìn)行卷積
3. 小目標(biāo)問(wèn)題
解決思路:
針對(duì)小目標(biāo)的擴(kuò)增方式:Copy-Pasted 也就是將小目標(biāo)貼到圖像中的任意位置并生成新的標(biāo)注,并且粘貼的小目標(biāo)可以進(jìn)行隨機(jī)變換(縮放,翻折,旋轉(zhuǎn)等),這種方式通過(guò)增加每個(gè)圖像中小目標(biāo)的數(shù)量,匹配的 anchor 的數(shù)量也會(huì)隨之增加,這進(jìn)而提升了小目標(biāo)在訓(xùn)練階段對(duì) loss 計(jì)算的貢獻(xiàn)。 多尺度訓(xùn)練:多尺度訓(xùn)練(Multi Scale Training, MST)通常是指設(shè)置幾種不同的圖片輸入尺度,訓(xùn)練時(shí)從多個(gè)尺度中隨機(jī)選取一種尺度,將輸入圖片縮放到該尺度并送入網(wǎng)絡(luò)中 FPN 增加融合因子 Effective Fusion Factor in FPN for Tiny Object Detection
4.漲分Tricks
在實(shí)現(xiàn)對(duì)網(wǎng)絡(luò)的改進(jìn)后,我們可以使用一些比賽的漲分技巧
半監(jiān)督學(xué)習(xí)
利用訓(xùn)練集訓(xùn)練好的模型預(yù)測(cè)測(cè)試集,將預(yù)測(cè)結(jié)果作為偽標(biāo)簽加入訓(xùn)練
測(cè)試增強(qiáng)
對(duì)檢測(cè)圖片進(jìn)行翻折、旋轉(zhuǎn)、色彩增強(qiáng),然后分別對(duì)這些擴(kuò)增圖片進(jìn)行預(yù)測(cè),將多個(gè)預(yù)測(cè)結(jié)果進(jìn)行融合
模型集成
多種模型進(jìn)行預(yù)測(cè),將一張圖片的多個(gè)結(jié)果進(jìn)行融合
往期精彩回顧
本站qq群704220115,加入微信群請(qǐng)掃碼:
