去年在参与一个工业质检项目时,我们遇到了一个棘手的问题:需要在传送带上检测直径只有5-8mm的精密零件。当时尝试了多种目标检测方案,最终发现YOLOv8在Visidron这类小目标数据集上的表现最为均衡。不过原始模型在直接应用时,对小目标的召回率仅有63%左右,这促使我们开展了一系列精度优化实践。
小目标检测(Small Object Detection)一直是计算机视觉领域的难点,其核心挑战主要来自三个方面:
Visidron是一个专注于微小无人机检测的数据集,其典型特征包括:
我们使用的子集包含:
plaintext复制训练集:4280张(含15600个标注框)
验证集:1070张
测试集:535张
针对小目标特性,我们采用了分层增强策略:
python复制# Albumentations实现
transform = A.Compose([
A.HorizontalFlip(p=0.5),
A.RandomBrightnessContrast(p=0.3),
A.HueSaturationValue(p=0.3)
])
特别注意:避免同时使用几何变换和色彩变换,这会导致小目标特征过度失真。我们采用概率阈值控制,确保每张图最多应用3种增强。
原始YOLOv8的CSPDarknet53在stride=32的深层会丢失小目标特征。我们做了以下修改:
python复制# 新增的HR分支结构
class HRBranch(nn.Module):
def __init__(self, in_c=256):
super().__init__()
self.conv1 = Conv(in_c, in_c//2, 3)
self.upsample = nn.Upsample(scale_factor=2)
def forward(self, x):
return self.upsample(self.conv1(x))
python复制# 聚类结果对比
原始锚框尺寸 优化后锚框尺寸
(10,13) (6,8)
(16,30) (12,15)
(33,23) (25,20)
采用加权复合损失:
code复制Loss = 1.2*CIoU + 0.8*Focal + 0.5*DFL
其中:
yaml复制lr0: 0.0012 # 初始学习率
lrf: 0.012 # 最终学习率
warmup_epochs: 5
batch: 16 # 使用梯度累积时设为32
imgsz: 1280 # 必须≥原图尺寸
实测发现:当batch<8时小目标检测性能会下降约15%,建议至少保持batch=16。
我们在测试集上对比了不同优化策略的效果:
| 优化方法 | mAP@0.5 | 推理速度(FPS) |
|---|---|---|
| 基线模型 | 0.542 | 142 |
| +数据增强 | 0.613 | 138 |
| +模型结构调整 | 0.657 | 125 |
| +损失函数优化 | 0.681 | 121 |
| 全部优化方案 | 0.723 | 113 |
python复制def letterbox(im, new_shape=(640, 640)):
# YOLOv8官方实现
shape = im.shape[:2] # current shape [height, width]
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]
# 保持长宽比的分割填充
问题1:训练早期出现大量漏检
问题2:验证集指标震荡
问题3:小目标与大目标检测性能冲突
在实际项目中,我们发现当目标尺寸小于10x10像素时,常规检测方法会面临瓶颈。这时可以尝试以下方案:
这种方案虽然会增加计算量,但能将极小目标的检测mAP提升8-12个百分点。