【计算机视觉实战】第10章 | 单阶段目标检测YOLO与SSD:实时检测的极致追求
欢迎来到《计算机视觉实战》系列教程的第十章。在第九章我们学习了Faster R-CNN等两阶段检测器它们精度高但速度慢。本章我们将学习单阶段检测器One-stage Detector特别是YOLO和SSD它们在保持可观精度的同时实现了实时检测。1. 环境声明Python版本Python 3.12PyTorch版本PyTorch 2.2torchvision版本0.17NumPy版本1.262. 单阶段 vs 两阶段检测器2.1 核心思想对比两阶段检测器Faster R-CNN第一阶段RPN生成候选区域提议第二阶段对每个提议进行分类和边界框精调单阶段检测器YOLO/SSD在单次前向传播中直接预测类别和边界框无需区域提议网络和两步处理defcompare_detectors():单阶段 vs 两阶段检测器对比print(性能对比 (COCO mAP 0.5:0.95):)print(*60)print(f{模型:20}{mAP:10}{FPS:10}{特点:30})print(-*60)print(f{Faster R-CNN:20}{42.0:10}{5:10}{最高精度:30})print(f{RetinaNet:20}{40.8:10}{12:10}{Focal Loss:30})print(f{SSD512:20}{38.5:10}{22:10}{多尺度:30})print(f{YOLOv5m:20}{45.0:10}{120:10}{平衡:30})print(f{YOLOv8n:20}{37.4:10}{300:10}{超实时:30})print(*60)print(\n关键洞察:)print(1. 两阶段检测器精度高但速度慢)print(2. 单阶段检测器速度快适合实时应用)print(3. YOLOv5/v8在速度和精度上取得了很好的平衡)print(4. 现代YOLO版本精度已接近Faster R-CNN)compare_detectors()3. YOLO系列详解3.1 YOLOv1开创性的单阶段检测importtorchimporttorch.nnasnnclassYOLOv1(nn.Module):YOLOv1简化版实现def__init__(self,num_classes20,num_grids7,num_bboxes2):super().__init__()self.num_classesnum_classes self.num_gridsnum_grids self.num_bboxesnum_bboxes# 主干网络 (类似GoogLeNet)self.backbonenn.Sequential(nn.Conv2d(3,64,7,stride2,padding3),nn.LeakyReLU(0.1),nn.MaxPool2d(2,2),# 1/2nn.Conv2d(64,192,3,padding1),nn.LeakyReLU(0.1),nn.MaxPool2d(2,2),# 1/4nn.Conv2d(192,128,1),nn.LeakyReLU(0.1),nn.Conv2d(128,256,3,padding1),nn.LeakyReLU(0.1),nn.MaxPool2d(2,2),# 1/8nn.Conv2d(256,256,1),nn.LeakyReLU(0.1),nn.Conv2d(256,512,3,padding1),nn.LeakyReLU(0.1),nn.MaxPool2d(2,2),# 1/16nn.Conv2d(512,256,1),nn.LeakyReLU(0.1),nn.Conv2d(256,512,3,padding1),nn.LeakyReLU(0.1),nn.Conv2d(512,512,1),nn.LeakyReLU(0.1),nn.Conv2d(512,1024,3,padding1),nn.LeakyReLU(0.1),nn.MaxPool2d(2,2),# 1/32nn.Conv2d(1024,512,1),nn.LeakyReLU(0.1),nn.Conv2d(512,1024,3,padding1),nn.LeakyReLU(0.1),nn.Conv2d(1024,1024,3,stride2,padding1),nn.LeakyReLU(0.1),# 1/64nn.Conv2d(1024,1024,3,padding1),nn.LeakyReLU(0.1),nn.Conv2d(1024,1024,3,padding1),nn.LeakyReLU(0.1),)# 检测头# 输出: S x S x (B*5 C)# 每个格子预测B个边界框每个框有5个值(cx, cy, w, h, conf)# 加上C个类别概率self.detectornn.Sequential(nn.Flatten(),nn.Linear(1024*7*7,4096),nn.LeakyReLU(0.1),nn.Linear(4096,num_grids*num_grids*(num_bboxes*5num_classes)),)defforward(self,x):featuresself.backbone(x)outputself.detector(features)# reshape为 (batch, S, S, B*5C)returnoutput.view(-1,self.num_grids,self.num_grids,self.num_bboxes*5self.num_classes)print(YOLOv1的核心创新:)print(*50)print(1. 将图像划分为S×S网格)print(2. 每个格子预测B个边界框和置信度)print(3. 每个框预测4个坐标值(cx,cy,w,h)和置信度)print(4. 加上C个类别概率)print(5. 单次前向传播完成检测速度极快)print(\n但YOLOv1存在:)print(- 对小物体检测效果差)print(- 召回率较低)print(- 定位精度不如两阶段方法)3.2 YOLOv3多尺度预测importtorchimporttorch.nnasnnclassYOLOv3(nn.Module):YOLOv3简化版 - 使用多尺度预测def__init__(self,num_classes80):super().__init__()self.num_classesnum_classes# 主干网络 (Darknet-53风格)self.backboneself._build_backbone()# 多尺度检测头# 大特征图 - 小物体# 中特征图 - 中等物体# 小特征图 - 大物体self.detect_largenn.Conv2d(256,3*(5num_classes),1)self.detect_mediumnn.Conv2d(512,3*(5num_classes),1)self.detect_smallnn.Conv2d(1024,3*(5num_classes),1)defforward(self,x): 返回三个尺度的检测结果 - 大: (batch, 3*(5C), 13, 13) - 中: (batch, 3*(5C), 26, 26) - 小: (batch, 3*(5C), 52, 52) # 简化的前向传播returnNone,None,Noneprint(YOLOv3的改进:)print(*50)print(1. Darknet-53主干网络更强的特征提取)print(2. FPN多尺度特征金字塔)print(3. 3个不同尺度的检测头)print(4. 使用sigmoid代替softmax支持多标签分类)print(5. 13x13, 26x26, 52x52三种特征图)print(\n改进效果:)print(- 小物体检测大幅提升)print(- 中等和大物体保持高性能)print(- 速度仍然很快 (YOLOv3-608: 20 FPS))3.3 YOLOv5/v8现代YOLOimporttorchdefyolov8_architecture():YOLOv8架构特点print(YOLOv8核心设计:)print(*50)print(1. CSPDarknet主干 PANet颈部)print(2. Anchor-free检测头 (YOLOX开创))print(3. Decoupled检测头 (分类和回归分开))print(4. 新的损失函数: Bbox Loss Distribution Focal Loss)print(5. 数据增强: Mosaic, MixUp, CopyPaste)print(\nYOLOv8 YAML配置 (COCO mAP):)configs{n:{mAP50:37.4,mAP50-95:28.0,params:3.2,FPS:300},s:{mAP50:44.9,mAP50-95:33.7,params:11.2,FPS:200},m:{mAP50:51.2,mAP50-95:39.2,params:25.9,FPS:120},l:{mAP50:53.1,mAP50-95:41.8,params:43.7,FPS:90},x:{mAP50:54.8,mAP50-95:43.4,params:68.2,FPS:60},}print(f{模型:8}{mAP50:12}{mAP50-95:15}{参数量(M):15}{FPS:10})print(-*60)forname,cfginconfigs.items():print(fYOLOv8-{name:4}{cfg[mAP50]:12}{cfg[mAP50-95]:15}{cfg[params]:15}{cfg[FPS]:10})yolov8_architecture()4. SSD多尺度单阶段检测classSSD(nn.Module):SSD (Single Shot MultiBox Detector)def__init__(self,num_classes21):super().__init__()# VGG16主干网络self.vggnn.Sequential(nn.Conv2d(3,64,3,padding1),nn.ReLU(),nn.Conv2d(64,64,3,padding1),nn.ReLU(),nn.MaxPool2d(2,2),nn.Conv2d(64,128,3,padding1),nn.ReLU(),nn.Conv2d(128,128,3,padding1),nn.ReLU(),nn.MaxPool2d(2,2),nn.Conv2d(128,256,3,padding1),nn.ReLU(),nn.Conv2d(256,256,3,padding1),nn.ReLU(),nn.Conv2d(256,256,3,padding1),nn.ReLU(),nn.MaxPool2d(2,2),# 38x38nn.Conv2d(256,512,3,padding1),nn.ReLU(),nn.Conv2d(512,512,3,padding1),nn.ReLU(),nn.Conv2d(512,512,3,padding1),nn.ReLU(),nn.MaxPool2d(2,2),# 19x19nn.Conv2d(512,512,3,padding1),nn.ReLU(),nn.Conv2d(512,512,3,padding1),nn.ReLU(),nn.Conv2d(512,512,3,padding1),nn.ReLU(),nn.MaxPool2d(2,2),# 10x10nn.Conv2d(512,1024,3,padding1),nn.ReLU(),nn.Conv2d(1024,1024,1),nn.ReLU(),# 额外卷积层nn.Conv2d(1024,256,1),nn.ReLU(),nn.Conv2d(256,512,3,stride2,padding1),nn.ReLU(),# 5x5)# 多尺度特征图检测# 38x38, 19x19, 10x10, 5x5, 3x3, 1x1self.detection_headsnn.ModuleList([nn.Conv2d(512,4*(num_classes5),3,padding1),# 38x38nn.Conv2d(1024,6*(num_classes5),3,padding1),# 19x19nn.Conv2d(512,6*(num_classes5),3,padding1),# 10x10nn.Conv2d(256,6*(num_classes5),3,padding1),# 5x5nn.Conv2d(256,4*(num_classes5),3,padding1),# 3x3nn.Conv2d(256,4*(num_classes5),1),# 1x1])print(SSD的设计特点:)print(*50)print(1. VGG16主干网络保留额外卷积层)print(2. 6个不同尺度的特征图)print(3. 每个位置使用多个默认框 (default boxes))print(4. 多尺度特征适合检测不同大小的物体)print(5. 比YOLO稍慢但精度更好)5. RetinaNet与Focal Lossdeffocal_loss():Focal Loss解决单阶段检测器正负样本不均衡问题print(样本不均衡问题:)print(*50)print(- 单阶段检测器需要在所有位置预测)print(- 背景区域远多于物体区域 (如1000:1))print(- 大量易分类的背景样本主导梯度)print(- 难分类的物体样本被忽视)print(\nFocal Loss公式:)print(FL(pt) -αt(1-pt)^γ * log(pt))print(- γ (gamma): 聚焦参数越大越关注难样本)print(- α (alpha): 平衡正负样本的权重)print(- pt: 分类概率)print(\n实验结果:)print(- γ0: 标准交叉熵)print(- γ2, α0.25: Focal Loss)print(- 相比标准交叉熵AP提升约3个点)focal_loss()6. 实战使用YOLOv8importtorchdefuse_yolov8():使用YOLOv8进行目标检测# 实际使用ultralytics库# from ultralytics import YOLOprint(YOLOv8使用示例:)print(*50)print( from ultralytics import YOLO # 加载预训练模型 model YOLO(yolov8n.pt) # nano版本 model YOLO(yolov8s.pt) # small版本 model YOLO(yolov8m.pt) # medium版本 # 推理 results model(image.jpg) # 绘制结果 results[0].show() # 获取检测框 boxes results[0].boxes for box in boxes: x1, y1, x2, y2 box.xyxy[0] conf box.conf[0] cls box.cls[0] print(f类别: {int(cls)}, 置信度: {conf:.2f}, 位置: ({x1:.0f}, {y1:.0f}, {x2:.0f}, {y2:.0f})) )use_yolov8()7. 本章小结通过本章学习我们掌握了单阶段 vs 两阶段理解了两类检测器的核心区别YOLO演进从YOLOv1到YOLOv8的发展历程多尺度预测FPN在单阶段检测中的应用Focal Loss解决样本不均衡的创新方法SSD设计多尺度特征图检测策略一句话总结YOLO系列通过不断的工程优化和算法改进在实时检测领域建立了标杆地位YOLOv8更是将精度和速度做到了极致平衡。下一章预告第11章《图像分割语义分割与实例分割》将带你学习U-Net、Mask R-CNN等分割网络。如果本章内容对你有帮助欢迎点赞、收藏和关注。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2473343.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!