有关Yolov8迁移学习工程化使用中的一些问题

最近在工作中大量使用了yolov8的迁移学习来作为实现工程化应用小样本学习的问题,在这里特意记载几个遇到的网络上比较少相关资料的问题点,作为自己日后学习和复盘的一个记录。topSpInfo

先说项目概要:通过yolov8迁移学习,实现类似增量学习的功能,并且通过类似嫁接的方法合成一个新的模型并且转换为 tensorRT应用在现场。具体的方法就不详细记录了,涉及到商业方面的问题。

主要遇到的问题可以概括为以下两个:

1. 使用ultralytics官方方法冻结backbone后进行训练后,各个backbone的输出仍然产生变化,无法达到绝对的一致;

2. 一些潜在的转换为tensorRT后产生的pt模型与trt模型输出差距较大的问题。

一、冻结backbone参数仍然发生变化

首先来说第一个问题,即backbone即使在冻结后也会发生参数的变化,在进行嫁接的时候会对后续的输出产生较大影响,对检测产生不稳定的不可知影响。按常规的理解来说,通过ultralytics里面给的方法,即freeze=10这种就可以使得backbone的参数完全冻结,但是在实际使用中,发现backbone的参数还是有一定变化的,那么是什么原因呢?

为了解决这个问题,我主要参考了一些csdn的文章(具体来源不记得了,有人知道的可以和我说下),总的来说问题大概是出在这两个地方:1. 官方框架的freeze方法对于一些bn层里的mean之类的参数没有实际冻结到;2. EMA的开启会对冻结backbone的参数产生一定影响。

1、BN层有一些参数没有实际冻结到:

这个问题很多博文也有提到,具体是否真的产生了变化我也暂时没有考证,之后可以进一步探讨,该文只记录如何手动在ultralytics框架里面冻结所需要所有参数。比如我的冻结层数是22,进入到yolov8的训练部分的代码,具体位置在ultralytcis/engine/trainer.py里面,位置大约是在326行的循环里面加上:

for layer in layers_to_freeze:
    layer.eval()

2. EMA的开启会对冻结backbone产生影响

首先EMA是一种平滑训练方法,具体的公式原理大家可以去相关博文下面看,这里就不过多阐述原理了。通俗的理解是,EMA会使得整体训练更加平滑,在训练刚开始阶段会让参数的更新更加倾向于新数据,当迭代次数多了之后,参数的更新更加接近于历史数据。在标准yolov8框架下,在 ultralytics\utils\torch_utils.py中,无论是否对层进行冻结,都会进行ema的更新,具体修改方法如下:在class ModelEMA的update更新函数下面,改成这样,这里我的冻结层数是22。

    def update(self, model):
        """Update EMA parameters."""
        if self.enabled:
            self.updates += 1
            d = self.decay(self.updates)

            msd = de_parallel(model).state_dict()  # model state_dict
            for k, v in self.ema.state_dict().items():
                if v.dtype.is_floating_point:  # true for FP16 and FP32
                    #冻结多少层就对应修改model后面的数字
                    if 'model.22' in k and 'dfl' not in k:
                        #print(f'updating EMA :{k}')
                        v *= d
                        v += (1 - d) * msd[k].detach()
                        assert v.dtype == msd[k].dtype == torch.float32, f'{k}: EMA {v.dtype},  model {msd[k].dtype}'

通过上面的两个修改,实测是可以实现完全冻结backbone的,原理原因这些还需要进一步的学习和复盘。

二、TensorRT模型和PT模型精度差距较大

这个问题在我的算法里面主要就是不小心把amp关掉了,开启amp之后精度差距又回到了正常的范围。这其中的原因有可能是

1. 混合精度训练与推理精度的关系

AMP 简介

AMP训练通过混合使用16位浮点数(FP16)和32位浮点数(FP32)来加速训练过程,同时减少显存使用量。许多现代GPU(如NVIDIA的Volta、Turing和Ampere架构)都支持高效的FP16运算。

TensorRT 优化

TensorRT是一个高性能深度学习推理库,它也广泛支持FP16运算。启用FP16模式可以显著提升推理速度,并减少显存使用。

训练与推理的一致性
  • 使用AMP进行训练:模型在训练过程中已经适应了FP16和FP32之间的数值变化和精度损失。当你将这种模型转换为TensorRT并在FP16模式下进行推理时,由于模型在训练过程中已经处理过FP16的数值范围和精度,推理时的数值表现会更稳定且一致。
  • 不使用AMP进行训练:模型在训练过程中只使用FP32浮点数,因此它可能没有适应FP16的数值范围和精度。转换为TensorRT并在FP16模式下进行推理时,可能会引入更多的数值误差和不稳定性,导致精度下降。

2. 数值稳定性和精度损失

在使用FP16进行计算时,数值的表示范围和精度比FP32要低得多。这可能导致一些数值不稳定性和精度损失。当模型在训练过程中没有经历过FP16的数值范围和精度时,其在FP16推理过程中的表现可能会不如预期。

3. TensorRT的优化手段

TensorRT在进行模型转换和优化时,可能会进行一些特有的操作,如层融合、权重量化等。这些操作在FP16精度下可能会引入一定的数值误差。如果模型在训练过程中已经使用过AMP,那么这些操作的影响可能会被最小化,因为模型已经适应了FP16的上下文。

4. 测试不同的精度模式

如果你发现精度损失较大,可以尝试以下几种方法来缓解:

  • 使用FP32模式:在TensorRT转换过程中,可以指定使用FP32模式进行推理,这样可以避免FP16带来的数值误差,但会增加计算成本和显存使用。
  • 混合精度模式:可以尝试使用混合FP16和FP32的模式,来平衡精度和性能。

结论

在使用AMP进行训练时,模型已经适应了FP16和FP32之间的数值变化和精度损失,因此在转换为TensorRT并启用FP16推理模式时,精度变化较小。而未使用AMP进行训练的模型在FP16推理模式下可能会遇到更多的数值误差和不稳定性,导致精度下降。

为了确保转换后的模型在TensorRT中具有较好的精度表现,建议在训练过程中启用AMP,并仔细调试和测试不同的精度模式。

  • 22
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值