YOLOv8/v10/11 模型训练技巧 | 基础篇
作者:CSDN博主 迪菲赫尔曼
引言
大家好,这里为大家准备了一些简单实用的训练小技巧。这些技巧不仅能帮助大家快速上手训练,还能节省不少时间,提高训练效率。无论是刚开始学习计算机视觉还是已经有一些经验,希望这篇指南能帮助你少走弯路,更轻松地训练出高质量的模型。当然这些技巧不仅仅适用于 YOLO 模型 ,这些适用于所有的深度学习模型。
文章目录
什么是机器学习模型的训练?
模型训练的过程可以想象成教孩子认识各种物体的过程。比如,一开始会给孩子看很多图片,这些图片已经标记好了是什么内容,比如苹果、橘子、汽车等等。孩子看到图片后会尝试说出它是什么,我们会告诉他对错,从而让他学会正确识别。类似地,模型一开始接收大量已经标记好的图像,尝试对这些图像进行预测,然后将结果与真实标签进行比较,看看哪里错了。
每次出错时,模型会根据这些错误信息调整内部的参数(比如权重和偏差),这个过程叫做“反向传播”。就像孩子在不断练习中逐渐记住了物体的样子,模型通过多次调整,慢慢学会了识别图像中的特征,比如形状、颜色、纹理等。
如果一开始给模型看很多苹果和橘子的图片,它可能一开始无法区分,但经过不断的训练和调整后,它能学会通过形状和颜色来区分苹果和橘子。最终,模型不仅能够识别这些简单的物体,还能更复杂地理解图像中的内容,例如在图像中找到特定的对象(对象检测)、对图像进行详细的划分(实例分割),或者对整个图像进行分类(图像分类)。
当你已经了解了模型训练的基本流程后,接下来就可以深入的学习如何优化 YOLO 模型的训练,以及在整个训练过程中需要重点关注的关键因素。
大数据集训练的挑战与对策
在训练模型的过程中,我们经常会遇到训练速度缓慢、精度不足、模型不收敛等问题,还容易陷入一些常见的误区。接下来,让我们逐一解释这些问题的原因及解决方法。
批量大小:加速模型训练最有效方法
批量大小(batch size)指的是每次训练迭代中,模型处理的图像数量。选择合适的批量大小可以有效利用 GPU 资源,减少训练时间。批量大小的选择直接影响显存(GPU 的内存)占用以及 GPU 的利用率。
显存是 GPU 上专门用于存储模型参数和训练数据的内存。如果批量大小过大,显存可能会被耗尽,从而导致内存不足的错误(也就是我们经常看到的 OOM,CUDA Out Of Memory,也叫显存爆炸)。而 GPU 利用率则表示 GPU 的计算资源的使用程度。理想情况下,我们希望 GPU 利用率越高越好,因为这表示 GPU 在全速工作,训练速度会更快。
批量大小和训练速度之间的关系是,如果批量大小过小,GPU 可能无法被充分利用,导致训练速度变慢。而批量大小越大,虽然可以提高 GPU 利用率,但也会增加显存的使用量,甚至可能导致内存不足。在大数据集训练时,建议使用 GPU 能够支持的最大批量大小,以确保高效利用其性能。
如果在训练过程中遇到内存不足的问题,可以逐步减小批量大小,直到模型能顺利进行训练。对于 YOLOv8/v10/v11,可以在训练配置中将 batch_size
设置为合适的值,或者将 batch=-1
以自动确定最佳批量大小。这种自动设置的方式可以帮助根据硬件条件找到一个平衡点,既充分利用 GPU 资源,又避免显存耗尽。
此外,在写论文时,可能会考虑是否保持 batch_size
一致,这一点确实会对模型的精度产生影响,因为不同的 batch_size
会影响模型在每个迭代中看到的数据量,这将间接影响模型的梯度更新方式和参数优化过程。较大的 batch_size
通常会导致模型在每次更新中更稳定,但可能对局部特征不敏感;而较小的 batch_size
则更容易捕捉到数据中的细节和随机性,但可能导致训练过程中的波动更大。因此,batch_size
不一致会影响模型最终的收敛效果和精度表现。
子集训练:节省时间的好方法
在初期测试阶段,如果完整训练模型过于耗时,可以选择子集训练。所谓子集训练,就是只用数据集中的一部分数据来训练模型。这样可以快速迭代,找到最佳的模型结构。然而需要注意的是,子集训练虽然能够在初期快速验证模型的效果,但并不代表这个模型在整个数据集上也能表现良好,因为子集可能无法涵盖所有数据的多样性,导致模型在完整数据集上泛化性能不足。
在 YOLO可以通过 fraction
参数来实现子集训练,例如设置 fraction=0.1
表示只用 10% 的数据集进行训练。这样可以在短时间内进行多次试验,以便在最终完整训练前找到最佳参数配置。
数据增强:提升模型样本量
YOLOv8 提供了很多数据增强的参数,这些参数可以帮助增加样本的多样性,从而提升模型的泛化能力,但在使用时要妥善选择,结合业务场景进行适当的调整,避免由于不当的增强方式导致模型性能的下降。例如,在某些场景下,过度的形变可能会使图像失真,影响模型的学习效果。举个更具体的例子,如果您在检测交通标志时使用了旋转或剪切增强,可能会导致某些标志的形状和方向发生变化,从而使模型误判。比如‘限速标志’如果经过了较大的旋转角度,模型可能会因为图像失真而无法正确识别其具体的限制速度。此外,在人脸识别任务中,过度的色调或饱和度增强也可能使得人脸特征变得不明显,导致模型精度下降。因此,在使用这些数据增强方法时,建议根据业务场景进行选择,例如在对方向敏感的对象检测中避免使用翻转或大幅旋转增强。
hsv_h: 0.015
- 图像 HSV 色调增强(百分比),可以稍微改变图像的色调来模拟不同光照条件。hsv_s: 0.7
- 图像 HSV 饱和度增强(百分比),增加或减少颜色的饱和度来增强模型在不同色彩条件下的表现。hsv_v: 0.4
- 图像 HSV 亮度增强(百分比),调整图像的亮度,模拟不同光照强度。degrees: 0.0
- 图像旋转(正负度数),轻微旋转图像可以增强模型的方向不变性。translate: 0.1
- 图像平移(正负百分比),模拟对象在图像中的不同位置。scale: 0.5
- 图像缩放(正负增益),通过调整对象的大小来提升模型对不同尺度下对象的适应能力。shear: 0.0
- 图像剪切(正负度数),用于模拟对象的倾斜变化。perspective: 0.0
- 图像透视(正负百分比),用于模拟透视失真的变化。flipud: 0.0
- 上下翻转图像(概率),适用于某些对方向不敏感的对象检测。fliplr: 0.5
- 左右翻转图像(概率),通常用于对象检测来增强模型对对称物体的检测能力。bgr: 0.0
- 图像通道 BGR(概率),用于在 BGR 和 RGB 颜色空间之间切换。mosaic: 1.0
- 图像 Mosaic(概率),将多张图像拼接在一起,增加复杂度。mixup: 0.0
- 图像 Mixup(概率),将多张图像融合,增强数据的多样性。copy_paste: 0.0
- 复制粘贴增强(概率),将图像中的某些部分复制并粘贴到其他图像中,增强样本的多样性。copy_paste_mode: "flip"
- 复制粘贴的方式,可以选择翻转、Mixup 等增强方法。auto_augment: randaugment
- 自动增强策略,用于分类任务,可选择randaugment
、autoaugment
、augmix
。erasing: 0.4
- 在分类训练中随机擦除的概率,范围为 0-0.9,用于模拟部分遮挡。crop_fraction: 1.0
- 图像裁剪比例,用于分类,范围为 0.1-1,1.0 表示不裁剪。
在检测交通标志的场景中,fliplr
左右翻转增强可能是不合适的,因为某些标志翻转后意义就完全变了,这时就需要结合实际业务场景,避免因不合适的数据增强而引起模型性能的下降。
缓存:提升数据处理速度
缓存是一种减少数据加载时间、提升训练效率的重要手段。通过将预处理后的图像保存在内存(RAM)或磁盘中,可以减少每次迭代时的数据读取时间。
RAM 和磁盘的区别:
- RAM(随机存取存储器)是计算机中的高速内存,用于临时存储当前正在处理的数据。它的读写速度非常快,所以在训练过程中将数据缓存到 RAM 中可以大大提高读取速度。但 RAM 的容量通常较小,而且较昂贵,因此在处理非常大的数据集时可能会遇到内存不足的问题。
- 磁盘(例如硬盘或固态硬盘)是用于长期存储数据的设备,容量大且价格相对低廉,但读写速度较 RAM 慢。将数据缓存到磁盘上可以节省 RAM 空间,但读取速度相比于 RAM 要慢一些。
在 YOLOv8/v10/v11 中,可以通过 cache
参数来设置缓存策略:
- 设置
cache=True
会将图像缓存到 RAM 中,读取速度最快,但需要较大内存。 - 设置
cache='disk'
则将图像缓存到磁盘上,比从头读取快,但比使用 RAM 慢。 - 如果禁用缓存(
cache=False
),每次都需要从硬盘读取数据,速度最慢。
线程:提升数据加载速度
workers 指在数据加载过程中所使用的工作线程或进程数目。在深度学习中,特别是在处理大规模数据集时,数据加载效率对训练速度有很大的影响。workers 参数的设置能够显著影响模型训练的整体效率。
在 YOLOv8/v10/v11 的数据加载器中,可以通过 workers
参数来指定数据加载过程中使用的并行加载线程或进程的数量:
workers=0
:表示使用主线程来加载数据,不使用并行处理。这通常会导致数据加载成为训练的瓶颈,因为主线程在加载数据时无法同时进行训练。因此,这种设置只适合小数据集或实验环境。workers>0
:表示使用多个工作线程或进程来并行加载数据,可以有效地减少数据加载的等待时间,尤其是在磁盘读取或预处理较耗时的场景下。通常来说,更多的 workers 可以更好地利用多核 CPU 的能力,从而加速数据的读取和预处理过程。
在设置 workers
的值时,需要考虑几个关键因素:
-
CPU 核心数:如果设置的 worker 数量超过了可用的 CPU 核心数,可能会导致 CPU 负载过高,从而影响整体性能。一般建议将 worker 数量设置为 CPU 核心数的 1/2 到 2 倍,以便合理利用 CPU 资源。
-
数据集的大小和预处理复杂度:如果数据集非常大,或者需要复杂的图像预处理步骤,可以增加 worker 数量来加速数据加载。反之,如果数据集较小或预处理较简单,过多的 workers 反而可能造成不必要的资源浪费。
-
内存(RAM)限制:增加 workers 数量也会增加内存消耗,因为每个 worker 可能会缓存一定数量的预处理数据。因此,在设置较多 workers 时,需要确保内存充足,避免因内存不足导致系统性能下降。
workers
参数和 cache
参数可以结合起来使用,以最大化数据加载的效率。例如可以使用 cache=True
将图像缓存到 RAM 中,达到最快读取速度,同时使用多个 workers 来加速数据的加载和预处理。这种组合可以显著减少数据加载成为训练瓶颈的可能性,从而提升整体训练效率。一般机器下 workers 最少可以设置成 8
。
混合精度训练:提升效率的利器
混合精度训练结合使用 16 位(FP16)和 32 位(FP32)浮点数来进行计算,既提高了计算速度,又节省了内存。现在大多 GPU 都支持这种技术,它能让模型在保持精度的同时更快地进行训练。
混合精度训练简单来说就是利用 FP16 来进行大部分计算操作,而在需要高精度时则使用 FP32。FP16 浮点数占用的内存更小,因此可以在一次计算中处理更多的数据,使得 GPU 的计算单元利用率提高。由于 FP16 的计算量更低,所以训练速度更快。与 FP32 相比,FP16 数值需要的内存大小减少了一半,因此可以显著降低显存占用量。这意味着我们可以在同样的显存下使用更大的批量大小(batch size),从而提高模型的训练效果和收敛速度。
在 YOLOv8/v10/v11 中,只需在训练配置中设置 amp=True
即可启用混合精度训练,这是一种简单且有效的方法来加速模型训练并减少内存占用。
然而需要注意的是,在一些较低版本的 PyTorch 中,开启混合精度训练可能会遇到兼容性问题,导致训练报错。因此,在使用混合精度训练之前,个人建议 PyTorch 版本在 2.0 以上。
使用预训练权重:快速接近模型上限
使用预训练权重可以显著缩短模型的训练时间。所谓预训练权重,就是在大数据集上预先训练好的一组模型参数,你可以直接用它们来微调适应你的数据集。这些权重并不是随便用的,必须确保它们与你的模型结构相匹配,因为预训练权重是根据特定的模型架构训练出来的,权重和模型结构需要对应,否则可能导致模型无法正确加载或训练。
使用预训练权重的好处包括:大大减少了训练时间、提高了模型的初始性能以及减少了对大规模计算资源的依赖。因为预训练权重已经学习到了基础的特征(例如边缘、颜色、形状等),所以它们可以为你的任务提供一个良好的起点,尤其是在数据有限的情况下,迁移学习能够帮助模型更快地收敛。
不过在使用预训练权重进行研究和写论文时,需要注意控制变量法,确保其他实验条件一致,避免由于预训练权重的不同而导致结果不具有可比性。
在 YOLOv8/v10/v11 中,通过设置 pretrained=True
或指定预训练模型的路径,可以快速加载这些权重,以提升训练效果。这种方法被称为迁移学习,它可以让模型从一开始就具备对基础特征的理解,从而更好地适应新的任务。
冻结:迁移学习的核心概念
权重这部分除了 pretrained
参数外还有一个 freeze
参数,
freeze
参数用于在模型的迁移学习过程中控制哪些层的权重保持不变,也就是冻结某些层。这在迁移学习中非常重要,因为它可以帮助我们在微调过程中锁定某些基础特征层,专注于调整模型的高层特征,从而更快地适应新任务,尤其是当数据量有限时,这种方法可以有效减少过拟合风险。
当模型使用预训练权重时,前几层通常会学习一些通用的特征(例如,卷积神经网络中的边缘检测、纹理、颜色等)。这些基础特征对大多数图像任务都是有用的。因此,我们可以选择冻结这些层,不再更新它们的权重,从而更快地微调模型。
通过冻结较早的层,仅更新与特定任务相关的高层特征,可以减少训练时间,提高效率。这在处理较小的数据集时特别有帮助,因为冻结这些层可以减少过拟合的风险。
freeze 参数的常见设置方法:
冻结底层层数:通常你可以设置 freeze=0
、freeze=1
、freeze=2
等,这样可以冻结模型的前几层;或者可以写成列表 freeze=[0, 3, 6]
冻结你指定的层。这些层通常提取较低级别的特征(例如,边缘和简单的形状),因此它们对各种任务都是通用的,不需要再重新学习。
如果设置 freeze=None
,那么不冻结任何层,所有的层都会更新,这意味着模型会从预训练权重的基础上,继续对所有层进行训练,这种方式对于大规模的数据集比较合适,特别是新任务的特征和预训练任务有很大不同的时候。
冻结大部分层,只更新后面层:通常可以只微调最后几层,这样做的好处是利用预训练网络前面学到的通用特征,只对更高级的、与特定任务相关的特征进行调整。
提高训练效率的其他技巧
分布式训练
如果你的数据量非常庞大,可以考虑使用分布式训练,即将训练任务分配到多个 GPU 或机器上,以减少训练时间。通过设置 device
参数,可以轻松实现多卡训练。例如,可以将 device="cuda:0"
或 device="0,1,2,3"
这样指定 GPU 设备,以利用多个显卡进行训练,这样可以有效加快模型的训练速度。许多深度学习框架,如 PyTorch,都提供分布式训练的支持。
此外,可以使用 nvidia-smi
命令查看显卡的使用情况,包括显存占用、显卡编号等信息,这对于分布式训练中合理分配显卡资源非常有帮助。
选择训练周期数
训练周期数(epochs)是指模型遍历整个数据集的次数,有时候也叫“轮数”。一般情况下,300 轮就足够了。少数的数据集可能需要更多的训练轮数,但如果需要的收敛轮数大于 300,建议考虑稍微调大学习率,这样可以帮助模型更快地收敛。
在 YOLOv8/v10/v11 中,可以通过训练脚本中的 epochs
参数来设置训练周期数,以适应不同的项目需求。
提前停止:防止过拟合
提前停止(早停)是一种通过监控模型在验证集上的表现来确定何时结束训练的方法。
早停具体关注的指标的变化是加权计算出来的,即 0.1 * mAP0.5 + 0.9 * mAP0.5-0.95
详细的代码位置在 ultralytics/ultralytics/utils/metrics.py
早停可以避免模型过拟合,从而节省计算资源和训练时间。提前停止的核心思想是在验证集的表现不再提升时及时终止训练,这样可以防止模型在训练集上过度拟合,导致在新数据上的性能下降。
在 YOLOv8/v10/v11 中,可以通过设置 patience
参数来启用提前停止。例如,设置 patience=5
表示如果验证集指标在连续 5 个周期内没有改善,训练将会停止。此外,还可以结合其他超参数,如学习率调度器,来进一步提升模型的泛化能力,使得模型能够在适当的时间点结束训练并达到最佳性能。
早停函数的代码在 ultralytics/ultralytics/utils/torch_utils.py
云训练与本地训练
在训练模型时,可以选择在云端进行训练,或者在本地机器上进行训练。
云训练具有强大的可扩展性,适合处理大数据集和复杂模型。云平台如 AWS、Google Cloud、Azure 等提供按需的高性能 GPU,可以加快训练速度。然而,云训练成本较高,特别是长时间使用时,数据传输的成本和延迟也需要考虑。
国内也有很多优秀的云计算厂商,例如我们常见的 autodl,以及蓝耘等。点击这个链接,可以领取 50 元的算力券,除了官方注册的20外,还有点击链接领取的我的粉丝专属20元,足够使用 24 小时的 4090 显卡,非常适合想要尝试云训练的用户。
本地训练则能提供更高的控制性和安全性,适合长期项目,因为数据留在本地,不需要担心隐私问题。但本地机器的资源可能有限,训练大型模型时可能会耗费更多时间。此外,不推荐使用个人笔记本电脑进行训练,即便是配有 4090 显卡的笔记本,其显存和整体性能依然不如台式机,特别是在处理大型数据集时,可能会遇到显存不足的问题。
如何选择优化器
优化器负责调整模型的参数,以最小化损失函数,进而提高模型的性能。选择合适的优化器能显著影响模型的收敛速度和准确性,目前 YOLO 项目内置多种的优化器供大家选择:
-
SGD(随机梯度下降):SGD 是一种简单且经典的优化器,适合大多数场景,但在复杂模型上收敛较慢,且可能陷入局部最小值。它每次只使用一个小批量的数据来更新模型参数,因此在优化过程中容易受到噪声影响,但是这也是最常用的优化器,一般用这个都要跑300轮。
-
Adam(自适应矩估计):Adam 结合了动量和学习率自适应调整的优点,适用于有噪声的数据和稀疏梯度的场景。它通过结合过去梯度的指数移动平均来调整每个参数的学习率,使得收敛速度快,且通常效果较好,因此也是 YOLOv8/v10/v11 推荐的优化器,用这个优化器训练的话,轮数要比 SGD 少一些,但是整体时间对比下来差别不是太大。
-
Adamax:Adamax 是 Adam 的变体,适用于处理不稳定或异常值的数据。它使用无穷范数来控制学习率的更新,能够有效处理梯度幅度变化较大的情况,适合一些需要稳定性的训练场景。
-
AdamW:AdamW 是对 Adam 的改进版本,它在原始 Adam 的基础上加入了权重衰减(weight decay)项,用于防止过拟合。相比于 Adam,AdamW 更适合大型神经网络,特别是在训练深层模型时表现更加优异。
-
NAdam(带有动量的 Adam):NAdam 是 Adam 的改进版,结合了 Nesterov 动量加速的方法,使得每次更新参数时可以预估未来的梯度方向,从而加速收敛。它在某些场景下比 Adam 表现更好,特别是在模型难以快速收敛的情况下。
-
RAdam(Rectified Adam):RAdam 是针对 Adam 收敛过程不稳定的问题提出的一种改进优化器。它通过自适应地调整学习率来解决早期阶段收敛不稳定的问题,从而提高训练过程的稳定性,尤其是在初期训练阶段,能够让模型更稳健地学习。
-
RMSProp(均方根传播):RMSProp 是一种通过调整每个参数的学习率来解决梯度消失问题的优化器,通常适用于循环神经网络(RNN)和 LSTM 等模型。它会根据过去的梯度平方的均值来动态调整学习率,使得训练在复杂损失函数的表面能更平滑地进行。
在 YOLOv8/v10/v11 中,可以通过 optimizer
参数选择优化器,包括 SGD、Adam、AdamW、NAdam、RAdam 和 RMSProp 等,或者直接设置为 auto
,让系统自动选择最适合的优化器。
优化器的相关代码在 ultralytics/ultralytics/engine/trainer.py
那么基础篇就先给大家分享这么多内容,这些都属于正常的优化范畴,下期给大家介绍一些炼丹老司机使用的实用作弊技巧~
有问题欢迎大家指正,如果感觉有帮助的话请点赞支持下👍📖🌟