如何对自定义数据集微调 YOLO#
微调通过从已学习的权重而不是随机初始化开始,使预训练模型能够识别新类别。微调无需从头训练数百个轮次,而是利用预训练的 COCO 特征,在极短时间内收敛于自定义数据。
本指南涵盖在自定义数据集上微调 YOLO26,从基础用法到诸如层冻结和两阶段训练等高级技术。
微调与从零开始训练的区别#
预训练模型已经从数百万张图像中学习到了通用的视觉特征——边缘检测、纹理识别、形状理解。通过微调进行的迁移学习会复用这些知识,只教会模型新类别是什么样的,这就是它收敛更快且需要较少数据的原因。从头开始训练会丢弃所有这些,并迫使模型从像素级模式开始学习一切,这需要显著更多的资源。
| 微调 | 从零开始训练 | |
|---|---|---|
| 起始权重 | 在 COCO 上预训练(80 个类别) | 随机初始化 |
| 命令 | YOLO("yolo26n.pt") | YOLO("yolo26n.yaml") |
| 收敛 | 更快 - 主干网络已经训练过 | 更慢 - 所有层都从零开始学习 |
| 数据需求 | 更低 - 预训练特征可以弥补数据不足 | 更高 - 模型必须仅从数据集中学习所有特征 |
| 适用场景 | 带有自然图像的自定义类别 | 与 COCO 领域完全不同的场景(医疗、卫星、雷达) |
当加载 .pt 文件并使用 YOLO("yolo26n.pt") 时,预训练权重会存储在模型中。在此之后调用 .train(data="custom.yaml") 会自动将所有兼容的权重传输到新的模型架构,重新初始化任何不匹配的层(例如当类别数量不同时的检测头),并开始训练。无需手动加载权重、操作层或编写自定义迁移学习代码。
预训练权重迁移的工作原理#
当预训练模型在类别数量不同的数据集上进行微调时(例如从 COCO 的 80 个类别到 5 个自定义类别),Ultralytics 会执行形状感知的权重迁移:
- 主干和颈部完全迁移 - 这些层提取通用视觉特征,它们的形状与类别数量无关。
- 检测头部分重新初始化 - 分类输出层(
cv3、one2one_cv3)的形状与类别数量(80 对 5)绑定,因此无法迁移且会随机初始化。检测头中的边界框回归层(cv2、one2one_cv2)无论类别数量如何,其形状都是固定的,因此会正常迁移。 - 当更改类别数量时,绝大多数权重都会迁移。例如,将 YOLO26n 从 COCO(80 个类别)微调到 5 类数据集时,708 个权重张量中有 606 个被迁移:只有与类别计数相关的分类层被重新初始化,而主干、颈部和边界框回归分支保持不变。
对于与预训练模型类别数量相同的数据集(例如,在另一个 80 类数据集上微调 COCO 预训练权重),100% 的权重(包括检测头)都会迁移。
使用名称别名传输类别#
Ultralytics 跨数据集按类名传输匹配的分类头行,忽略大小写和前后空格。当等效类别使用不同名称时,在加载前于内存中重命名源检查点类别。这保留了共享概念的预训练分类权重,否则这些概念将被视为不匹配并随机初始化。
这个 Objects365 v2 转 COCO 的示例重命名了已加载检查点上的源类别,train() 随后将其作为预训练权重传递:
from ultralytics import YOLO
# Source Objects365 v2 name -> target COCO name
ALIASES = {
"wild bird": "bird",
"handbag/satchel": "handbag",
"luggage": "suitcase",
"bowl/basin": "bowl",
"orange/tangerine": "orange",
"monitor/tv": "tv",
"stuffed toy": "teddy bear",
"hair dryer": "hair drier",
}
model = YOLO("path/to/yolo26s-objects365.pt")
model.model.names = {i: ALIASES.get(name, name) for i, name in model.model.names.items()}
model.train(data="coco.yaml", epochs=100, imgsz=640)基本微调示例#
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # load pretrained model
model.train(data="custom.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)有助于保留预训练特征
当 optimizer=auto 时,lr0 和 momentum 值将被忽略。要手动控制学习率,请显式设置优化器:optimizer=SGD, lr0=0.005。
冻结层#
冻结可防止特定层在训练期间更新。当数据集相对于模型容量较小时,这可以加速训练并减少过拟合。
freeze 参数接受整数或列表。整数 freeze=10 冻结前 10 层(索引 0-9),这涵盖了大部分 YOLO26 骨干网。骨干网跨越层 0-10,因此 freeze=10 使最终的 C2PSA 块(层 10)保持可训练状态;使用 freeze=11 冻结整个骨干网。列表可以包含层索引(如 freeze=[0, 3, 5])以实现部分骨干网冻结,或者包含模块名称字符串(如 freeze=["23.cv2", "23.one2one_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:默认预热(3 个轮次)逐渐将学习率从零增加,这可防止大的梯度更新在早期迭代中损坏预训练特征。即使对于微调,也建议保持默认值。
有关训练参数的完整列表,请参阅训练配置参考。
两阶段微调#
两阶段微调将训练分为两个阶段。第一阶段冻结主干并仅训练颈部和头部,使检测层在不干扰预训练特征的情况下适应新类别。第二阶段解冻所有层,并以较低的学习率训练完整模型,以针对目标领域精炼主干。
当目标域与 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)常见问题#
模型不产生任何预测结果#
- 训练数据不足:使用极少量样本进行训练是最常见的原因——模型无法从太少的数据中学习或泛化。在调查其他原因之前,请确保每个类别都有足够且多样的示例。
- 检查数据集路径:
data.yaml中的错误路径会静默产生零标签。在训练前运行yolo detect val model=yolo26n.pt data=custom.yaml以确认标签加载正确。 - 降低置信度阈值:如果预测存在但被过滤掉了,请在推理期间尝试
conf=0.1。 - 验证类别数量:确保
data.yaml中的nc与标签文件中的实际类别数量相匹配。
验证 mAP 过早停滞#
- 添加更多数据:微调极大地受益于额外的训练数据,尤其是具有不同角度、光照和背景的多样化示例。
- 检查类别平衡:代表性不足的类别将具有较低的 AP。使用
cls_pw应用逆频率类别加权(对于中度不平衡,从cls_pw=0.25开始;对于严重不平衡,增加到1.0)。 - 减少数据增强:对于非常小的数据集,过多的增强可能弊大于利。尝试
mosaic=0.5或mosaic=0.0。 - 增加分辨率:对于包含小对象的数据集,请尝试
imgsz=1280以保留细节。
微调后原始类别性能下降#
这被称为灾难性遗忘——模型在仅针对新数据进行微调时丢失了以前学到的知识。如果不将原始数据集图像与新数据一起包含,遗忘在很大程度上是不可避免的。缓解措施:
- 合并数据集:在微调期间,将原始类别的示例与新类别一起包含。这是防止遗忘的唯一可靠方法。
- 冻结主干和颈部:冻结主干和颈部,仅训练检测头,有助于在较低的学习率下进行短期的微调。
- 减少训练 epoch:模型在仅针对新数据上训练的时间越长,遗忘现象就越严重。
常见问题解答#
没有固定的最小值——结果取决于任务的复杂性、类别数量以及领域与 COCO 的相似程度。更多样化的图像(变化的光照、角度、背景)比纯粹的数量更重要。从你现有的数据开始,如果验证指标不足,再增加数据量。
最常见的原因是
data.yaml中的路径不正确(这会静默产生零标签)、YAML 中的nc与实际标签文件不匹配,或者置信度阈值设置得太高。有关完整的故障排除清单,请参阅常见陷阱。这取决于数据集的大小和领域相似性。对于与 COCO 领域相似的小型数据集,冻结骨干网(
freeze=10)可防止过拟合。对于与 COCO 截然不同的领域,让所有层保持未冻结状态(freeze=None)允许骨干网进行调整。有关详细建议,请参阅冻结层。在训练数据中除了包含新类别外,还要包含原始类别的示例。如果无法做到这一点,冻结更多层(
freeze=10或更高)并使用较低的学习率有助于保留预训练知识。有关更多详细信息,请参阅原始类别的性能下降。