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('\nStarting 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中找到,其余的來自熱門的開源實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM