yolov5 介绍

x33g5p2x  于2021-11-12 转载在 其他  
字(7.6k)|赞(0)|评价(0)|浏览(731)

1、前言

YOLOv5项目地址ultralytics/yolov5

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

  • ONNX (Open Neural Network Exchange

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

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

  • TensorRT

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

1.1 模型训练

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

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

  1. $ 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是一样的,采用数据并行可以提高我们的计算速度。

  1. $ 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

  1. $ 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 环境准备

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

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

  1. $ 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模型结构。

文件中代码:

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

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

关于torch.onnx的介绍见:torch.onnx — PyTorch 1.9.1 documentation

3、Test Time Augmentation (TTA)

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

3.1 Test Normally

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

3.2 Test with TTA

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

3.3 Inference with TTA

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

4、Model Ensembling模型嵌入

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

4.1 Test Normally

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

4.2 Ensemble Test

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

4.3 Ensemble Inference

  1. $ 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

  1. $ python test.py --weights yolov5x.pt --data coco.yaml --img 640
  1. Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.492 < -------- baseline mAP
  2. Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.676
  3. Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.534
  4. Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.318
  5. Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.541
  6. Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.633
  7. Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.376
  8. Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.616
  9. Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.670 < -------- baseline mAR
  10. Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.493
  11. Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.723
  12. 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)

  1. $ python test.py --weights yolov5x.pt --data coco.yaml --img 640
  1. Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.462 < -------- lower mAP
  2. Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.649
  3. Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.505
  4. Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.293
  5. Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.507
  6. Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.602
  7. Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.361
  8. Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.590
  9. Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.643 < -------- lower mAR
  10. Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.465
  11. Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.691
  12. 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%。您可以根据需要调整这些值,也可以使用默认的适应度定义。

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

6.3 遗传算法演变

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

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

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

  1. # Single-GPU
  2. python train.py --epochs 10 --data coco128.yaml --weights yolov5s.pt --cache --evolve
  3. # Multi-GPU
  4. for i in 0 1 2 3; do
  5. nohup python train.py --epochs 10 --data coco128.yaml --weights yolov5s.pt --cache --evolve --device $i > evolve_gpu_$i.log &
  6. done
  7. # Multi-GPU bash while (not recommended)
  8. for i in 0 1 2 3; do
  9. nohup "$(while true; do python train.py ... --evolve --device $i; done)" > evolve_gpu_$i.log &
  10. 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 冻结骨干网络

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

查看模型的参数名:

  1. for k, v in model.named_parameters():
  2. print(k)
  3. # Output
  4. model.0.conv.conv.weight
  5. model.0.conv.bn.weight
  6. model.0.conv.bn.bias
  7. model.1.conv.weight
  8. model.1.bn.weight
  9. model.1.bn.bias
  10. model.2.cv1.conv.weight
  11. model.2.cv1.bn.weight
  12. ...
  13. model.23.m.0.cv2.bn.weight
  14. model.23.m.0.cv2.bn.bias
  15. model.24.m.0.weight
  16. model.24.m.0.bias
  17. model.24.m.1.weight
  18. model.24.m.1.bias
  19. model.24.m.2.weight
  20. model.24.m.2.bias

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

  1. 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**中找到,其余的来自热门的开源实现。

相关文章