《博主简介》
小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。
✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~
👍感谢小伙伴们点赞、关注!
《------往期经典推荐------》
一、AI应用软件开发实战专栏【链接】
项目名称 | 项目名称 |
---|---|
1.【人脸识别与管理系统开发】 | 2.【车牌识别与自动收费管理系统开发】 |
3.【手势识别系统开发】 | 4.【人脸面部活体检测系统开发】 |
5.【图片风格快速迁移软件开发】 | 6.【人脸表表情识别系统】 |
7.【YOLOv8多目标识别与自动标注软件开发】 | 8.【基于YOLOv8深度学习的行人跌倒检测系统】 |
9.【基于YOLOv8深度学习的PCB板缺陷检测系统】 | 10.【基于YOLOv8深度学习的生活垃圾分类目标检测系统】 |
11.【基于YOLOv8深度学习的安全帽目标检测系统】 | 12.【基于YOLOv8深度学习的120种犬类检测与识别系统】 |
13.【基于YOLOv8深度学习的路面坑洞检测系统】 | 14.【基于YOLOv8深度学习的火焰烟雾检测系统】 |
15.【基于YOLOv8深度学习的钢材表面缺陷检测系统】 | 16.【基于YOLOv8深度学习的舰船目标分类检测系统】 |
17.【基于YOLOv8深度学习的西红柿成熟度检测系统】 | 18.【基于YOLOv8深度学习的血细胞检测与计数系统】 |
19.【基于YOLOv8深度学习的吸烟/抽烟行为检测系统】 | 20.【基于YOLOv8深度学习的水稻害虫检测与识别系统】 |
21.【基于YOLOv8深度学习的高精度车辆行人检测与计数系统】 | 22.【基于YOLOv8深度学习的路面标志线检测与识别系统】 |
23.【基于YOLOv8深度学习的智能小麦害虫检测识别系统】 | 24.【基于YOLOv8深度学习的智能玉米害虫检测识别系统】 |
25.【基于YOLOv8深度学习的200种鸟类智能检测与识别系统】 | 26.【基于YOLOv8深度学习的45种交通标志智能检测与识别系统】 |
27.【基于YOLOv8深度学习的人脸面部表情识别系统】 | 28.【基于YOLOv8深度学习的苹果叶片病害智能诊断系统】 |
29.【基于YOLOv8深度学习的智能肺炎诊断系统】 | 30.【基于YOLOv8深度学习的葡萄簇目标检测系统】 |
31.【基于YOLOv8深度学习的100种中草药智能识别系统】 | 32.【基于YOLOv8深度学习的102种花卉智能识别系统】 |
33.【基于YOLOv8深度学习的100种蝴蝶智能识别系统】 | 34.【基于YOLOv8深度学习的水稻叶片病害智能诊断系统】 |
35.【基于YOLOv8与ByteTrack的车辆行人多目标检测与追踪系统】 | 36.【基于YOLOv8深度学习的智能草莓病害检测与分割系统】 |
37.【基于YOLOv8深度学习的复杂场景下船舶目标检测系统】 | 38.【基于YOLOv8深度学习的农作物幼苗与杂草检测系统】 |
39.【基于YOLOv8深度学习的智能道路裂缝检测与分析系统】 | 40.【基于YOLOv8深度学习的葡萄病害智能诊断与防治系统】 |
41.【基于YOLOv8深度学习的遥感地理空间物体检测系统】 | 42.【基于YOLOv8深度学习的无人机视角地面物体检测系统】 |
43.【基于YOLOv8深度学习的木薯病害智能诊断与防治系统】 | 44.【基于YOLOv8深度学习的野外火焰烟雾检测系统】 |
45.【基于YOLOv8深度学习的脑肿瘤智能检测系统】 | 46.【基于YOLOv8深度学习的玉米叶片病害智能诊断与防治系统】 |
47.【基于YOLOv8深度学习的橙子病害智能诊断与防治系统】 | 48.【基于深度学习的车辆检测追踪与流量计数系统】 |
49.【基于深度学习的行人检测追踪与双向流量计数系统】 | 50.【基于深度学习的反光衣检测与预警系统】 |
51.【基于深度学习的危险区域人员闯入检测与报警系统】 | 52.【基于深度学习的高密度人脸智能检测与统计系统】 |
53.【基于深度学习的CT扫描图像肾结石智能检测系统】 | 54.【基于深度学习的水果智能检测系统】 |
55.【基于深度学习的水果质量好坏智能检测系统】 | 56.【基于深度学习的蔬菜目标检测与识别系统】 |
57.【基于深度学习的非机动车驾驶员头盔检测系统】 | 58.【基于深度学习的太阳能电池板检测与分析系统】 |
59.【基于深度学习的工业螺栓螺母检测】 | 60.【基于深度学习的金属焊缝缺陷检测系统】 |
61.【基于深度学习的链条缺陷检测与识别系统】 | 62.【基于深度学习的交通信号灯检测识别】 |
63.【基于深度学习的草莓成熟度检测与识别系统】 | 64.【基于深度学习的水下海生物检测识别系统】 |
65.【基于深度学习的道路交通事故检测识别系统】 |
二、机器学习实战专栏【链接】,已更新31期,欢迎关注,持续更新中~~
三、深度学习【Pytorch】专栏【链接】
四、【Stable Diffusion绘画系列】专栏【链接】
五、YOLOv8改进专栏【链接】,持续更新中~~
六、YOLO性能对比专栏【链接】,持续更新中~
《------正文------》
目录
- 引言
- 为什么探测小物体很难?
- 目标太小
- 训练数据
- 固定输入尺寸
- SAHI如何工作
- 实际案例
- 使用YOLOv8进行标准推理
- 使用SAHI进行超推理
- 评估SAHI预测结果
- 后续优化
引言
目标检测是计算机视觉的基本任务之一。在高层次上,它涉及预测图像中对象的位置和类别。像You-Only-Look-Once(YOLO)家族中的那些最先进的(SOTA)深度学习模型已经达到了惊人的准确度。然而,目标检测中一个众所周知的挑战性前沿是小目标。
在这篇文章中,你将学习如何使用切片辅助超推理(Slicing Aided Hyper Inference --SAHI)检测数据集中的小对象。主要包括以下内容:
- 为什么很难发现小物体
- SAHI如何工作
- 如何将SAHI应用于数据集
- 如何评价这些预测的性能
为什么探测小物体很难?
目标太小
首先,检测小物体很难,因为小物体很小。物体越小,检测模型必须处理的信息就越少。如果一辆汽车在远处,它可能只占用我们图像中的几个像素。就像人类很难辨认出远处的物体一样,我们的模型很难识别出没有车轮和车牌等视觉可识别特征的汽车!
训练数据
模型的好坏取决于它们所训练的数据。大多数标准对象检测数据集和基准测试都集中在大中型对象上,这意味着大多数现成的对象检测模型并未针对小对象检测进行优化。
固定输入尺寸
对象检测模型通常采用固定大小的输入。例如,YOLOv 8是在最大边长为640像素的图像上训练的。这意味着,当我们向它提供一个大小为1920 x1080的图像时,模型将在进行预测之前将图像降采样到640 x360,降低分辨率并丢弃小对象的重要信息。
SAHI如何工作
切片辅助超推理(Slicing Aided HyperInference)
从理论上讲,你可以在更大的图像上训练模型,以提高对小物体的检测。然而,实际上,这将需要更多的内存,更多的计算能力,以及更劳动密集型的数据集来创建。
另一种方法是利用现有的对象检测,将模型应用于图像中固定大小的补丁或切片,然后将结果拼接在一起
。这就是切片辅助超推理
背后的理念!
SAHI的工作原理是将图像划分为完全覆盖它的切片,并使用指定的检测模型对每个切片进行推理。然后将所有这些切片的预测合并在一起,以生成整个图像的检测列表。SAHI中的“hyper”来自于这样一个事实,即SAHI的输出不是模型推理的结果,而是涉及多个模型推理的计算结果。
💡允许SAHI切片重叠(如上面的GIF所示),这有助于确保至少有一个切片中有足够的物体被检测到。
使用SAHI的主要优点是它与模型无关。SAHI可以利用今天的SOTA对象检测模型和未来的SOTA模型!
当然,天下没有免费的午餐。作为“超推理”的交换,除了将结果拼接在一起所需的处理之外,您还运行了检测模型的多次向前传递。
实际案例
为了说明SAHI如何应用于检测小物体,我们将使用来自中国天津大学机器学习与数据挖掘实验室的AISKYEYE团队的VisDrone检测数据集。该数据集由8629张图像组成,边长从360像素到2000像素不等,使其成为SAHI的理想测试场。Ultralytics的YOLOv8l将作为我们的基本对象检测模型。
我们将使用以下库:
fiftyone
数据集管理和可视化huggingface_hub
用于从Hugging Face Hub加载VisDrone数据集- 使用YOLOv 8运行推理的
ultralytics
,以及 - 用于在图像切片上运行推理
的Sahi
如果您还没有安装这些库的最新版本,请安装。您需要fiftyone>=0.23.8
从Hugging Face Hub加载VisDrone:
pip install -U fiftyone sahi ultralytics huggingface_hub --quiet
现在,在Python进程中,让我们导入FiftyOne模块,我们将使用这些模块来查询和管理数据:
import fiftyone as fo
import fiftyone.zoo as foz
import fiftyone.utils.huggingface as fouh
from fiftyone import ViewField as F
就这样,我们准备好加载数据了!我们将使用FiftyOne的Hugging Face utils中的load_from_hub()
函数通过其repo_id
直接从Hugging Face Hub加载VisDrone数据集的一部分。
为了演示并保持代码执行尽可能快,我们将只从数据集中获取前100张图像。我们还将为我们正在创建的这个新数据集命名为“sahi-test”
:
dataset = fouh.load_from_hub(
"Voxel51/VisDrone2019-DET",
name="sahi-test",
max_samples=100
)
在添加任何预测之前,让我们看看我们在FiftyOne应用程序中的数据集:
session = fo.launch_app(dataset)
使用YOLOv8进行标准推理
在下一节中,我们将使用SAHI对我们的数据进行超推理。在引入SAHI之前,让我们使用Ultralytics的YOLOv8模型的大型变体对我们的数据运行标准对象检测推理。
首先,我们创建一个ultralytics.YOLO
模型实例,必要时下载模型检查点。然后,我们将此模型应用于我们的数据集,并将结果存储在样本的“base_model”
字段中:
python
from ultralytics import YOLO
ckpt_path = "yolov8l.pt"
model = YOLO(ckpt_path)
dataset.apply_model(model, label_field="base_model")
session.view = dataset.view()
我们可以通过查看地面真实标签旁边的模型预测来看到一些东西。首先,我们的YOLOv8l模型检测到的类与VisDrone数据集中的真实类不同。我们的YOLO模型是在COCO数据集上训练的,COCO数据集有80个类,而VisDrone数据集有12个类,包括一个ignore_regions
类。
为了简化比较,我们只关注数据集中最常见的几个类,并将VisDrone类映射到COCO类,如下所示:
mapping = {"pedestrians": "person", "people": "person", "van": "car"}
mapped_view = dataset.map_labels("ground_truth", mapping)
然后过滤我们的标签,只包含我们感兴趣的类:
def get_label_fields(sample_collection):
"""Get the (detection) label fields of a Dataset or DatasetView."""
label_fields = list(
sample_collection.get_field_schema(embedded_doc_type=fo.Detections).keys()
)
return label_fields
def filter_all_labels(sample_collection):
label_fields = get_label_fields(sample_collection)
filtered_view = sample_collection
for lf in label_fields:
filtered_view = filtered_view.filter_labels(
lf, F("label").is_in(["person", "car", "truck"]), only_matches=False
)
return filtered_view
filtered_view = filter_all_labels(mapped_view)
session.view = filtered_view.view()
现在我们已经有了基本模型预测,让我们使用SAHI来切片和切割我们的图像。💪
使用SAHI进行超推理
SAHI技术在我们之前安装的sahi
Python包中实现。SAHI是一个与许多对象检测模型兼容的框架,包括YOLOv 8。我们可以选择我们想要使用的检测模型,并创建sahi.models.DetectionModel子类
的任何类的实例,包括YOLOv8、YOLOv5,甚至拥抱脸变形金刚模型。
我们将使用SAHI的AutoDetectionModel
类创建模型对象,指定模型类型和检查点文件的路径:
from sahi import AutoDetectionModel
from sahi.predict import get_prediction, get_sliced_prediction
detection_model = AutoDetectionModel.from_pretrained(
model_type='yolov8',
model_path=ckpt_path,
confidence_threshold=0.25, ## same as the default value for our base model
image_size=640,
device="cpu", # or 'cuda' if you have access to GPU
)
在我们生成切片预测之前,让我们使用SAHI的get_prediction()
函数检查模型对试验图像的预测:
result = get_prediction(dataset.first().filepath, detection_model)
print(result)
<sahi.prediction.PredictionResult object at 0x2b0e9c250>
幸运的是,SAHI结果对象有一个to_fiftyone_detections()
方法,它将结果转换为FiftyOneDetection
对象的列表:
print(result.to_fiftyone_detections())
[<Detection: {
'id': '661858c20ae3edf77139db7a',
'attributes': {},
'tags': [],
'label': 'car',
'bounding_box': [
0.6646394729614258,
0.7850866247106482,
0.06464214324951172,
0.09088355170355902,
],
'mask': None,
'confidence': 0.8933132290840149,
'index': None,
}>, <Detection: {
'id': '661858c20ae3edf77139db7b',
'attributes': {},
'tags': [],
'label': 'car',
'bounding_box': [
0.6196376800537109,
0.7399617513020833,
0.06670347849527995,
0.09494832356770834,
],
'mask': None,
'confidence': 0.8731599450111389,
'index': None,
}>, <Detection: {
....
....
....
这使我们的数据处理变得简单,因此我们可以专注于数据,而不是格式转换的细节。SAHI的get_sliced_prediction()
函数的工作方式与get_prediction()函数
相同,但有一些额外的超参数让我们配置图像的切片方式。特别是,我们可以指定切片的高度和宽度,以及切片之间的重叠。下面是一个示例:
sliced_result = get_sliced_prediction(
dataset.skip(40).first().filepath,
detection_model,
slice_height = 320,
slice_width = 320,
overlap_height_ratio = 0.2,
overlap_width_ratio = 0.2,
)
作为初步检查,我们可以将切片预测中的检测数量与原始预测中的检测数量进行比较:
num_sliced_dets = len(sliced_result.to_fiftyone_detections())
num_orig_dets = len(result.to_fiftyone_detections())
print(f"Detections predicted without slicing: {num_orig_dets}")
print(f"Detections predicted with slicing: {num_sliced_dets}")
Detections predicted without slicing: 17
Detections predicted with slicing: 73
我们可以看到,预测的数量大幅增加!我们还没有确定额外的预测是否有效,或者我们只是有更多的误报。我们将很快使用FiftyOne的Evaluation API来实现这一点。我们还想为切片找到一组好的超参数。我们需要将SAHI应用于整个数据集来完成所有这些事情。
为了简化这个过程,我们将定义一个函数,它将预测添加到指定标签字段中的样本,然后我们将遍历数据集,将该函数应用于每个样本。该函数将样本的文件路径和切片超参数传递给get_sliced_prediction()
,然后将预测添加到指定标签字段中的样本:
def predict_with_slicing(sample, label_field, **kwargs):
result = get_sliced_prediction(
sample.filepath, detection_model, verbose=0, **kwargs
)
sample[label_field] = fo.Detections(detections=result.to_fiftyone_detections())
我们将切片重叠固定为0.2,并查看切片高度和宽度如何影响预测的质量:
kwargs = {"overlap_height_ratio": 0.2, "overlap_width_ratio": 0.2}
for sample in dataset.iter_samples(progress=True, autosave=True):
predict_with_slicing(sample, label_field="small_slices", slice_height=320, slice_width=320, **kwargs)
predict_with_slicing(sample, label_field="large_slices", slice_height=480, slice_width=480, **kwargs)
请注意,这些推理时间比原始推理时间长得多。这是因为我们在每个图像的多个切片上运行模型,这增加了模型必须进行的向前传递的数量。我们正在做出权衡,以提高对小物体的检测。
现在,让我们再次过滤标签,仅包含我们感兴趣的类,并在FiftyOne应用程序中可视化结果:
filtered_view = filter_all_labels(mapped_view)
session = fo.launch_app(filtered_view, auto=False)
结果看起来很有希望!从一些视觉示例来看,切片似乎可以提高地面实况检测的覆盖率,特别是较小的切片似乎可以捕获更多的人
检测。但我们怎么能确定呢?让我们运行一个评估例程,将检测标记为真阳性、假阳性或假阴性,以将切片预测与地面实况进行比较。我们将使用过滤视图的evaluate_detections()
方法。
评估SAHI预测结果
保持我们对数据集的过滤视图,让我们运行一个评估示例,将来自每个预测标签字段的预测与真实标签进行比较。在这里,我们使用默认的IoU阈值0.5,但您可以根据需要进行调整:
base_results = filtered_view.evaluate_detections("base_model", gt_field="ground_truth", eval_key="eval_base_model")
large_slice_results = filtered_view.evaluate_detections("large_slices", gt_field="ground_truth", eval_key="eval_large_slices")
small_slice_results = filtered_view.evaluate_detections("small_slices", gt_field="ground_truth", eval_key="eval_small_slices")
让我们为每个打印一个报告:
print("Base model results:")
base_results.print_report()
print("-" * 50)
print("Large slice results:")
large_slice_results.print_report()
print("-" * 50)
print("Small slice results:")
small_slice_results.print_report()
Base model results:
precision recall f1-score support
car 0.81 0.55 0.66 692
person 0.94 0.16 0.28 7475
truck 0.66 0.34 0.45 265
micro avg 0.89 0.20 0.33 8432
macro avg 0.80 0.35 0.46 8432
weighted avg 0.92 0.20 0.31 8432
--------------------------------------------------
Large slice results:
precision recall f1-score support
car 0.67 0.71 0.69 692
person 0.89 0.34 0.49 7475
truck 0.55 0.45 0.49 265
micro avg 0.83 0.37 0.51 8432
macro avg 0.70 0.50 0.56 8432
weighted avg 0.86 0.37 0.51 8432
--------------------------------------------------
Small slice results:
precision recall f1-score support
car 0.66 0.75 0.70 692
person 0.84 0.42 0.56 7475
truck 0.49 0.46 0.47 265
micro avg 0.80 0.45 0.57 8432
macro avg 0.67 0.54 0.58 8432
weighted avg 0.82 0.45 0.57 8432
我们可以看到,随着我们引入更多的切片,假阳性的数量增加,而假阴性的数量减少。这是意料之中的,因为模型能够用更多的切片检测更多的对象,但也会犯更多的错误!您可以应用更积极的置信度阈值来对抗这种误报的增加,但即使不这样做,F1分数也会显着提高。
让我们更深入地研究这些结果。我们之前注意到,模型在处理小对象时会遇到困难,所以让我们看看这三种方法在处理小于32 x32像素的对象时的效果如何。我们可以使用FiftyOne的ViewField来执行此过滤:
## Filtering for only small boxes
box_width, box_height = F("bounding_box")[2], F("bounding_box")[3]
rel_bbox_area = box_width * box_height
im_width, im_height = F("$metadata.width"), F("$metadata.height")
abs_area = rel_bbox_area * im_width * im_height
small_boxes_view = filtered_view
for lf in get_label_fields(filtered_view):
small_boxes_view = small_boxes_view.filter_labels(lf, abs_area < 32**2, only_matches=False)
session.view = small_boxes_view.view()
如果我们像以前一样根据这些视图评估我们的模型并打印报告,我们就可以清楚地看到SAHI提供的价值!使用SAHI时,对于小对象的召回率要高得多,而精度没有显著下降,从而提高了F1分数。这对于人员
检测尤其明显,其中F1分数是三倍!
## Evaluating on only small boxes
small_boxes_base_results = small_boxes_view.evaluate_detections("base_model", gt_field="ground_truth", eval_key="eval_small_boxes_base_model")
small_boxes_large_slice_results = small_boxes_view.evaluate_detections("large_slices", gt_field="ground_truth", eval_key="eval_small_boxes_large_slices")
small_boxes_small_slice_results = small_boxes_view.evaluate_detections("small_slices", gt_field="ground_truth", eval_key="eval_small_boxes_small_slices")
## Printing reports
print("Small Box — Base model results:")
small_boxes_base_results.print_report()
print("-" * 50)
print("Small Box — Large slice results:")
small_boxes_large_slice_results.print_report()
print("-" * 50)
print("Small Box — Small slice results:")
small_boxes_small_slice_results.print_report()
Small Box — Base model results:
precision recall f1-score support
car 0.71 0.25 0.37 147
person 0.83 0.08 0.15 5710
truck 0.00 0.00 0.00 28
micro avg 0.82 0.08 0.15 5885
macro avg 0.51 0.11 0.17 5885
weighted avg 0.82 0.08 0.15 5885
--------------------------------------------------
Small Box — Large slice results:
precision recall f1-score support
car 0.46 0.48 0.47 147
person 0.82 0.23 0.35 5710
truck 0.20 0.07 0.11 28
micro avg 0.78 0.23 0.36 5885
macro avg 0.49 0.26 0.31 5885
weighted avg 0.80 0.23 0.36 5885
--------------------------------------------------
Small Box — Small slice results:
precision recall f1-score support
car 0.42 0.53 0.47 147
person 0.79 0.31 0.45 5710
truck 0.21 0.18 0.19 28
micro avg 0.75 0.32 0.45 5885
macro avg 0.47 0.34 0.37 5885
weighted avg 0.77 0.32 0.45 5885
后续优化
在本示例中,我们介绍了如何将SAHI预测添加到数据中,然后严格评估切片对预测质量的影响。我们已经看到了切片辅助超推理(SAHI)如何提高检测的召回率和F1分数,特别是对于小对象,而不需要在较大的图像上训练模型。
为了最大限度地提高SAHI的有效性,您可能需要进行以下试验:
- 切片超参数,如切片高度和宽度以及重叠
- 基本对象检测模型,因为SAHI与许多模型兼容,包括YOLOv 5和拥抱脸变形器模型
- 可能在逐个类别的基础上进行置信度阈值处理,以减少误报的数量
- 后处理技术,如非最大抑制(NMS),以减少重叠检测的数量
无论你想调整什么参数,重要的是要获取更高的性能指标。在执行小物体检测任务时,图像中的小物体越多,丢失“地面实况”标签的可能性就越大。SAHI可以帮助您发现潜在的错误,您可以使用人在回路(HITL)工作流程纠正这些错误。
关注文末名片G-Z-H:【阿旭算法与机器学习】,发送【开源】可获取更多学习资源
好了,这篇文章就介绍到这里,喜欢的小伙伴感谢给点个赞和关注,更多精彩内容持续更新~~
关于本篇文章大家有任何建议或意见,欢迎在评论区留言交流!