
写在前面2015-2018 年是 YOLO 的创世纪。Joseph Redmon 用 3 年时间从一个无名小卒变成目标检测领域的颠覆者。YOLOv1 第一次让检测跑到了 45FPSYOLOv3 把单阶段精度推到了 76% mAP。今天我们一起回顾这 3 年看看单阶段范式是如何诞生的。YOLOv1-v3 就像漫威的复仇者联盟 1-3——奠定了英雄基础但还没到巅峰。Redmon 是 YOLO 的斯坦·李。目录一、YOLO 诞生前的目标检测江湖1.1 2015 年前的两阶段王朝1.2 两阶段检测的速度瓶颈二、YOLOv1第一次让检测实时2.1 YOLOv1 的核心理念2.2 YOLOv1 的网格划分2.3 YOLOv1 架构基于 GoogLeNet2.4 YOLOv1 性能2.5 YOLOv1 的3 大问题2.6 YOLOv1 损失函数三、YOLOv2YOLO9000更强、更快、更包容3.1 YOLOv2 的7 大改进3.2 YOLOv2 架构Darknet-193.3 YOLOv2 性能3.4 YOLOv2 的两大黑科技3.5 K-means 聚类 Anchor 实战3.6 YOLOv2 的细粒度特征——Passthrough 层四、YOLOv3单阶段检测的成熟之作4.1 YOLOv3 的3 大创新4.2 YOLOv3 架构Darknet-534.3 YOLOv3 的3 尺度预测4.4 YOLOv3 性能4.5 YOLOv3 的逻辑回归创新4.6 YOLOv3 的3 尺度完整架构五、3 代的技术师承关系5.1 YOLOv1 → v2 → v3 演进图5.2 关键改进传了多少5.3 数据对比六、Redmon 的急流勇退6.1 2020 年的告别 Twitter6.2 Redmon 退出的原因6.3 接力棒七、避坑指南复现 YOLOv1-v3 的 5 个真实坑坑 1YOLOv1 损失函数权重设置错误坑 2YOLOv2 Anchor 聚类失败坑 3YOLOv3 的 Sigmoid 没生效坑 4多尺度训练时输入尺寸报错坑 5Darknet-53 训练时梯度爆炸一、YOLO 诞生前的目标检测江湖1.1 2015 年前的两阶段王朝graph TB A[2014: R-CNN] -- B[2015: Fast R-CNN] B -- C[2015: Faster R-CNN] C -- D[2016: YOLOv1br/⚡ 颠覆者] D -- E[2017: YOLOv2] E -- F[2018: YOLOv3] style A fill:#95E1D3,color:#000 style B fill:#95E1D3,color:#000 style C fill:#95E1D3,color:#000 style D fill:#FF6B6B,color:#fff style E fill:#FFD93D,color:#000 style F fill:#6BCB77,color:#fff1.2 两阶段检测的速度瓶颈模型年份FPSmAP50速度瓶颈R-CNN20140.0566%2000 个候选框独立 CNNFast R-CNN20150.570%仍是两段式Faster R-CNN2015778%RPN 串行 RoI Pooling效率技巧2015 年前实时检测是奢望——所有模型都跑不到 30FPS。二、YOLOv1第一次让检测实时2.1 YOLOv1 的核心理念graph LR A[传统两阶段] --|先猜后修| B[2000 个候选框] C[YOLOv1 单阶段] --|一次出结果| D[7×7 网格] style A fill:#FF6B6B,color:#fff style C fill:#6BCB77,color:#fff2.2 YOLOv1 的网格划分graph TB A[输入图像 448×448] -- B[划分 7×7 网格] B -- C[共 49 个格子] C -- D[每个格子预测] D -- D1[2 个边界框] D -- D2[20 个类别概率br/VOC 数据集] D -- D3[1 个置信度] D1 -- E[最终: 49×(2×520)1470 维] D2 -- E D3 -- E style A fill:#4ECDC4,color:#fff style E fill:#FF6B6B,color:#fff2.3 YOLOv1 架构基于 GoogLeNetgraph TB A[Input 448×448×3] -- B[Conv 7×7br/64ch, stride 2] B -- C[MaxPool 2×2] C -- D[Conv 3×3br/192ch] D -- E[MaxPool] E -- F[GoogLeNet Inception ×1] F -- G[MaxPool] G -- H[GoogLeNet Inception ×3] H -- I[MaxPool] I -- J[GoogLeNet Inception ×5] J -- K[MaxPool] K -- L[Conv 3×3br/1024ch] L -- M[AvgPool] M -- N[FC 4096] N -- O[FC 1470br/(7×7×30)] style A fill:#4ECDC4,color:#fff style O fill:#FF6B6B,color:#fff2.4 YOLOv1 性能数据集类别数mAPFPS (Titan X)VOC20072063.4%45VOC20122057.9%45YOLOv1 的 45FPS 是个什么概念当时 Faster R-CNN 7FPS——YOLO 快了6.4 倍。这就好比别人都在骑马YOLO 突然开上了汽车。2.5 YOLOv1 的3 大问题graph TD A[YOLOv1 问题] -- B[1. 网格粗糙br/7×7 49 格br/小目标难检测] A -- C[2. 类别互斥br/一个格子只能一类] A -- D[3. 定位不准br/直接回归误差大] style A fill:#FF6B6B,color:#fff style B fill:#FF6B6B,color:#fff style C fill:#FF6B6B,color:#fff style D fill:#FF6B6B,color:#fff2.6 YOLOv1 损失函数# YOLOv1 损失函数多部分组成 import torch import torch.nn as nn class YOLOv1Loss(nn.Module): def __init__(self, S7, B2, lambda_coord5, lambda_noobj0.5): super().__init__() self.S S # 网格数 self.B B # 每格预测框数 self.lambda_coord lambda_coord self.lambda_noobj lambda_noobj def forward(self, predictions, targets): # predictions: [B, S, S, (B*5C)] # targets: [B, S, S, (B*5C)] # 1. 坐标损失仅正样本 coord_loss self.lambda_coord * torch.sum( (predictions[..., 0:2] - targets[..., 0:2])**2 (predictions[..., 2:4] - torch.sqrt(targets[..., 2:4]))**2 ) # 2. 置信度损失 conf_loss_obj torch.sum( (predictions[..., 4] - targets[..., 4])**2 * targets[..., 4] ) conf_loss_noobj self.lambda_noobj * torch.sum( (predictions[..., 4] - targets[..., 4])**2 * (1 - targets[..., 4]) ) # 3. 分类损失 cls_loss torch.sum( (predictions[..., 10:] - targets[..., 10:])**2 * targets[..., 4].unsqueeze(-1) ) return coord_loss conf_loss_obj conf_loss_noobj cls_loss三、YOLOv2YOLO9000更强、更快、更包容3.1 YOLOv2 的7 大改进graph TB A[YOLOv2 改进] -- B1[1. BatchNormbr/mAP 2%] A -- B2[2. Hi-Res Classifierbr/mAP 4%] A -- B3[3. ConvAnchorbr/召回率 7%] A -- B4[4. 维度聚类br/更优 Anchor] A -- B5[5. 细粒度特征br/mAP 1%] A -- B6[6. 多尺度训练br/适应不同输入] A -- B7[7. Darknet-19br/更快骨干] style A fill:#FF6B6B,color:#fff style B1 fill:#4ECDC4,color:#fff style B2 fill:#95E1D3,color:#000 style B3 fill:#FFD93D,color:#000 style B4 fill:#6BCB77,color:#fff style B5 fill:#9D4EDD,color:#fff style B6 fill:#FFA500,color:#000 style B7 fill:#4ECDC4,color:#fff3.2 YOLOv2 架构Darknet-19graph TB A[Input 416×416×3] -- B[Conv 3×3br/32ch] B -- C[MaxPool] C -- D[Conv 3×3br/64ch] D -- E[MaxPool] E -- F[Conv 3×3br/128ch] F -- G[Conv 3×3br/64ch] G -- H[Conv 3×3br/128ch] H -- I[MaxPool] I -- J[×4 Conv blocksbr/256ch] J -- K[×4 Conv blocksbr/512ch] K -- L[×4 Conv blocksbr/1024ch] L -- M[GlobalAvgPool] M -- N[输出] style A fill:#4ECDC4,color:#fff style N fill:#FF6B6B,color:#fff3.3 YOLOv2 性能数据集类别数mAPFPS (Titan X)改进VOC20072076.8%67vs v1: 13.4%VOC20122073.4%67vs v1: 15.5%COCO8021.6%40首个 YOLO 多类别3.4 YOLOv2 的两大黑科技graph TD A[YOLOv2 黑科技] -- B[1. K-means 聚类 Anchorbr/代替手工设计] A -- C[2. 联合训练br/YOLO9000 预测 9000 类] style A fill:#FF6B6B,color:#fff style B fill:#4ECDC4,color:#fff style C fill:#FFD93D,color:#000YOLO9000 是个狂妄的名字——目标是检测 9000 个类别。虽然最终没完全做到但体现了 Redmon 的雄心。3.5 K-means 聚类 Anchor 实战# kmeans_anchors.py import numpy as np from sklearn.cluster import KMeans def kmeans_anchors(boxes, k5): 对 GT 框做 K-means 聚类得到最优 Anchor boxes: [N, 2] (w, h) 归一化的 GT 框 # 1. K-means 聚类用 IoU 作为距离 kmeans KMeans(n_clustersk, random_state0) kmeans.fit(boxes) anchors kmeans.cluster_centers_ # 2. 按面积排序 areas anchors[:, 0] * anchors[:, 1] sorted_indices np.argsort(areas) anchors anchors[sorted_indices] return anchors # 实际使用 # from ultralytics import yolo # model YOLO(yolov8.yaml) # model.kmeans(/path/to/dataset.yaml, k9) # 自动聚类 9 个 Anchor3.6 YOLOv2 的细粒度特征——Passthrough 层graph LR A[26×26×512 浅层] -- B[Passthrough 层br/重组为 13×13×2048] B -- C[Concat] C -- D[13×13×(10242048)] D -- E[输出] style A fill:#4ECDC4,color:#fff style E fill:#FF6B6B,color:#fff关键把浅层 26×26 重组为 13×13×2048与深层 13×13 拼接保留小目标信息。四、YOLOv3单阶段检测的成熟之作4.1 YOLOv3 的3 大创新graph TB A[YOLOv3 创新] -- B1[1. Darknet-53br/更深骨干] A -- B2[2. 多尺度预测br/3 个尺度] A -- B3[3. 逻辑回归br/代替 Softmax] style A fill:#FF6B6B,color:#fff style B1 fill:#4ECDC4,color:#fff style B2 fill:#95E1D3,color:#000 style B3 fill:#FFD93D,color:#0004.2 YOLOv3 架构Darknet-53graph TB A[Input 416×416×3] -- B[Conv 32br/stride 2] B -- C[Residual ×1br/64ch] C -- D[Conv 64br/stride 2] D -- E[Residual ×2br/128ch] E -- F[Conv 128br/stride 2] F -- G[Residual ×8br/256ch] G -- H[Conv 256br/stride 2] H -- I[Residual ×8br/512ch] I -- J[Conv 512br/stride 2] J -- K[Residual ×4br/1024ch] K -- L[AvgPool] L -- M[FC 1000] style A fill:#4ECDC4,color:#fff style M fill:#FF6B6B,color:#fff4.3 YOLOv3 的3 尺度预测graph TB A[Backbone 输出] -- P3[P3: 52×52br/检测小目标] A -- P4[P4: 26×26br/检测中目标] A -- P5[P5: 13×13br/检测大目标] P3 -- O1[输出 1br/85 维/Anchor] P4 -- O2[输出 2br/85 维/Anchor] P5 -- O3[输出 3br/85 维/Anchor] style A fill:#4ECDC4,color:#fff style P3 fill:#6BCB77,color:#fff style P4 fill:#FFD93D,color:#000 style P5 fill:#FF6B6B,color:#fff4.4 YOLOv3 性能数据集mAP50mAP50:95FPS (Titan X)COCO82.3%31.0%65VOC200789%-65效率技巧YOLOv3 让 YOLO 第一次突破 80% mAP——这是单阶段范式的里程碑。4.5 YOLOv3 的逻辑回归创新# YOLOv3 不再用 Softmax 做多分类 # 改用每个类别独立用逻辑回归二分类 import torch import torch.nn as nn class YOLOv3Head(nn.Module): YOLOv3 风格的检测头每类别独立 sigmoid def __init__(self, num_classes80, num_anchors3): super().__init__() self.nc num_classes self.na num_anchors # 每锚点输出: 5 (xywhconf) nc (类别概率) self.no 5 num_classes def forward(self, x): # x: [B, na*(5nc), H, W] B, _, H, W x.shape # 重塑: [B, na, H, W, 5nc] x x.view(B, self.na, self.no, H, W).permute(0, 1, 3, 4, 2).contiguous() # 关键分类用 sigmoid 而非 softmax x[..., 5:] x[..., 5:].sigmoid() return x为什么改用 SigmoidSoftmax 强制类别互斥一个物体只能是一类Sigmoid 允许多标签分类如既是猫又是动物YOLOv3 的逻辑回归就像学生选课——Softmax 时代只能选一门Sigmoid 时代可以多选。这就是 YOLOv3 灵活的关键。4.6 YOLOv3 的3 尺度完整架构graph TB A[Input 416×416] -- B[Darknet-53] B -- R1[Route 82 层] B -- R2[Route 94 层] B -- R3[Route 106 层] R3 -- DBL1[DBL ×5] DBL1 -- UPS1[上采样] UPS1 -- CAT1[ R2] CAT1 -- DBL2[DBL ×5] DBL2 -- UPS2[上采样] UPS2 -- CAT2[ R1] CAT2 -- DBL3[DBL ×5] DBL3 -- Y1[Y1: 13×13br/大目标] DBL2 -- DBL4[DBL ×5] DBL4 -- Y2[Y2: 26×26br/中目标] DBL1 -- DBL5[DBL ×5] DBL5 -- Y3[Y3: 52×52br/小目标] style A fill:#4ECDC4,color:#fff style Y1 fill:#FF6B6B,color:#fff style Y2 fill:#FFD93D,color:#000 style Y3 fill:#6BCB77,color:#fff五、3 代的技术师承关系5.1 YOLOv1 → v2 → v3 演进图graph LR A[YOLOv1br/2016] --| 7 改进| B[YOLOv2br/2017] B --| 3 创新| C[YOLOv3br/2018] A -- A1[45 FPSbr/63.4% mAP] B -- B1[67 FPSbr/76.8% mAP] C -- C1[65 FPSbr/82.3% mAP] style A fill:#FF6B6B,color:#fff style B fill:#FFD93D,color:#000 style C fill:#6BCB77,color:#fff5.2 关键改进传了多少改进项YOLOv1YOLOv2YOLOv3骨干GoogLeNetDarknet-19Darknet-53Anchor无K-means 聚类9 个固定多尺度无1 尺度3 尺度分类SoftmaxSoftmaxSigmoid残差无无有5.3 数据对比graph TB A[mAP 提升] -- B[v1: 63.4%] A -- C[v2: 76.8% (13.4%)] A -- D[v3: 82.3% (5.5%)] style B fill:#95E1D3,color:#000 style C fill:#FFD93D,color:#000 style D fill:#6BCB77,color:#fff效率技巧3 代 YOLO 累计提升 18.9% mAP——这就是技术迭代的力量。六、Redmon 的急流勇退6.1 2020 年的告别 Twittergraph TB A[Joseph Redmon] -- B[2016: YOLOv1 震惊世界] A -- C[2017: YOLOv2 巅峰] A -- D[2018: YOLOv3 经典] A -- E[2020: 宣布退出 CVbr/出于道德顾虑] style A fill:#FF6B6B,color:#fff style B fill:#4ECDC4,color:#fff style C fill:#FFD93D,color:#000 style D fill:#6BCB77,color:#fff style E fill:#9D4EDD,color:#fff6.2 Redmon 退出的原因“我看着 YOLO 被用于军事、隐私侵犯我无法继续。”6.3 接力棒graph LR A[YOLOv3 (Redmon)] -- B[YOLOv4 (Alexey Bochkovskiy)] B -- C[YOLOv5 (Ultralytics)] C -- D[YOLOv6-v10 (多家)] style A fill:#FF6B6B,color:#fff style B fill:#FFD93D,color:#000 style C fill:#6BCB77,color:#fff style D fill:#4ECDC4,color:#fffRedmon 退出后YOLO 像复仇者联盟失去钢铁侠——但其他英雄接过了大旗。YOLOv4-v10 都来了。七、避坑指南复现 YOLOv1-v3 的 5 个真实坑坑 1YOLOv1 损失函数权重设置错误症状训练时 loss 振荡不收敛。原因YOLOv1 损失中λ_coord5, λ_noobj0.5是关键。解法# 严格按论文设置 lambda_coord 5.0 # 坐标损失权重高 lambda_noobj 0.5 # 负样本置信度损失权重低坑 2YOLOv2 Anchor 聚类失败症状聚类出来的 Anchor 形状诡异一个极大一个极小。原因用了欧氏距离而非 IoU 距离。解法# 关键用 1-IoU 作为距离度量 def iou_distance(box, centroids): box: (w, h), centroids: (k, 2) # 计算 1 - IoU iou compute_iou(box, centroids) return 1 - iou坑 3YOLOv3 的 Sigmoid 没生效症状训练时分类概率总和不是 1但应该用 sigmoid。原因代码里写成 softmax 或没激活。解法# 关键分类分支用 sigmoid不用 softmax x[..., 5:] x[..., 5:].sigmoid() # 80 个独立概率 # 而不是 x[..., 5:] F.softmax(x[..., 5:], dim-1)坑 4多尺度训练时输入尺寸报错症状每 10 个 iter 改变输入尺寸但维度不匹配。原因直接修改 input.shape 没用。解法# 多尺度训练的正确姿势 import random def train_iter(): input_size random.choice([320, 352, 384, 416, 448, 480, 512, 544, 576, 608]) dataloader DataLoader(dataset, batch_sizebatch_size, collate_fnlambda x: collate(x, sizeinput_size)) return dataloader坑 5Darknet-53 训练时梯度爆炸症状训练 loss 突然变 NaN。原因53 层网络梯度链长容易爆炸。解法用梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm10.0)减小学习率混合精度训练⚠️避坑警告YOLOv3 至今仍是工业级目标检测的基础款——很多工业项目直接用 YOLOv3。八、总结YOLOv1-v3 的历史地位8.1 核心结论graph TD A[YOLOv1-v3 贡献] -- B[1. 单阶段范式br/45FPS 开启实时] A -- C[2. 端到端训练br/一个 Loss 搞定] A -- D[3. 开源文化br/Darknet 框架] A -- E[4. 工业落地br/无数项目基石] style A fill:#FF6B6B,color:#fff style B fill:#4ECDC4,color:#fff style C fill:#95E1D3,color:#000 style D fill:#FFD93D,color:#000 style E fill:#6BCB77,color:#fff8.2 5 大核心 TakeawayYOLOv1 是破冰者第一次让检测跑到了 45FPS开启实时检测时代YOLOv2 是工程化巅峰7 大改进把 mAP 推到 76.8%引入 K-means 聚类YOLOv3 是经典款Darknet-53 多尺度 Sigmoid至今仍是工业首选Redmon 是急流勇退的孤胆英雄出于道德考虑退出 CV留下一段传奇YOLOv1-v3 是 YOLO 的创世纪后续所有版本都基于这 3 代奠基8.3 一句话总结YOLOv1-v3 是单阶段检测的创世纪——3 年时间45FPS → 65FPS63.4% → 82.3% mAP。Redmon 用 3 篇论文颠覆了目标检测 10 年的格局。致敬这位急流勇退的英雄。 文末三件套【源码获取】关注此公众号后台回复「YOLO07」获取本文全部代码YOLOv1/v2/v3 损失函数 Darknet-19/53 K-means 聚类完整实现。【思考题】Joseph Redmon 在 YOLOv3 之后宣布退出 CV 领域——原因是被用于军事和隐私侵犯。开源技术的伦理边界在哪里开发者是否应该为代码的最终用途负责欢迎在评论区讨论。【系列文章预告】✅ 07 篇YOLOv1-v3 技术演进详解本文⏭️ 08 篇YOLOv4-v5——CSPNet 时代的工程化巅峰⏭️ 09 篇YOLOv6-v7——RepVGG 与 ELAN 的推理加速⏭️ 10 篇YOLOv8-v10——Anchor-Free 与多模态的未来⏭️ 后续 20 篇行业应用、案例、训练部署避坑标签#YOLOv1#YOLOv2#YOLOv3#Redmon#Darknet#单阶段检测#YOLO创世纪