前言
在YOLOv5的6.1版本新出了 xView.yaml
数据配置文件,提供了遥感数据集xView的检测方法。此篇就使用YOLOv5来试跑xView数据集,并对一些小样本检测的策略进行消融实验。
xView数据集下载:https://github.com/zstar1003/Dataset
数据预处理
在YOLOv5的 xView.yaml
文件中,提供了xView数据集的预处理方式。
这里单独新建一个脚本文件 xView.py
import json
import os
from pathlib import Path
import numpy as np
import yaml
from PIL import Image
from tqdm import tqdm
from utils.datasets import autosplit
from utils.general import download, xyxy2xywhn
def convert_labels(fname=Path('xView/xView_train.geojson')):
path = fname.parent
with open(fname) as f:
print(f'Loading {fname}...')
data = json.load(f)
labels = Path(path / 'labels' / 'train')
os.system(f'rm -rf {labels}')
labels.mkdir(parents=True, exist_ok=True)
xview_class2index = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, 8, -1, 9, 10, 11,
12, 13, 14, 15, -1, -1, 16, 17, 18, 19, 20, 21, 22, -1, 23, 24, 25, -1, 26, 27, -1, 28, -1,
29, 30, 31, 32, 33, 34, 35, 36, 37, -1, 38, 39, 40, 41, 42, 43, 44, 45, -1, -1, -1, -1, 46,
47, 48, 49, -1, 50, 51, -1, 52, -1, -1, -1, 53, 54, -1, 55, -1, -1, 56, -1, 57, -1, 58, 59]
shapes = {}
for feature in tqdm(data['features'], desc=f'Converting {fname}'):
p = feature['properties']
if p['bounds_imcoords']:
id = p['image_id']
file = path / 'train_images' / id
if file.exists():
try:
box = np.array([int(num) for num in p['bounds_imcoords'].split(",")])
assert box.shape[0] == 4, f'incorrect box shape {box.shape[0]}'
cls = p['type_id']
cls = xview_class2index[int(cls)]
assert 59 >= cls >= 0, f'incorrect class index {cls}'
if id not in shapes:
shapes[id] = Image.open(file).size
box = xyxy2xywhn(box[None].astype(np.float), w=shapes[id][0], h=shapes[id][1], clip=True)
with open((labels / id).with_suffix('.txt'), 'a') as f:
f.write(f"{cls}{' '.join(f'{x:.6f}' for x in box[0])}\n")
except Exception as e:
print(f'WARNING: skipping one label for {file}: {e}')
dir = Path('D:/Dataset/Xview')
convert_labels(Path('D:/Dataset/Xview/xView_train.geojson'))
images = Path(dir / 'images')
images.mkdir(parents=True, exist_ok=True)
Path(dir / 'train_images').rename(dir / 'images' / 'train')
Path(dir / 'val_images').rename(dir / 'images' / 'val')
autosplit(dir / 'images' / 'train')
运行之后,在train文件夹里会新增训练集和验证集的划分文件。
注:xView数据集没有提供测试集,并且其验证集没有标签,因此这里在train中划分出训练集和验证集。
训练配置
训练和之前跑VOC的流程类似,首先需要修改配置文件路径 myxView.yaml
train: D:/Dataset/Xview/images/train/autosplit_train.txt
val: D:/Dataset/Xview/images/train/autosplit_val.txt
nc: 60
names: ['Fixed-wing Aircraft', 'Small Aircraft', 'Cargo Plane', 'Helicopter', 'Passenger Vehicle', 'Small Car', 'Bus',
'Pickup Truck', 'Utility Truck', 'Truck', 'Cargo Truck', 'Truck w/Box', 'Truck Tractor', 'Trailer',
'Truck w/Flatbed', 'Truck w/Liquid', 'Crane Truck', 'Railway Vehicle', 'Passenger Car', 'Cargo Car',
'Flat Car', 'Tank car', 'Locomotive', 'Maritime Vessel', 'Motorboat', 'Sailboat', 'Tugboat', 'Barge',
'Fishing Vessel', 'Ferry', 'Yacht', 'Container Ship', 'Oil Tanker', 'Engineering Vehicle', 'Tower crane',
'Container Crane', 'Reach Stacker', 'Straddle Carrier', 'Mobile Crane', 'Dump Truck', 'Haul Truck',
'Scraper/Tractor', 'Front loader/Bulldozer', 'Excavator', 'Cement Mixer', 'Ground Grader', 'Hut/Tent', 'Shed',
'Building', 'Aircraft Hangar', 'Damaged Building', 'Facility', 'Construction Site', 'Vehicle Lot', 'Helipad',
'Storage Tank', 'Shipping container lot', 'Shipping Container', 'Pylon', 'Tower']
之后在 train.py
中修改对应的 weights
、 cfg
、 data
等参数。
小样本检测策略实验
起初我使用默认的640×640的 img-size
,但是在这种小样本的检测中,效果很糟。
于是我将 img-size
的尺寸改成1280×1280,使用官方提供的 yolov5l6.pt
这个预训练模型训练100个epoch。
测试得到的AP50为0.847%。
下面我输入验证集中的 2618.tif
这张图片来进行检测。
我想到了之前学习过的【目标检测】YOLOv5针对小目标检测的改进模型中的小样本检测策略,正好在此次也加入测试。
detect.py
中的改进代码如下所示:
t1 = time_synchronized()
pred = model(img, augment=opt.augment)[0]
'''
此处进行分块预测改进
'''
mulpicplus = "3"
assert (int(mulpicplus) >= 1)
if mulpicplus == "1":
pred = model(img, augment=opt.augment)[0]
else:
xsz = img.shape[2]
ysz = img.shape[3]
"""
输入图片:1400x788
1400/640 = 2.1875
788/2.1875 = 360.2285..
384(32的整数倍)最接近360.2285..
因此输出:640x384
"""
mulpicplus = int(mulpicplus)
x_smalloccur = int(xsz / mulpicplus * 1.2)
y_smalloccur = int(ysz / mulpicplus * 1.2)
for i in range(mulpicplus):
x_startpoint = int(i * (xsz / mulpicplus))
for j in range(mulpicplus):
y_startpoint = int(j * (ysz / mulpicplus))
x_real = min(x_startpoint + x_smalloccur, xsz)
y_real = min(y_startpoint + y_smalloccur, ysz)
if (x_real - x_startpoint) % 64 != 0:
x_real = x_real - (x_real - x_startpoint) % 64
if (y_real - y_startpoint) % 64 != 0:
y_real = y_real - (y_real - y_startpoint) % 64
dicsrc = img[:, :, x_startpoint:x_real, y_startpoint:y_real]
pred_temp = model(dicsrc, augment=opt.augment)[0]
"""
pred_temp[..., 0] 取最后一维度的第一个,也就是x
pred_temp[..., 1] 取最后一维度的第二个,也就是y
注意这里的y_startpoint和x_startpoint和从原图上看是相反的
"""
pred_temp[..., 0] = pred_temp[..., 0] + y_startpoint
pred_temp[..., 1] = pred_temp[..., 1] + x_startpoint
if i == 0 and j == 0:
pred = pred_temp
else:
pred = torch.cat([pred, pred_temp], dim=1)
pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms)
简单来说,这个优化策略就是对图像进行切块分别预测,为了防止切块时会把目标给切开,每块之间有20%的重合度。最后将所得到的预测框全部进行叠加,统一输入到NMS之中进行过滤。
下面是我的实验结果:
可以看到,这个切片检测策略一定程度上确实能够缓解漏检情况,不过对于这幅图来说提升并不显著。同时,我也使用了更大尺寸的输入图片尺寸,结果却使小样本丢失,而大样本检测效果更好。
下面是可视化的展示结果:图一是原图标签可视化;图二是表中第二行结果;图三是表中最后一行结果。
Original: https://blog.csdn.net/qq1198768105/article/details/126283196
Author: zstar-_
Title: 【目标检测】YOLOv5跑xView数据集/小样本检测策略实验
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/651087/
转载文章受原作者版权保护。转载请注明原作者出处!