3. 深度学习基础回顾
说实话,很多同学一上来就急着调YOLO的代码,结果连卷积怎么算的、锚框干嘛用的都没搞明白。我见过太多人卡在“为什么我的模型检测不到小目标”这种问题上,其实根子就在这几个基础概念没吃透。
这一章,咱们就把YOLO背后的四个核心概念掰开揉碎讲清楚。别怕,我会用我踩过的坑帮你铺路。
3.1 卷积神经网络(CNN)——YOLO的骨架
YOLO本质上就是一个CNN。你想想看,一张图片进来,怎么变成一堆框和类别?靠的就是卷积层一层层地“看”图像。
3.1.1 卷积到底在干什么?
说白了,卷积就是一个滑动窗口。一个小矩阵(卷积核)在图像上滑过,每个位置做一次点乘求和。我刚开始学的时候,总觉得这玩意儿很玄乎,后来自己手写了一次前向传播,才明白它就是在提取特征——边缘、纹理、形状,一层比一层抽象。
举个例子,输入是224×224的图像,用3×3的卷积核,步长1,填充1,输出还是224×224。嗯,这里要注意,填充是为了不让图像越卷越小。
3.1.2 池化层——降维的艺术
池化层就是“浓缩精华”。最大池化取窗口里的最大值,平均池化取平均值。我在做一个小目标检测项目时,发现池化层用太多会把小目标直接“池”没了。后来我改用步长卷积来降采样,效果好了不少。
| 操作 | 作用 | 常见参数 |
|---|---|---|
| 卷积 | 提取特征 | 3×3, 1×1, 5×5 |
| 最大池化 | 保留最强响应 | 2×2, 步长2 |
| 平均池化 | 平滑特征 | 2×2, 步长2 |
3.2 感受野——网络到底看到了多大范围?
感受野这个概念,我当年面试的时候被问过好几次。它指的是特征图上某个点对应到原始图像上的区域大小。你想想看,如果感受野太小,网络只能看到局部,检测大物体就会出问题。
3.2.1 感受野的计算
计算公式其实不复杂:
# 感受野计算示例
def compute_rf(layers):
rf = 1
for k, s in layers:
rf = rf + (k - 1) * s
return rf
# 例子:3层3x3卷积,步长均为1
print(compute_rf([(3,1), (3,1), (3,1)])) # 输出 7
3层3×3卷积堆叠,感受野是7×7。为什么不用一个7×7的卷积?因为三层3×3参数量更少,非线性更强。这是我个人习惯——能用小卷积堆叠就不用大卷积。
3.3 锚框(Anchor Box)——YOLO的“预设答案”
锚框是YOLO里最容易被忽视但又最关键的设计之一。说白了,它就是一组预设的框,网络只需要预测这些框的偏移量,而不是直接预测坐标。
3.3.1 为什么需要锚框?
直接预测坐标太难了。网络要预测(x, y, w, h),这四个值范围太大,不稳定。有了锚框,网络只需要预测“相对于锚框的偏移”,范围小得多,训练也稳定得多。
我记得第一次自己训练YOLOv3时,用了默认的锚框,结果检测自行车总是偏大。后来我重新用K-Means聚类了训练集的标注框,换了锚框,mAP直接涨了3个点。
3.3.2 锚框的生成与匹配
YOLO通常在每个特征图网格上放3个不同尺寸的锚框。训练时,每个标注框会匹配IoU最大的锚框。匹配上了,这个锚框就负责预测这个物体。
| 特征图尺寸 | 锚框尺寸(以YOLOv5为例) | 负责检测 |
|---|---|---|
| 80×80 | (10,13), (16,30), (33,23) | 小目标 |
| 40×40 | (30,61), (62,45), (59,119) | 中目标 |
| 20×20 | (116,90), (156,198), (373,326) | 大目标 |
3.4 非极大值抑制(NMS)——去掉多余的框
模型预测完,同一个物体上可能叠了十几个框。NMS就是把这些框合并成一个。流程很简单:选置信度最高的框,去掉所有和它IoU大于阈值的框,重复直到没有框剩下。
3.4.1 NMS的代码实现
def nms(boxes, scores, iou_threshold=0.5):
# boxes: [[x1,y1,x2,y2], ...]
# scores: [0.9, 0.8, ...]
indices = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)
keep = []
while indices:
i = indices[0]
keep.append(i)
# 计算当前框与其余框的IoU
ious = compute_iou(boxes[i], boxes[indices[1:]])
# 保留IoU小于阈值的框
indices = [indices[j+1] for j, iou in enumerate(ious) if iou < iou_threshold]
return keep
这段代码我手写过不下十次。注意一点:IoU阈值设得太低(比如0.3),会漏掉挨得近的物体;设得太高(比如0.7),又会留下很多重复框。我一般从0.5开始调。
3.4.2 NMS的变种
YOLOv5用了加权NMS,不是简单去掉,而是把重叠框的坐标按置信度加权平均。Soft-NMS则是降低重叠框的置信度而不是直接去掉。这些改进在密集场景下特别有用。
3.5 知识体系总览
下面这张图把四个概念串起来了。CNN提取特征,感受野决定网络能看到多大范围,锚框提供预设的检测模板,NMS负责后处理去重。YOLO就是靠这套组合拳实现端到端检测的。
3.6 本章小结
这四个概念是YOLO的基石。CNN负责提取特征,感受野决定了网络能看到多大的上下文,锚框提供了检测的“先验知识”,NMS负责后处理去重。我建议你把这章的内容吃透再往下走,不然后面调参的时候会一头雾水。