Skip to main content

如何针对自定义数据集对 YOLO 进行微调

微调 通过从学习到的权重而非随机初始化开始,使预训练模型能够识别新类别。微调不需要从头开始进行数百个 epoch 的训练,而是利用预训练的 检测文档 特征,并以极短的时间在自定义数据上收敛。

本指南涵盖了针对自定义数据集微调 YOLO26 的全过程,从基础用法到诸如 冻结层两阶段训练.

微调与从头开始训练的对比

预训练模型已经从数百万张图像中学习到了通用的视觉特征——如边缘检测、纹理识别和形状理解。迁移学习 通过微调可以重用这些知识,只教模型新类别的样子,这就是为什么它收敛更快且所需数据更少的原因。从头开始训练会丢弃所有这些知识,强迫模型从像素级的模式开始学习所有内容,这需要消耗更多的资源。

微调从头开始训练
起始权重在 COCO 上预训练 (80 个类别)随机初始化
指令YOLO("yolo26n.pt")YOLO("yolo26n.yaml")
收敛更快 - 主干网络已经过训练更慢 - 所有层从零开始学习
数据需求较低 - 预训练特征弥补了数据的不足较高 - 模型必须仅从数据集中学习所有特征
适用场景具有自然图像的自定义类别与 COCO 有本质区别的领域(医疗、卫星、雷达)
微调不需要额外的代码

当通过 .pt 加载文件时,预训练权重会存储在模型中。在此之后调用 YOLO("yolo26n.pt") 会自动将所有兼容的权重传输到新的模型架构中,重新初始化所有不匹配的层(例如,当类别数量不同时,检测头会重新初始化),并开始训练。无需手动加载权重、处理层或编写自定义的迁移学习代码。.train(data="custom.yaml")不需要手动加载权重、层操作或自定义迁移学习代码。

预训练权重迁移的工作原理

当在具有不同类别数量的数据集上对预训练模型进行微调时(例如,从 COCO 的 80 个类别迁移到 5 个自定义类别),Ultralytics 会执行形状感知权重迁移:

  1. 主干和颈部网络完全迁移 - 这些层提取通用视觉特征,它们的形状与类别数量无关。
  2. 检测头部分重新初始化 - 分类输出层 (cv3, one2one_cv3) 的形状与类别计数(80 vs 5)相关,因此它们无法迁移,会被随机初始化。检测头中的边界框回归层 (cv2, one2one_cv2) 的形状是固定的,与类别数量无关,因此它们可以正常迁移。
  3. 绝大多数权重都会迁移当更改类别数量时。只有检测头中分类特定的层会被重新初始化——主干、颈部和边界框回归分支保持不变。

对于类别数量与预训练模型相同的训练任务(例如,在另一个 80 类数据集上微调 COCO 预训练权重),包括检测头在内的 100% 的权重都会迁移。

基础微调示例

示例
from ultralytics import YOLO

model = YOLO("yolo26n.pt")  # load pretrained model
model.train(data="path/to/data.yaml", epochs=50, imgsz=640)

选择模型大小

较大的模型容量更大,但需要更新的参数也更多,这在训练数据有限时可能会增加过拟合的风险。从较小的模型(YOLO26n 或 YOLO26s)开始,仅在验证指标停滞时扩大模型规模是一种实用的方法。最佳模型大小取决于任务的复杂度、类别数量、数据集的多样性以及可用于部署的硬件。查看完整的 YOLO26 模型页面 以获取可用尺寸和性能基准。

优化器和学习率选择

默认的 optimizer=auto 设置会根据训练迭代总次数选择优化器和学习率:

  • < 10,000 次迭代(小数据集或少量 epoch):使用 AdamW 和较低的自动计算学习率
  • > 10,000 次迭代(大数据集):MuSGD(一种混合 Muon+SGD 优化器),lr=0.01

对于大多数微调任务,默认设置无需手动调整即可良好运行。在以下情况中,考虑显式设置优化器:

  • 训练不稳定(损失波动或发散):尝试 optimizer=AdamW, lr0=0.001 以实现更稳定的收敛
  • 在小数据集上微调大模型:更低的学习率(如 lr0=0.001)有助于保留预训练特征
自动优化器会覆盖手动设置的 lr0

optimizer=autolr0momentum 值会被忽略。如需手动控制学习率,请显式设置优化器:optimizer=SGD, lr0=0.005.

冻结层

冻结可防止特定层在训练期间更新。当数据集相对于模型容量较小时,这可以加速训练并减少 过拟合

freeze 参数接受整数或列表。整数 freeze=10 会冻结前 10 层(0 到 9,对应 YOLO26 中的主干)。列表可以包含层索引,如 freeze=[0, 3, 5] 用于部分冻结主干,或者包含模块名称字符串,如 freeze=["23.cv2"] 用于对层内的特定分支进行细粒度控制。

示例
model.train(data="custom.yaml", epochs=50, freeze=10)

正确的冻结深度取决于目标领域与预训练数据的相似度,以及可用训练数据的多少:

场景推荐基本原理
大数据集,领域相似freeze=None (默认)有足够的数据来调整所有层而不产生过拟合
小数据集,领域相似freeze=10保留主干特征,减少可训练参数
极小数据集freeze=23仅训练检测头,将过拟合风险降至最低
领域与 COCO 差异巨大freeze=None主干特征可能无法很好地迁移,需要重新训练

冻结深度也可以视为一个超参数——尝试几个值(0, 5, 10)并比较验证 mAP 是找到特定数据集最佳设置的实用方法。

微调的关键超参数

微调通常比从头开始训练需要更少的超参数调整。最重要的参数是:

  • epochs:微调比从头开始训练收敛得更快。从一个中等数值开始,并使用 patience 在验证指标平稳时提前停止。
  • patience:默认的 100 旨在用于较长的训练运行。将此值降低到 10-20 可避免在已经收敛的运行上浪费时间。
  • warmup_epochs:默认的 warmup(3 个 epoch)会逐渐提高学习率,防止大梯度更新在早期迭代中损坏预训练特征。即使在微调时,也建议保留该默认值。

关于训练参数的完整列表,请参见 训练配置参考.

两阶段微调

两阶段微调将训练分为两个阶段。第一阶段冻结主干网络,只训练颈部和头部,使检测层能够适应新类别,而不干扰预训练特征。第二阶段解冻所有层,并以较低的学习率训练完整模型,以针对目标领域完善主干网络。这种方法在目标领域与 COCO 差异显著时特别有用。

这种方法在目标领域与 COCO 差异显著(医疗图像、航空影像、显微镜图像)时特别有用,此时可能需要调整主干,但一次性训练所有内容会导致不稳定。有关使用基于回调的方法进行自动解冻,请参见 冻结和解冻主干网络.

两阶段微调
from ultralytics import YOLO

# Stage 1: freeze backbone, train head and neck
model = YOLO("yolo26n.pt")
model.train(data="custom.yaml", epochs=20, freeze=10, name="stage1", exist_ok=True)

# Stage 2: unfreeze all, fine-tune with lower lr
model = YOLO("runs/detect/stage1/weights/best.pt")
model.train(data="custom.yaml", epochs=30, lr0=0.001, name="stage2", exist_ok=True)

常见缺陷

模型没有任何预测输出

  • 训练数据不足:使用极少样本进行训练是最常见的原因——模型无法从太少的数据中学习或泛化。在调查其他原因之前,请确保每个类别有足够多样化的示例。
  • 检查数据集路径:YAML 文件中的路径不正确data.yaml 会在静默状态下导致标签数量为零。在训练前运行 yolo detect val model=yolo26n.pt data=your_data.yaml 以确认标签已正确加载。
  • 降低置信度阈值:如果预测结果存在但被过滤掉了,请在推理过程中尝试 conf=0.1
  • 核对类别数量:确保 nc 应该描述参考图像中的对象,而不是你正在进行预测的目标图像:data.yaml 与标签文件中实际的类别数量相符。

验证 mAP 提早进入平台期

  • 增加更多数据:微调非常依赖于额外训练数据的支持,尤其是具有不同角度、光照和背景的多样化样本。
  • 检查类别均衡:样本不足的类别会导致 AP 较低。使用 cls_pw 来应用反向频率类别加权(对于轻度不平衡,从 cls_pw=0.25 开始;对于严重不平衡,增加至 1.0)。
  • 减少数据增强:对于非常小的数据集,过度的增强弊大于利。尝试 mosaic=0.5mosaic=0.0.
  • 提高分辨率:对于包含小目标的数据集,尝试 imgsz=1280 以保留更多细节。

微调后原始类别性能下降

这被称为灾难性遗忘——模型在仅针对新数据进行微调时会丢失先前学到的知识。如果不将原始数据集的图像与新数据一起加入,遗忘现象几乎是不可避免的。为了缓解这一问题:

  • 合并数据集:在微调期间,将原始类别的示例与新类别一并包含。这是防止遗忘唯一可靠的方法。
  • 冻结骨干网络 (backbone) 和颈部网络 (neck):冻结骨干网络和颈部网络,仅训练检测头,这有助于缩短微调周期并使用非常小的学习率。
  • 减少训练轮数 (epochs):模型在仅针对新数据上训练的时间越长,遗忘程度就越高。

FAQ

微调 YOLO 需要多少图像?

没有固定的最小值——结果取决于任务的复杂性、类别数量以及领域与 COCO 的相似度。更多样化的图像(不同的光照、角度、背景)比单纯的图像数量更重要。从你现有的数据开始,如果验证指标不足,再增加规模。

如何针对自定义数据集微调 YOLO26?

加载一个预训练的 .pt 文件并调用 .train() 并传入指向自定义 data.yaml 的路径。Ultralytics 会自动处理 权重迁移、检测头重初始化和优化器选择。请参阅 基础微调 部分获取完整代码示例。

为什么我微调的 YOLO 模型什么都没检测到?

最常见的原因是 data.yaml 中的路径不正确(这会导致静默地产生零标签)、YAML 中的 nc 与实际标签文件不匹配,或者是置信度阈值过高。请参阅 常见缺陷 以获取完整的故障排除清单。

在微调时我应该冻结哪些 YOLO 层?

这取决于数据集的大小和领域相似度。对于与 COCO 领域相似的小型数据集,冻结骨干网络(freeze=10)可以防止过拟合。对于与 COCO 截然不同的领域,不冻结任何层(freeze=None)可以让骨干网络进行适应。请参阅 冻结层 以获取详细建议。

在对新类别微调 YOLO 时,我该如何防止灾难性遗忘?

将原始类别的示例与新类别一起包含在训练数据中。如果无法做到这一点,冻结更多层(freeze=10 或更高)并使用较低的学习率有助于保留预训练知识。请参阅 原始类别性能下降 获取更多详细信息。

评论