從0梳理1場CV缺陷檢測賽事!
一、布匹缺陷檢測比賽分析
1. 賽題背景
去年的廣東工業(yè)大賽已入選到全球人工智能技術大賽熱身賽,大賽聚焦布匹疵點智能檢測,要求選手研究開發(fā)高效可靠的計算機視覺算法,提升布匹疵點檢驗的準確度,降低對大量人工的依賴,提升布樣疵點質(zhì)檢的效果和效率。
比賽地址:https://tianchi.aliyun.com/competition/entrance/531864/introduction
2. 比賽要求
要求算法既要檢測布匹是否包含疵點,又要給出疵點具體的位置和類別,既考察疵點檢出能力、也考察疵點定位和分類能力。
3. 評估指標
賽題分數(shù)計算方式:0.2ACC+0.8mAP
ACC:是有瑕疵或無瑕疵的分類指標,考察瑕疵檢出能力。
其中提交結果name字段中出現(xiàn)過的測試圖片均認為有瑕疵,未出現(xiàn)的測試圖片認為是無瑕疵。
mAP:參照PASCALVOC的評估標準計算瑕疵的mAP值。
4. 提交說明
平臺采用了基于GPU計算資源的提交鏡像的方式,將本地代碼打包成鏡像提交,推送至阿里云容器鏡像倉庫后,在天池提交頁面中輸入鏡像地址、用戶名和倉庫密碼。由比賽平臺拉取鏡像運行, 運行結束即可在成績頁面查詢運行日志及評測結果。
二、比賽數(shù)據(jù)分析
1. 數(shù)據(jù)大小
數(shù)據(jù)大小
官方一共提供了9576張圖片用于訓練其中有瑕疵圖片5913張,無瑕疵圖片3663張
瑕疵類別共有34個類別,在最終提交結果上對一些相似類別進行了合并后,共分為15個瑕疵類別。圖片尺寸:4096 * 1696。
2. 比賽難點
種類較多,且數(shù)據(jù)分布不均 缺陷形狀具有極端的長寬比 圖片尺寸較大,部分缺陷尺寸小,小目標問題。
三、快速實現(xiàn)比賽Baseline
完整代碼已開源 或后臺回復 缺陷檢測 下載
開源地址:https://github.com/datawhalechina/team-learning-cv/tree/master/DefectDetection
視頻講解:https://www.bilibili.com/video/BV1dK4y1Q7dc
1. 開源框架選擇
任務分析
此次任務是布匹瑕疵檢測,首先考慮的應該是目標檢測框架。當前目標檢測主要分為one-stage和two-stage兩種類型,以YOLO,SSD等框架為代表的one-stage速度快,以Faster-RCNN為代表的two-stage框架精度高?;诒敬稳蝿諘r間有限制在1小時內(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
訓練設置
$ python train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64
yolov5m 40
yolov5l 24
yolov5x 16
測試設置
$ python detcet.py --source ./inference/images/ --weights yolov5s.pt --conf 0.4
2. 數(shù)據(jù)預處理
數(shù)據(jù)格式轉(zhuǎn)換
代碼詳見convertTrainLabel.py ,部分代碼及分析如下
#讀取比賽數(shù)據(jù)標簽文件
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"]
#獲取標簽對應的類別一共15種
if temp["defect_name"]=="沾污":
defect_name = '0'
elif temp["defect_name"]=="錯花":
defect_name = '1'
.......
#標注格式轉(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ù),并劃分訓練集和驗證集
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ù)寫入 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. 模型訓練
數(shù)據(jù)路徑設置:編輯一個數(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]],
...........
模型訓練
$ python train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64
yolov5m 40
yolov5l 24
yolov5x 16
4. 測試模型并生成結果
將detect.py的輸出結果的格式修改成提交結果的格式
#將輸出結果的格式變成比賽需要提交的格式,并存入list,方便后面寫入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})
#寫入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生成鏡像,并提交鏡像,至此就實現(xiàn)了比賽的Baseline了
四、改進思路
在實現(xiàn)比賽的Baseline后,可以說是完成了第一步,后面如果想要獲取好的成績就需要我們根據(jù)比賽的任務,比賽的難點。進行調(diào)整方案,修改網(wǎng)絡,修改策略。
前面我們提到該布匹缺陷檢測任務的難點主要有:
數(shù)據(jù)種類分布不均勻 缺陷具有極端的長寬比 小目標問題
1. 數(shù)據(jù)種類分布不均勻
解決思路:
過采樣種類較少的樣本 數(shù)據(jù)擴增:在訓練方面,除了常規(guī)的數(shù)據(jù)增強之外,我們觀察到原始的標注存在不準確的情況,為了使網(wǎng)絡適應這種不確定性,我們在訓練時隨機對原始的標注框進行了抖動,是網(wǎng)絡能夠?qū)W習這種不確定性
2. 缺陷具有極端的長寬比
解決思路:
anchor 設置:考慮到樣本的長寬比差異較大,通過聚類分析可以發(fā)現(xiàn),原始的anchor并不能滿足當前任務的需要,通過增加anchor數(shù)目,提高檢測性能。 可變形卷積:增強特征提取能力,提高檢測性能 方法:在 backbone結構的最后一個block采用可變形卷積核 優(yōu)點:可變形卷積能夠計算每個點的偏移,從最合適的地方取特征進行卷積
3. 小目標問題
解決思路:
針對小目標的擴增方式:Copy-Pasted 也就是將小目標貼到圖像中的任意位置并生成新的標注,并且粘貼的小目標可以進行隨機變換(縮放,翻折,旋轉(zhuǎn)等),這種方式通過增加每個圖像中小目標的數(shù)量,匹配的 anchor 的數(shù)量也會隨之增加,這進而提升了小目標在訓練階段對 loss 計算的貢獻。 多尺度訓練:多尺度訓練(Multi Scale Training, MST)通常是指設置幾種不同的圖片輸入尺度,訓練時從多個尺度中隨機選取一種尺度,將輸入圖片縮放到該尺度并送入網(wǎng)絡中 FPN 增加融合因子 Effective Fusion Factor in FPN for Tiny Object Detection
4.漲分Tricks
在實現(xiàn)對網(wǎng)絡的改進后,我們可以使用一些比賽的漲分技巧
半監(jiān)督學習
利用訓練集訓練好的模型預測測試集,將預測結果作為偽標簽加入訓練
測試增強
對檢測圖片進行翻折、旋轉(zhuǎn)、色彩增強,然后分別對這些擴增圖片進行預測,將多個預測結果進行融合
模型集成
多種模型進行預測,將一張圖片的多個結果進行融合
