• YOLOv5项目介绍


    YOLOv5 项目教程


    作者:elfin  资料来源:YOLOv5


    1、前言

    YOLOv5项目地址ultralytics/yolov5

    ​ 项目自发布以来,直到现在仍然在不断改进模型、项目。作者的更新频率很大,很多问题都能够及时解决,当然问题也很多!到写稿此时,项目的device参数仍然无法正常工作,查看源码,作者的代码写的GPU设备控制比较复杂,修改源码也没有解决,可能我里解决就差一步了吧!在项目提交bug后,得到作者的及时回应,但是最后仍然没有解决。难道使用GPU必须从GPU:0开始吗?查看bug请点击

    • ONNXOpen Neural Network Exchange

      开发式神经网络交换格式!

      它是深度学习模型的一种标准,可使模型在不同框架间转移

    • TensorRT

      英伟达官方提供的GPU版深度学习模型加速平台,可以和Tensor Serving一起部署模型,实现模型的快速运算,其特点是性能高、资源占用少。

    1.1 模型训练

    $ python train.py  --batch-size 64 --data coco.yaml --weights yolov5l.pt --device 0,1
    

    使用 --device 0,1指定多个GPU是没有用的!会衰减计算速度。推荐多GPU使用数据并行的方法。

    $ python -m torch.distributed.launch --nproc_per_node 2 train.py --batch-size 64 --data coco.yaml --weights yolov5x.pt
    
    • --nproc_per_node: 指定你的GPU节点数;

    • --batch-size:这里的批量是总的批量,实际每个GPU的的batch为 64/32.

      这里的处理方式和keras是一样的,采用数据并行可以提高我们的计算速度。

    $ python -m torch.distributed.launch --nproc_per_node 2 train.py --batch-size 64 --data coco.yaml --cfg yolov5x.yaml --weights '' --device 2,3
    

    数据并行运算的时候可以指定要使用的GPU: --device 2,3

    $ python -m torch.distributed.launch --nproc_per_node 2 train.py --batch-size 64 --data coco.yaml --cfg yolov5x.yaml --weights '' --sync-bn
    

    SyncBatchNorm多个GPU之间进行批量标准化!

    ​ 下面介绍将模型转为ONNX模型,使用TensorRT部署……


    2、yolov5模型转ONNX模型

    2.1 环境准备

    $ git clone https://github.com/ultralytics/yolov5  # clone repo
    $ cd yolov5
    $ pip install -r requirements.txt  # base requirements
    $ pip install onnx>=1.7.0  # for ONNX export
    $ pip install coremltools==4.0  # for CoreML export
    

    2.2 输出已训练的模型为ONNX模型

    $ python models/export.py --weights yolov5x.pt --img 640 --batch 1  # export at 640x640 with batch size 1
    

    export.py输出了三个模型,这里我们主要查看onnx模型!

    使用https://netron.app/可以查看我们生成的ONNX模型结构。

    文件中代码:

    print('
    Starting ONNX export with onnx %s...' % onnx.__version__)
    f = opt.weights.replace('.pt', '.onnx')  # filename
    torch.onnx.export(model, img, f, verbose=False, opset_version=12, input_names=['images'],
                      output_names=['classes', 'boxes'] if y is None else ['output'])
    # Checks
    onnx_model = onnx.load(f)  # load onnx model
    onnx.checker.check_model(onnx_model)  # check onnx model
    # print(onnx.helper.printable_graph(onnx_model.graph))  # print a human readable model
    print('ONNX export success, saved as %s' % f)
    except Exception as e:
    print('ONNX export failure: %s' % e)
    

    torch.onnx.export()模型转换关键函数

    关于torch.onnx的介绍见:https://pytorch.org/docs/stable/onnx.html


    3、Test Time Augmentation (TTA)

    添加命令行参数--augment实现测试、预测时的性能增强!

    3.1 Test Normally

    $ python test.py --weights yolov5x.pt --data coco.yaml --img 640
    

    3.2 Test with TTA

    $ python test.py --weights yolov5x.pt --data coco.yaml --img 832 --augment
    

    3.3 Inference with TTA

    $ python detect.py --weights yolov5s.pt --img 832 --source ./inference/images/ --augment
    

    4、Model Ensembling模型嵌入

    还记得决策树吗?而现在我们一般使用随机森林、LightGBM等模型。Ensembling的思想在深度学习模型中同样适应,这里我们对yolov5的不同模型进行融合,结果发现,预测显著性明显提升。

    4.1 Test Normally

    $ python test.py --weights yolov5x.pt --data coco.yaml --img 640
    

    4.2 Ensemble Test

    $ python test.py --weights yolov5x.pt yolov5l.pt --data coco.yaml --img 640
    

    4.3 Ensemble Inference

    $ python detect.py --weights yolov5x.pt yolov5l.pt --img 640 --source ./inference/images/
    

    这里测试结果为:齐达内是人的概率从0.8上涨到0.9!


    5、Pruning/Sparsity Tutorial 剪枝/稀疏教程

    5.1 Test Normally

    $ python test.py --weights yolov5x.pt --data coco.yaml --img 640
    
    Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.492 < -------- baseline mAP
    Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.676
    Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.534
    Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.318
    Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.541
    Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.633
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.376
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.616
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.670 < -------- baseline mAR
    Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.493
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.723
    Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.812
    

    5.2 Test with 30% Pruned Model

    我们现在用一个修剪过的模型重复上面的测试,设置修剪30%,这里我们需要修改test.py文件的torch_utils.prune(model, 0.3)

    $ python test.py --weights yolov5x.pt --data coco.yaml --img 640
    
    Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.462 < -------- lower mAP
    Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.649
    Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.505
    Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.293
    Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.507
    Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.602
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.361
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.590
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.643 < -------- lower mAR
    Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.465
    Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.691
    Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.786
    

    在结果中我们可以观察到,我们的模型在剪枝后达到了30%的稀疏性,这意味着30%的模型权重参数nn.Conv2d层等于0。测试时间(在P100 GPU上)保持不变,而模型的AP和AR分数略有降低。


    6、 Hyperparameter Evolution超参数调优

    超参数对模型的影响是很大的,但是具体是如何影响的,通过严格的数学推导我们是做不到的。科学家在如何获取最优参数的道路上做了很多尝试,遗传算法(GA)就是比较出名的存在。

    6.1 初始化超参数

    YOLOv5有大约25个用于各种训练设置的超参数。这些是在/data目录的yaml文件中定义的。更好的初始猜测将产生更好的最终结果,因此在演化之前正确初始化这些值是很重要的。如果有疑问,只需使用默认值,这是优化YOLOv5在COCO数据集的配置参数。

    6.2 定义适应性函数

    适应性是我们追求最大化的价值。在YOLOv5中,我们将默认适应度函数定义为度量的加权组合:mp@0.5贡献了10%、mp@0.5:0.95占其余90%。您可以根据需要调整这些值,也可以使用默认的适应度定义。

    def fitness(x): 
        # Returns fitness (for use with results.txt or evolve.txt) 
        w = [0.0, 0.0, 0.1, 0.9]  # weights for [P, R, mAP@0.5, mAP@0.5:0.95] 
        return (x[:, :4] * w).sum(1) 
    

    6.3 遗传算法演变

    evolution是在一个我们寻求改进的基本场景下进行的。本例中的基本场景是使用预训练的yolov5对COCO128进行10个时期的微调。基本场景训练命令是:

    $ python train.py --epochs 10 --data coco128.yaml --weights yolov5s.pt --cache
    

    为了进化特定于这个场景的超参数,从我们在第6.1节中定义的初始值开始,并最大化第6.2节中定义的适应度,增加--evolve

    # Single-GPU
    python train.py --epochs 10 --data coco128.yaml --weights yolov5s.pt --cache --evolve
    
    # Multi-GPU
    for i in 0 1 2 3; do
      nohup python train.py --epochs 10 --data coco128.yaml --weights yolov5s.pt --cache --evolve --device $i > evolve_gpu_$i.log &
    done
    
    # Multi-GPU bash while (not recommended)
    for i in 0 1 2 3; do
      nohup "$(while true; do python train.py ... --evolve --device $i; done)" > evolve_gpu_$i.log &
    done
    

    ​ 主要的遗传算子是交叉变异。在这项工作中,使用了变异,以90%的概率和0.04的方差,根据所有前几代最好的父母的组合来创造新的后代。结果记录在yolov5中/evolve.txt,每一代都保存着最适合的后代于yolov5/runs/evolve/hyp_evolved.yaml中。

    ​ 我们建议至少300代进化才能获得最佳结果。请注意,进化通常是昂贵和耗时的,因为基本场景需要数百次训练,可能需要数百或数千个小时的GPU训练。

    项目超参数进化说明


    7、迁移学习冻结yolov5层

    ​ 本指南解释了如何在迁移学习时冻结YOLOv5层。迁移学习是一种有用的方法,可以快速地在新数据上重新训练模型,而不必重新训练整个网络。相反,一部分初始权重被冻结在原位,其余权重用于计算损失,并由优化器更新。这需要比正常训练更少的资源,并且允许更快的训练时间,尽管它也可能导致最终训练精度的降低。

    Transfer Learning with Frozen Layers

    7.1 冻结骨干网络

    # Freeze 
    freeze = []  # parameter names to freeze (full or partial) 
    for k, v in model.named_parameters(): 
        v.requires_grad = True  # train all layers 
        if any(x in k for x in freeze): 
            print('freezing %s' % k) 
            v.requires_grad = False
    

    查看模型的参数名:

    for k, v in model.named_parameters():
        print(k)
    
    # Output
    model.0.conv.conv.weight
    model.0.conv.bn.weight
    model.0.conv.bn.bias
    model.1.conv.weight
    model.1.bn.weight
    model.1.bn.bias
    model.2.cv1.conv.weight
    model.2.cv1.bn.weight
    ...
    model.23.m.0.cv2.bn.weight
    model.23.m.0.cv2.bn.bias
    model.24.m.0.weight
    model.24.m.0.bias
    model.24.m.1.weight
    model.24.m.1.bias
    model.24.m.2.weight
    model.24.m.2.bias
    

    发现模型的backbone是0~9层,所以在freeze中添加这几层的name。

    freeze = ['model.%s.' % x for x in range(10)]  # parameter names to freeze (full or partial)
    

    7.2 冻结全部yolov5的layers

    这个简单,你可以将name全部放入freeze中,也可以设置所以层v.requires_grad = False

    7.3 总结

    ​ 冻结yolov5的backbone之后,GPU的占用率下降了20%,显存占用下降了40%+。训练其他数据即的性能指标下降了0.0021%,这种性能损失还是可以接受的。

    既然训练非backbone部分训练时间更快,GPU占用、显存占用更少,是不是可以先训练非backbone部分,再一起训练呢?


    8、TensorRT模型加速

    yolov5里面涉及的一些结构在TensorRT里面还没有支持,这些结构要加速就只能自己用C++实现。使用C++编程对很多人来说都是非常麻烦的事情,这里借鉴TensorRTx项目进入这个领域。

    TensorRTx旨在通过TensorRT网络定义API实现流行的深度学习网络。我们知道,TensorRT有内置的解析器,包括caffeparser、uffparser、onnxparser等,但当我们使用这些解析器时,常常会遇到一些“不支持的操作或层”问题,特别是一些最新的模型正在使用新型的层。

    ​ 我们为什么不跳过所有的解析器呢?我们只需要使用TensorRT网络定义API来构建整个网络,并不复杂。

    ​ 这个项目是为了熟悉TensorRT API,也为了分享和向社区学习。

    ​ 所有模型首先在pytorch/mxnet/tensorflow中实现,并导出一个权重文件xxx.wts然后使用TensorRT进行权值加载、网络定义和推理。一些pytorch实现可以在我的repo Pytorchx中找到,其余的来自热门的开源实现。

  • 相关阅读:
    Codeforces
    Codeforces
    Codeforces
    Codeforces
    Codeforces
    Codeforces
    Codeforces
    Codeforces
    洛谷
    GXU
  • 原文地址:https://www.cnblogs.com/dan-baishucaizi/p/14183614.html
Copyright © 2020-2023  润新知