如何针对自定义数据集对 YOLO 进行微调
微调 通过从学习到的权重而非随机初始化开始,使预训练模型能够识别新类别。微调不需要从头开始进行数百个 epoch 的训练,而是利用预训练的 检测文档 特征,并以极短的时间在自定义数据上收敛。
本指南涵盖了针对自定义数据集微调 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 vs 5)相关,因此它们无法迁移,会被随机初始化。检测头中的边界框回归层 (cv2,one2one_cv2) 的形状是固定的,与类别数量无关,因此它们可以正常迁移。 - 绝大多数权重都会迁移当更改类别数量时。只有检测头中分类特定的层会被重新初始化——主干、颈部和边界框回归分支保持不变。
对于类别数量与预训练模型相同的训练任务(例如,在另一个 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)有助于保留预训练特征
当 optimizer=auto,lr0 和 momentum 值会被忽略。如需手动控制学习率,请显式设置优化器: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.5或mosaic=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 或更高)并使用较低的学习率有助于保留预训练知识。请参阅 原始类别性能下降 获取更多详细信息。