YOLOv3 训练与推理流程详解-结合真实的数据样例进行模拟

发布于:2025-06-15 ⋅ 阅读:(14) ⋅ 点赞:(0)

✅ YOLOv3 训练与推理流程详解

一、前言

YOLOv3 是目标检测领域的重要模型之一,其核心思想是:

  • 使用多尺度预测提升小目标检测能力;
  • 使用 anchor boxes 提升边界框匹配合理性;
  • 单阶段结构实现高效实时检测;

本文将通过一个实际数据样例,带你一步步走过 YOLOv3 的训练和推理过程。


二、假设的数据集样例

我们构造一个小型的真实数据集样例用于说明训练与推理流程:

📦 数据集描述:

  • 图像尺寸:416 × 416
  • 类别数量:2 类(person, car
  • Anchor Boxes 数量:9 个(每层 3 个)
  • 标注格式:PASCAL VOC XML(归一化坐标)

🧾 示例图像标注(ground truth):

<object>
    <name>person</name>
    <bndbox>
        <xmin>100</xmin>
        <ymin>150</ymin>
        <xmax>200</xmax>
        <ymax>300</ymax>
    </bndbox>
</object>

<object>
    <name>car</name>
    <bndbox>
        <xmin>250</xmin>
        <ymin>100</ymin>
        <xmax>350</xmax>
        <ymax>200</ymax>
    </bndbox>
</object>

三、YOLOv3 的训练流程详解

✅ 来源依据:


⚙️ Step 1: 数据预处理

🔁 输入图像处理:
  • 调整为固定大小:416 × 416;
  • 归一化像素值到 [0, 1] 区间;
🧮 边界框处理:
  • (xmin, ymin, xmax, ymax) 转换为 (x_center, y_center, width, height),并归一化到 [0, 1];
  • 示例转换结果:
    image_size = 416
    person_bbox = [150 / 416, 225 / 416, 100 / 416, 150 / 416]  # x_center, y_center, w, h
    car_bbox = [300 / 416, 150 / 416, 100 / 416, 100 / 416]
    

⚙️ Step 2: Anchor Box 分配(正样本划分)

🧠 原理回顾:

YOLOv3 使用 K-Means 对 COCO 数据集中的真实框聚类得到的 9 个 anchors,按层级分配如下:

层级 Anchors
大目标(13×13) [116×90, 156×198, 373×326]
中目标(26×26) [30×61, 62×45, 59×119]
小目标(52×52) [10×13, 16×30, 33×23]
🧪 示例 anchor 匹配逻辑:

对每个 ground truth 框,计算其与所有 anchor 的 IoU,并选择 IoU 最大的那个作为正样本。

from yolov3.utils import compute_iou, match_anchor_to_gt

anchors = [(10, 13), (16, 30), (33, 23),
          (30, 61), (62, 45), (59, 119),
          (116, 90), (156, 198), (373, 326)]

gt_boxes = [[0.36, 0.54, 0.24, 0.36],  # person
            [0.72, 0.36, 0.24, 0.24]]  # car

positive_anchors = match_anchor_to_gt(gt_boxes, anchors)

输出示例(简化表示):

[
    {"anchor_idx": 0, "layer": 2, "grid_cell": (26, 26)},  # person → 小目标层 anchor 0
    {"anchor_idx": 4, "layer": 1, "grid_cell": (18, 9)}   # car → 中目标层 anchor 4
]

⚙️ Step 3: 构建训练标签(Label Assignment)

YOLOv3 的输出是一个三维张量:

[batch_size, H, W, (B × (5 + C))]

其中:

  • H × W:特征图大小(如 13×13)
  • B = 3:每个位置预测的 bounding box 数量
  • 5 + C:每个 bounding box 的参数(tx, ty, tw, th, confidence, class_probs)
🧪 示例标签构建:

对于 person 和 car 各一个目标,生成三个层级的 label:

label_13x13 = np.zeros((13, 13, 3, 5 + 2))
label_26x26 = np.zeros((26, 26, 3, 5 + 2))
label_52x52 = np.zeros((52, 52, 3, 5 + 2))

# 在 person 对应的 grid cell 和 anchor 上填充真实值
label_52x52[26, 26, 0, :4] = [0.36, 0.54, 0.24, 0.36]  # tx, ty, tw, th
label_52x52[26, 26, 0, 4] = 1.0  # confidence
label_52x52[26, 26, 0, 5] = 1.0  # person 类别置信度

# 在 car 对应的 grid cell 和 anchor 上填充真实值
label_26x26[18, 9, 1, :4] = [0.72, 0.36, 0.24, 0.24]
label_26x26[18, 9, 1, 4] = 1.0
label_26x26[18, 9, 1, 6] = 1.0  # car 类别置信度

⚙️ Step 4: 损失函数计算

YOLOv3 的损失函数由三部分组成:

1. 定位损失(Localization Loss)

仅对正样本计算:

L l o c = λ c o o r d ∑ ( tx , ty , tw , th ) 2 \mathcal{L}_{loc} = \lambda_{coord} \sum (\text{tx}, \text{ty}, \text{tw}, \text{th})^2 Lloc=λcoord(tx,ty,tw,th)2

2. 置信度损失(Confidence Loss)

对正样本和负样本分别计算:

L c o n f = ∑ p o s ( confidence − 1 ) 2 + λ n o o b j ∑ n e g ( confidence ) 2 \mathcal{L}_{conf} = \sum_{pos} (\text{confidence} - 1)^2 + \lambda_{noobj} \sum_{neg} (\text{confidence})^2 Lconf=pos(confidence1)2+λnoobjneg(confidence)2

3. 分类损失(Class Probability Loss)

仅对正样本计算交叉熵或 BCELoss:

L c l s = ∑ c = 1 C ( p c − p ^ c ) 2 \mathcal{L}_{cls} = \sum_{c=1}^{C} (p_c - \hat{p}_c)^2 Lcls=c=1C(pcp^c)2


四、YOLOv3 的推理流程详解

⚙️ Step 1: 图像输入与预处理

image = cv2.imread("test.jpg")
resized_image = cv2.resize(image, (416, 416)) / 255.0  # 归一化
input_tensor = np.expand_dims(resized_image, axis=0)     # 添加 batch 维度

⚙️ Step 2: 推理输出(来自 Darknet 或 PyTorch 模型)

模型输出三个层级的预测结果:

output_13x13 = model.predict(input_tensor)[0]  # shape: (13, 13, 255)
output_26x26 = model.predict(input_tensor)[1]  # shape: (26, 26, 255)
output_52x52 = model.predict(input_tensor)[2]  # shape: (52, 52, 255)

每个 bounding box 的输出格式为:

(tx, ty, tw, th, confidence, class_0, class_1)

⚙️ Step 3: 解码 bounding box

使用以下公式将网络输出解码为图像空间中的绝对坐标:

b x = σ ( t x ) + c x b y = σ ( t y ) + c y b w = p w ⋅ e t w b h = p h ⋅ e t h b_x = \sigma(t_x) + c_x \\ b_y = \sigma(t_y) + c_y \\ b_w = p_w \cdot e^{t_w} \\ b_h = p_h \cdot e^{t_h} bx=σ(tx)+cxby=σ(ty)+cybw=pwetwbh=pheth

其中:

  • ( c x , c y ) (c_x, c_y) (cx,cy):当前 grid cell 左上角坐标(归一化后)
  • ( p w , p h ) (p_w, p_h) (pw,ph):对应 anchor 的宽高(归一化后)
🧪 示例解码(伪代码):
def decode_box(output_tensor, anchors):
    num_anchors = len(anchors)
    bboxes = []
    for i in range(output_tensor.shape[0]):
        for j in range(output_tensor.shape[1]):
            for k in range(num_anchors):
                tx, ty, tw, th = output_tensor[i, j, k*85:(k+1)*85][:4]
                conf = output_tensor[i, j, k*85+4]
                class_probs = output_tensor[i, j, k*85+5:k*85+7]

                # 解码
                bx = sigmoid(tx) + j * stride_x
                by = sigmoid(ty) + i * stride_y
                bw = anchors[k][0] * exp(tw)
                bh = anchors[k][1] * exp(th)

                # 归一化坐标转为图像空间坐标
                x1 = (bx - bw/2) * image_size
                y1 = (by - bh/2) * image_size
                x2 = (bx + bw/2) * image_size
                y2 = (by + bh/2) * image_size

                bboxes.append([x1, y1, x2, y2, conf, class_probs])
    return bboxes

⚙️ Step 4: 执行 NMS(Non-Maximum Suppression)

🧮 计算综合得分:

score = confidence × max ⁡ ( class_probs ) \text{score} = \text{confidence} \times \max(\text{class\_probs}) score=confidence×max(class_probs)

🧪 示例执行 NMS(PyTorch):
import torch
from torchvision.ops import nms

# 假设 boxes 是 [N, 4],scores 是 [N]
keep_indices = nms(boxes, scores, iou_threshold=0.45)

final_boxes = boxes[keep_indices]
final_scores = scores[keep_indices]
final_labels = labels[keep_indices]

五、YOLOv3 的完整训练与推理流程总结

阶段 内容
✅ 输入图像 416 × 416 × 3 RGB 图像
✅ 数据增强 随机缩放、翻转、HSV扰动等
✅ 正样本划分 anchor 与 GT IoU 最大者为正样本
✅ 输出结构 三层输出:13×13、26×26、52×52
✅ 损失函数 BCE Loss + IoU Loss(可选 GIoU/DIoU)
✅ NMS 默认使用 greedynms,阈值 0.45
✅ 推理输出 每个 bounding box 包含 (x1, y1, x2, y2, score, label)

六、YOLOv3 的关键配置文件片段(来自 .cfg 文件)

[yolo]
mask = 0,1,2
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=2
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
scale_x_y = 1.05
iou_thresh=0.213
iou_normalizer=0.07

✅ 这些配置项在 AlexeyAB/darknet 中真实存在,影响 anchor 匹配、loss 计算、NMS 等流程。


七、YOLOv3 的性能表现(来源:官方测试数据)

模型 mAP@COCO FPS(V100) 是否支持改进 IoU
YOLOv3 ~33.0 ~45 支持(需手动配置)
YOLOv3-tiny ~25.4 ~150 不推荐用于复杂任务
YOLOv3 + DIoU ~33.6 ~45 ✅ 支持
YOLOv3 + CIoU ~33.9 ~45 ✅ 支持

八、YOLOv3 的局限性(来自社区反馈)

局限性 说明
❌ 不支持 Soft-NMS 需要自定义修改
❌ 不支持 Efficient NMS 如 ONNXRuntime 的优化版本
❌ anchor 设置固定 新任务需重新聚类适配
❌ 输出结构固定 不适合直接部署到 ONNX

九、结语

YOLOv3 的训练与推理流程清晰、稳定,且已在工业界广泛使用多年。它的设计虽然简洁,但非常实用:

  • Anchor Boxes 提升了召回率
  • 多尺度预测增强了小物体检测能力
  • IoU 支持多种变体(GIoU/DIoU/CIoU)
  • NMS 支持多种策略(greedy / soft)

📌 欢迎点赞 + 收藏 + 关注我,我会持续更新更多关于目标检测、YOLO系列、深度学习等内容!


网站公告

今日签到

点亮在社区的每一天
去签到