在计算机视觉目标检测领域,YOLO 系列凭借单阶段、端到端、实时性强的优势,长期占据工业落地与学术研究的核心地位。继 YOLOv3 之后,YOLOv4横空出世,它并非由原作者 Joseph Redmon 开发,而是 AlexeyAB 团队汇集当时深度学习领域最成熟、最有效的优化策略,打造出的速度与精度极致平衡的里程碑式模型。

相比于追求极简工程化的 YOLOv5,YOLOv4 更偏向学术实现,它不执着于颠覆性理论创新,而是将各类 “涨点技巧” 科学组合,让模型在保持实时推理速度的同时,实现精度大幅跃升。本文完全基于课堂 PPT 内容,从基础定位、核心策略、网络结构、损失函数、后处理优化到应用价值,全方位深度拆解,带你彻底吃透 YOLOv4。


一、YOLOv4:实时目标检测的 “全能劳模”

1. 核心定位与设计理念

YOLOv4 的核心口号是Optimal Speed and Accuracy of Object Detection(最优速度与精度),它完美继承了 YOLO 系列 “You Only Look Once” 的核心思想 —— 将目标检测转化为回归问题,输入图像仅需一次前向传播,直接输出目标的类别与位置信息,无需复杂的候选框生成步骤。

PPT 中明确区分了 YOLOv4 与后续版本的差异:

  • YOLOv4:偏学术实现,集主流算法优点于一身,追求精度与性能的极致平衡;
  • YOLOv5:偏工程使用,代码简洁、易部署、轻量化适配性强,实际开发优先选择。

可以说,YOLOv4 是 YOLOv3 的全面进化版,也是实时目标检测领域的 “技巧集大成者”,它用成熟的技术组合,实现了 “速度不打折、精度大幅升” 的效果,被业内称为 CV 界的 “劳模算法”。

2. 核心优势

  • 兼顾速度与精度,实时检测场景下表现顶尖;
  • 融合当时最优的网络结构、数据增强、损失函数策略;
  • 泛化能力极强,适配小目标、密集目标、复杂场景检测;
  • 无需复杂改造,即可直接用于工业检测、自动驾驶、安防监控等场景。

二、YOLOv4 两大核心优化策略:免费涨点 + 小成本大涨点

YOLOv4 的核心创新,在于将各类优化方法归纳为两大策略集合,不增加推理负担或仅小幅增加计算量,就能实现精度显著提升,这也是它能快速成为主流模型的关键。

1. Bag of Freebies(BOF):免费涨点神器

Bag of Freebies 简称 BOF,核心特点是仅增加训练成本,完全不影响推理速度,相当于 “免费提升精度”,主要包含以下优化:

  • 数据增强:调整图像亮度、对比度、色调,随机缩放、剪切、翻转、旋转,丰富数据分布,提升模型鲁棒性;
  • 正则化方法:采用 Dropout、DropBlock 等方式,抑制模型过拟合,提高泛化能力;
  • 类别不平衡处理:针对数据集中样本数量差异大的问题,优化训练权重分配;
  • 损失函数优化:升级边界框回归损失,让模型定位更精准。

2. Bag of Specials(BOS):小成本大涨点策略

Bag of Specials 简称 BOS,仅小幅增加计算量,就能让模型精度暴涨,主要包含:

  • 感受野增强:采用 SPP、ASPP 等结构,扩大模型感受野,提取更丰富的全局特征;
  • 注意力机制:引入 CBAM、SAM 注意力模块,让模型聚焦目标区域,忽略背景干扰;
  • 特征融合:结合 FPN、PAN 结构,实现多尺度特征高效融合;
  • 激活函数升级:使用 Mish 激活函数,替代传统 ReLU,提升特征表达能力。

三、YOLOv4 数据增强:从基础到进阶的全面升级

数据增强是提升模型泛化能力的核心手段,YOLOv4 在这一环节做到了极致,PPT 中重点讲解了 6 种核心增强策略:

1. Mosaic 数据增强(核心创新)

Mosaic 是 YOLOv4 最具代表性的增强方法,参考 CutMix 思想,将 4 张不同的图像随机缩放、裁剪、拼接成 1 张训练图像

  • 优势:丰富图像背景与目标尺度,让模型在小数据集上也能训练出强泛化能力;
  • 效果:减少对大批次(batch-size)训练的依赖,大幅提升小目标、密集目标检测效果。

2. Random Erase 随机擦除

随机用图像均值或随机像素值,覆盖图像的部分区域,强制模型学习关键特征,避免过度依赖局部像素信息。

3. Hide and Seek 隐藏搜索

按照预设概率,随机隐藏图像的多个补丁区域,模拟目标被遮挡的场景,提升模型在遮挡环境下的检测能力。

4. SAT 自对抗训练

通过对抗生成的方式,向图像中添加微小噪声,增加模型训练难度,让模型学会抵抗干扰,显著提升鲁棒性。

5. DropBlock 正则化

这是针对 CNN 网络优化的正则化方法,区别于传统 Dropout 随机丢弃神经元,DropBlock 丢弃连续的特征区域,能更有效移除图像中的语义信息,彻底解决过拟合问题。

6. Label Smoothing 标签平滑

防止模型对预测结果 “过度自信” 导致过拟合,将传统硬标签[0,1]转换为软标签,例如[0.05, 0.95],让模型学习更平滑的分布,提升泛化能力。


四、YOLOv4 损失函数进化:从 IoU 到 CIoU 的完美升级

边界框回归损失是目标检测的核心,YOLOv4 沿着IoU→GIoU→DIoU→CIoU的路线,一步步解决传统损失函数的缺陷,最终采用CIoU Loss作为标准框损失,这也是面试与考试的高频考点。

1. IoU Loss(交并比损失)

最基础的框损失,计算预测框与真实框的交集和并集比值。

  • 缺陷:无重叠时 IoU=0,无法计算梯度;相同 IoU 无法区分框的位置差异。

2. GIoU Loss(广义交并比损失)

引入能同时包裹预测框与真实框的最小外接矩形 C,解决无重叠时无法优化的问题。

  • 缺陷:仍无法区分框的中心点距离与长宽比差异。

3. DIoU Loss(距离交并比损失)

在 GIoU 基础上,直接优化预测框与真实框的中心点欧式距离,收敛速度更快,定位精度更高。

  • 缺陷:未考虑框的长宽比一致性。

4. CIoU Loss(完整交并比损失,YOLOv4 最终选用)

同时兼顾三大几何关键因素:重叠面积、中心点距离、边界框长宽比一致性,是目前最稳定、最精准的框回归损失。

  • 优势:收敛快、定位准、适配各种尺度目标,完美解决传统损失的所有缺陷。

五、后处理优化:DIoU‑NMS 与 Soft‑NMS

模型推理后会生成大量冗余检测框,需要非极大值抑制(NMS)筛选最优框,传统 NMS 存在重叠目标漏检的问题,YOLOv4 对此进行双重优化:

1. DIoU‑NMS

在传统 NMS 基础上,不仅计算 IoU,还加入框中心点距离,避免因目标重叠导致的漏检,尤其适合行人、车辆等密集目标检测。

2. Soft‑NMS

摒弃传统 NMS “直接删除低置信度框” 的粗暴方式,通过高斯函数衰减重叠框的置信度,保留重叠目标的有效检测,进一步提升召回率。


六、YOLOv4 网络结构:全模块深度优化

YOLOv4 采用输入端 + 主干网络 + 颈部网络 + 检测头 + 后处理的经典架构,每个模块都经过针对性优化,完全贴合 PPT 核心内容:

1. 主干网络:CSPDarknet53

基于 Darknet53 改进,加入CSP(跨阶段局部)结构

  • 将特征图按通道拆分为两部分,一部分走残差网络,另一部分直接拼接输出;
  • 优势:增强特征学习能力、降低内存消耗、减少计算瓶颈,兼顾精度与速度。

2. 颈部网络:SPP + 改进版 PANet

颈部网络负责多尺度特征融合,是检测不同大小目标的关键:

  • SPP 空间金字塔池化:多尺度池化结构,无需固定输入尺寸,扩大感受野,提取全局特征;
  • PANet 路径聚合网络:结合 FPN “自顶向下” 传递语义特征、PAN “自底向上” 传递定位特征的优势,将传统加法改为拼接(concat),保留更完整的特征信息。

3. 注意力机制:SAM 空间注意力

融合 CBAM 通道注意力与空间注意力的优势,YOLOv4 重点使用SAM 空间注意力模块,让模型自动聚焦目标区域,忽略无效背景,提升检测精度。

4. 激活函数:Mish

替代传统 ReLU 激活函数,公式为:f(x) = x * tanh( ln(1 + e^x) )

  • 优势:函数更平滑,信息保留更完整,小幅提升精度与泛化能力,计算成本可控。

5. Eliminate grid sensitivity 网格敏感消除

解决目标中心位于网格边界时,预测困难的问题:

  • 对坐标回归值乘以大于 1 的系数,让预测框更容易到达网格边缘;
  • 显著提升小目标、边缘目标的定位精度。

七、YOLOv4 完整架构总结

YOLOv4 的整体架构可以概括为:输入端(Mosaic+SAT + 标签平滑)→ 主干网络(CSPDarknet53)→ 颈部网络(SPP+PAN)→ 检测头(YOLO Head)→ 损失函数(CIoU)→ 后处理(DIoU‑NMS)

这套组合让 YOLOv4 在保持高 FPS(实时推理)的同时,mAP 指标远超 YOLOv3,成为实时目标检测的标杆模型。


八、YOLOv4 优缺点全面分析

优点

  1. 速度精度双优:实时检测场景中,精度与速度达到行业顶尖水平;
  2. 技术集大成:融合当时所有成熟有效的优化策略,无需额外创新即可落地;
  3. 泛化性极强:适配小目标、密集目标、遮挡场景、复杂环境检测;
  4. 实用性拉满:无需复杂改造,可直接用于工业、安防、自动驾驶等领域。

缺点

  1. 结构复杂,训练调参难度较高;
  2. 基于 Darknet 框架开发,工程部署难度高于 YOLOv5;
  3. 对硬件算力有一定要求,低配设备训练较慢。

九、YOLOv4 与 YOLOv5 的核心关系(PPT 原文)

很多人会混淆 YOLOv4 与 YOLOv5,二者并非迭代替代关系,而是定位不同、互补共存

  • YOLOv4:学术导向,堆精度、堆创新,适合研究与复杂场景;
  • YOLOv5:工程导向,代码简洁、易部署、轻量化齐全,适合实际开发。

技术层面,YOLOv5 大量继承 YOLOv4 的核心设计(Mosaic、CSP、SPP、CIoU 等),可以说YOLOv5 是 YOLOv4 的工程化简化版,而 YOLOv4 是 YOLOv5 的技术理论基础。


十、实战代码:YOLO 系列通用 detect.py 完整实现(附注释)

下面给出 YOLO 系列最经典、最常用的检测推理代码 detect.py,支持图片 / 视频 / 摄像头实时检测,可直接用于 YOLOv4、YOLOv5 项目。

python

运行

import argparse
import time
import os
import shutil
import platform
import random
import torch
import torch.backends.cudnn as cudnn
import cv2
from pathlib import Path
from models.experimental import *
from utils.datasets import *
from utils.utils import *

def detect(save_img=False):
    out, source, weights, view_img, save_txt, imgsz = \
        opt.output, opt.source, opt.weights, opt.view_img, opt.save_txt, opt.img_size
    webcam = source == '0' or source.startswith('rtsp') or source.startswith('http') or source.endswith('.txt')

    # 初始化设备
    device = torch_utils.select_device(opt.device)
    if os.path.exists(out):
        shutil.rmtree(out)
    os.makedirs(out)
    half = device.type != 'cpu'

    # 加载模型
    model = attempt_load(weights, map_location=device)
    imgsz = check_img_size(imgsz, s=model.stride.max())
    if half:
        model.half()

    # 分类器(可选)
    classify = False
    if classify:
        modelc = torch_utils.load_classifier(name='resnet101', n=2)
        modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=device)['model'])
        modelc.to(device).eval()

    # 数据加载
    vid_path, vid_writer = None, None
    if webcam:
        view_img = True
        cudnn.benchmark = True
        dataset = LoadStreams(source, img_size=imgsz)
    else:
        save_img = True
        dataset = LoadImages(source, img_size=imgsz)

    # 类别与颜色
    names = model.module.names if hasattr(model, 'module') else model.names
    colors = [[random.randint(0, 255) for _ in range(3)] for _ in names]

    # 预热模型
    t0 = time.time()
    img = torch.zeros((1, 3, imgsz, imgsz), device=device)
    _ = model(img.half() if half else img) if device.type != 'cpu' else None

    # 开始推理
    for path, img, im0s, vid_cap in dataset:
        img = torch.from_numpy(img).to(device)
        img = img.half() if half else img.float()
        img /= 255.0
        if img.ndimension() == 3:
            img = img.unsqueeze(0)

        # 前向推理
        t1 = torch_utils.time_synchronized()
        pred = model(img, augment=opt.augment)[0]

        # NMS 非极大值抑制
        pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms)
        t2 = torch_utils.time_synchronized()

        # 分类器(可选)
        if classify:
            pred = apply_classifier(pred, modelc, img, im0s)

        # 处理检测结果
        for i, det in enumerate(pred):
            if webcam:
                p, s, im0 = path[i], '%g: ' % i, im0s[i].copy()
            else:
                p, s, im0 = path, '', im0s

            save_path = str(Path(out) / Path(p).name)
            txt_path = str(Path(out) / Path(p).stem)
            s += '%gx%g ' % img.shape[2:]
            gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]

            if det is not None and len(det):
                # 坐标映射回原图
                det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()

                # 打印结果
                for c in det[:, -1].unique():
                    n = (det[:, -1] == c).sum()
                    s += '%g %ss, ' % (n, names[int(c)])

                # 保存标签与画框
                for *xyxy, conf, cls in det:
                    if save_txt:
                        xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()
                        with open(txt_path + '.txt', 'a') as f:
                            f.write(('%g ' * 5 + '\n') % (cls, *xywh))

                    if save_img or view_img:
                        label = '%s %.2f' % (names[int(cls)], conf)
                        plot_one_box(xyxy, im0, label=label, color=colors[int(cls)], line_thickness=3)

            # 输出耗时
            print('%sDone. (%.3fs)' % (s, t2 - t1))

            # 显示结果
            if view_img:
                cv2.imshow(p, im0)
                if cv2.waitKey(1) == ord('q'):
                    raise StopIteration

            # 保存图片/视频
            if save_img:
                if dataset.mode == 'images':
                    cv2.imwrite(save_path, im0)
                else:
                    if vid_path != save_path:
                        vid_path = save_path
                        if isinstance(vid_writer, cv2.VideoWriter):
                            vid_writer.release()
                        fourcc = 'mp4v'
                        fps = vid_cap.get(cv2.CAP_PROP_FPS)
                        w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
                        h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                        vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*fourcc), fps, (w, h))
                    vid_writer.write(im0)

    if save_txt or save_img:
        print('结果已保存到:', os.path.join(os.getcwd(), out))

    print('总耗时:(%.3fs)' % (time.time() - t0))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='模型路径')
    parser.add_argument('--source', type=str, default='inference/images', help='图片/视频/0摄像头')
    parser.add_argument('--output', type=str, default='inference/output', help='输出文件夹')
    parser.add_argument('--img-size', type=int, default=640, help='推理尺寸')
    parser.add_argument('--conf-thres', type=float, default=0.4, help='置信度阈值')
    parser.add_argument('--iou-thres', type=float, default=0.5, help='NMS的IOU阈值')
    parser.add_argument('--device', default='', help='cuda 0 或 cpu')
    parser.add_argument('--view-img', action='store_true', help='显示结果')
    parser.add_argument('--save-txt', action='store_true', help='保存坐标txt')
    opt = parser.parse_args()

    with torch.no_grad():
        detect()

十一、总结

YOLOv4 是目标检测发展史上 **“技术集成” 的巅峰之作 **,它用实践证明:优秀的算法不一定需要颠覆性理论,将成熟、高效的优化方案科学组合,就能打造出工业级顶尖模型。

它兼顾实时速度与高精度,适配绝大多数目标检测场景,既是学术研究的经典模型,也是工业落地的优质选择。对于深度学习学习者而言,吃透 YOLOv4,就能掌握目标检测的核心逻辑,为后续学习 YOLOv7、YOLOv8、YOLOv10 等进阶模型打下坚实基础。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐