opencv dnnモジュール例(17) yolo v5のターゲット検出object_detection

前回の記事[ opencv dnn モジュールの例 (16) ターゲット検出 object_detection - yolov4]で紹介した yolo v4 から 2 か月後、Ultralytics は YOLO V4 と同等のパフォーマンスを持つ YOLOV5 の最初の正式バージョンをリリースしました。

ここに画像の説明を挿入します

Yolo v5 は実際には Yolo v4 と継承関係はなく、どちらも yolo v3 をベースに改良されたものですが、対応する論文やオープンソースプロトコルなどが公開されていないため、新世代とは言えないのではないかという疑問が持たれています。 YOLOの。しかし、私たちの学習や利用においては、ネズミを捕まえることができれば、白猫でも黒猫でもどちらも良い猫です。

1.Yolo v5とYolo v4の違いの説明

YOLO V5 と V4 を以下の観点から比較し、それぞれの新技術の特徴を簡単に説明し、両者の相違点と類似点を比較します。

1.1. データ拡張 - データ拡張

YOLO V4 は、単一の画像に対して複数のデータ拡張テクノロジーを組み合わせて使用​​しており、古典的な幾何学的歪みと照明歪みに加えて、画像オクルージョン (ランダム消去、カットアウト、かくれんぼ、グリッド マスク、ミックスアップ) テクノロジーも革新的に使用しています。 -画像の組み合わせでは、作者は CutMix と Mosaic テクノロジーを組み合わせて使用​​しています。さらに、著者はデータ強化のために自己敵対的トレーニング (SAT) も使用しました。

YOLO V5 の作者はまだ論文を発表していないため、そのデータ拡張パイプラインはコードの観点からのみ理解できます。
YOLOV5 は、トレーニング データの各バッチをデータ ローダーに渡し、同時にトレーニング データを強化します。
データ ローダーは、スケーリング、色空間調整、モザイク拡張の 3 種類のデータ拡張を実行します。
興味深いことに、YOLO V5 の作者である Glen Jocher 氏が Mosaic Augmentation の作者であるとの報道があり、彼は YOLO V4 の大幅なパフォーマンス向上はモザイク データの強化によるところが大きいと考えており、おそらく不満を抱いているのではないかと考えています。 YOLO V4 から
わずか 2 か月で YOLO V5 が発売されましたが、もちろん、今後も YOLO V5 という名前を使い続けるか、他の名前を採用するかは、まず YOLO V5 の最終研究結果が本当に YOLO V4 をリードできるかどうかにかかっています。
しかし、モザイク データの強化によって、モデルのトレーニングで最も厄介な「小さなオブジェクトの問題」、つまり小さなオブジェクトが大きなオブジェクトほど正確に検出されない問題を実際に効果的に解決できることは否定できません。

1.2. 自動学習バウンディングボックスアンカー - アダプティブアンカーボックス

以前の YOLO V3 では、K 平均法と遺伝的学習アルゴリズムを使用してカスタム データ セットを分析し、カスタム データ セット内のオブジェクト境界ボックス予測に適したプリセット アンカー ボックスを取得していました。
ここに画像の説明を挿入します
YOLO V5 では、アンカー ボックスはトレーニング データに基づいて自動的に学習されますが、YOLO V4 には適応型アンカー ボックスがありません

COCO データ セットの場合、640×640 の画像サイズの下のアンカー ボックスのサイズは、YOLO V5 の構成ファイル *.yaml で事前設定されています。

anchors:
  - [10,13, 16,30, 33,23]  		# P3/8
  - [30,61, 62,45, 59,119]  	# P4/16
  - [116,90, 156,198, 373,326]  # P5/32

カスタム データ セットの場合、ターゲット認識フレームワークは元の画像サイズを拡大縮小する必要があり、データ セット内のターゲット オブジェクトのサイズが COCO データ セットとは異なる場合があるため、YOLO V5 はアンカー ボックスのサイズを自動的に学習します。また。
ここに画像の説明を挿入します
上の図では、YOLO V5 が自動アンカー ボックスのサイズを学習しています。BDD100K データ セットの場合、モデル内の画像が 512 にスケーリングされた後の最適なアンカー ボックスは次のようになります。
ここに画像の説明を挿入します

1.3. バックボーン - クロスステージ部分ネットワーク (CSP)

YOLO V5 と V4 はどちらも CSPDarknet をバックボーンとして使用しており、CSPNet の正式名称は Cross Stage Partial Networks で、クロスステージ部分ネットワークです。CSPNet は、他の大規模な畳み込みニューラル ネットワーク フレームワーク Backbone のネットワーク最適化における勾配情報の重複問題を解決し、勾配の変化を最初から最後まで特徴マップに統合することで、モデル パラメーターの数と FLOPS 値を削減し、推論速度を確保するだけでなく、と精度が向上し、モデルのサイズが縮小されました。

1.4. ネックパス集約ネットワーク (PANET)

ネックは主に特徴ピラミッドを生成するために使用されます。特徴ピラミッドにより、モデルによるさまざまなスケールでのオブジェクトの検出が強化され、異なるサイズやスケールで同じオブジェクトを認識できるようになります。

PANET が登場するまで、FPN は物体検出フレームワークの機能集約層における最先端の技術でした。

YOLO V4 の研究では、PANET が YOLO に最適な機能融合ネットワークであると考えられているため、YOLO V5 と V4 の両方で PANET をネックとして機能を集約します。

1.5. Head-YOLO ユニバーサル検出レイヤー

モデルヘッドは主に最終検出部分に使用されます。特徴マップにアンカー ボックスを適用し、クラス確率、オブジェクト スコア、および境界ボックスを含む最終出力ベクトルを生成します。

YOLO V5 モデルでは、モデル ヘッドは以前の YOLO V3 および V4 バージョンと同じです。
ここに画像の説明を挿入します
異なるスケーリング スケールを持つこれらのヘッドは、異なるサイズのオブジェクトを検出するために使用されます (入力 608、最終出力 5 回のダウンサンプリング)。各ヘッドには合計 (80 クラス + 1 確率 + 4 座標) * 3 アンカー ボックス、合計 255 があります。チャンネル。

1.5、アクティベーション関数 - アクティベーション関数

活性化関数の選択は、深層学習ネットワークにとって重要です。YOLO V5 の作成者は、Leaky ReLU および Sigmoid 活性化関数を使用しました。

YOLO V5 では、中間/隠れ層は Leaky ReLU 活性化関数を使用し、最終検出層は Sigmoid 活性化関数を使用します。YOLO V4 は Mish アクティベーション関数を使用します。

Mish は 39 のベンチマークで Swish を上回り、40 のベンチマークで ReLU を上回り、一部の結果ではベンチマークの精度が 3 ~ 5% 向上したことが示されています。ただし、Mish のアクティベーションは ReLU や Swish に比べて計算コストが高いことに注意してください。
ここに画像の説明を挿入します

1.6. 最適化機能 - 最適化機能

YOLO V5 の作成者は、2 つの最適化関数 Adam と SGD、および両方のプリセットのマッチング トレーニング ハイパーパラメーターを提供しています。デフォルトはシンガポールドルです。

YOLO V4 は SGD を使用します。

YOLO V5 の作成者は、小規模なカスタム データセットをトレーニングする必要がある場合は、Adam の方が適切な選択肢であると推奨していますが、Adam の学習率は一般に SGD よりも低いです。

ただし、大規模なデータセットをトレーニングする場合、YOLOV5 では Adam よりも SGD の方がうまく機能します。

実際、SGD と Adam のどちらが優れているかについては、学術界で統一された結論はなく、実際のプロジェクトの状況によって異なります。

コスト関数
YOLO シリーズの損失計算は、オブジェクト性スコア、クラス確率スコア、および境界ボックス回帰スコアに基づいています。

YOLO V5 は、境界ボックスの損失として GIOU 損失を使用し、バイナリ クロス エントロピーとロジッツ損失関数を使用してクラスの損失確率とターゲット スコアを計算します。同時に、fl_gamma パラメーターを使用して焦点損失をアクティブにし、損失関数を計算することもできます。

YOLO V4 は境界ボックスの損失として CIOU Loss を使用しており、前述の他の方法と比較して、CIOU はより高速な収束と優れたパフォーマンスをもたらします。
ここに画像の説明を挿入します

上図の結果は Faster R-CNN に基づいており、実際には CIoU の方が GIoU よりも優れたパフォーマンスを発揮していることがわかります。

1.7、ベンチマーク - YOLO V5 VS YOLO V4

論文で詳細な議論を行う前に、著者が発表した COCO 指標を調べ、その後の大手企業による評価例と組み合わせて 2 つのパフォーマンスを比較することしかできません。

1.7.1. 公式パフォーマンス評価

ここに画像の説明を挿入します
ここに画像の説明を挿入します
上の 2 つの図では、FPS と ms/img の関係が逆転しており、単位換算後、YOLO V5 は V100GPU で 250FPS に達し、高い mAP を持っていることがわかります。

YOLO V4 の元々のトレーニングは 1080TI であり、V100 のパフォーマンスよりもはるかに低く、AP_50 と AP_val のベンチマークが異なるため、上記の表だけから 2 つのベンチマークを取得することは不可能です。

幸いなことに、YOLO V4 の 2 番目の作成者である WongKinYiu は、V100 GPU を使用して同等のベンチマークを提供しました。
ここに画像の説明を挿入します

グラフからわかるように、実際には 2 つのパフォーマンスは非常に近いですが、データによると、YOLO V4 が依然として最良のオブジェクト検出フレームワークです。YOLO V4 は高度にカスタマイズ可能で、さらにカスタム構成を恐れない場合は、やはり Darknet ベースの YOLO V4 が最も正確です。

YOLO V4 では実際に Ultralytics YOLOv3 コード ベースで多数のデータ拡張テクノロジが使用されていることは注目に値します。これらのテクノロジは YOLO V5 でも実行されます。データ拡張テクノロジが結果にどの程度の影響を与えるかについては、著者の論文を待つ必要があります。分析。

1.7.2. トレーニング時間

Roboflow の調査によると、YOLO V5 はトレーニング速度が非常に速く、トレーニング速度において YOLO V4 をはるかに上回っています。Roboflow のカスタム データセットの場合、YOLO V4 では最大検証評価に達するまでに 14 時間かかりましたが、YOLO V5 では 3.5 時間しかかかりませんでした。

ここに画像の説明を挿入します

1.7.3. モデルのサイズ

図内のさまざまなモデルのサイズは次のとおりです: V5x: 367MB​​、V5l: 192MB、V5m: 84MB、V5s: 27MB、YOLOV4: 245 MB.YOLO V5s モデルのサイズは非常に小さいため、導入コストが削減され、迅速な導入に役立ちます
。モデルの。
ここに画像の説明を挿入します

1.7.4. 推論時間

ここに画像の説明を挿入します

単一のイメージ (バッチ サイズ 1) では、YOLOV4 は 22 ミリ秒で推論し、YOLOV5s は 20 ミリ秒で推論します。

YOLOV5 実装のデフォルトはバッチ推論 (バッチ サイズ 36) であり、バッチ処理時間をバッチ内の画像の数で割ります。単一画像の推論時間は 7 ミリ秒、つまり 140FPS に達することがあります。これが現在の状態です。 -物体検出の分野における最先端の技術。

トレーニングしたモデルを使用して、10,000 個のテスト画像に対してリアルタイム推論を実行しました。YOLOV5 の推論速度は非常に驚くべきものです。各画像に必要な推論時間はわずか 7 ミリ秒です。20 メガバイトを超えるモデル サイズと相まって、比類のないものです。柔軟性の観点から。

しかし実際には、これは YOLO V4 にとって公平ではありません。YOLO V4 はデフォルトのバッチ推論を実装していないため、比較すると不利です。同じベンチマークの下で 2 つのオブジェクト検出フレームワークについて多くのテストが必要です。

次に、YOLO V4 の tiny バージョンが最近リリースされましたが、YOLO V5 と V4 tiny のパフォーマンスと速度の比較には、より実践的な分析が必要です。

1.8. 比較と要約

一般に、YOLO V4 はパフォーマンスでは YOLO V5 よりも優れていますが、柔軟性と速度では YOLO V5 よりも劣ります。

YOLO V5 は現在も急速に更新されているため、YOLO V5 の最終的な研究結果はまだ分析されていません。

個人的には、これらの物体検出フレームワークでは、特徴融合層のパフォーマンスが非常に重要であると考えており、現在はどちらも PANET を使用していますが、Google Brain の調査によると、特徴融合層には BiFPN が最適であるとのことです。このテクノロジーを統合できる人は、大幅なパフォーマンスの向上を達成できる可能性があります。

ここに画像の説明を挿入します

YOLO V5 はまだ劣っていますが、YOLO V5 には次のような大きな利点があります。

  • Pytorch フレームワークの使用は非常にユーザーフレンドリーで、独自のデータセットを簡単にトレーニングできます。YOLO V4 で採用されている Darknet フレームワークと比較して、Pytorch フレームワークは運用環境への導入が容易です。

  • コードは読みやすく、多数のコンピューター ビジョン テクノロジが統合されているため、学習や参照に非常に役立ちます。

  • 環境の構成が簡単なだけでなく、モデルのトレーニングも非常に高速で、バッチ推論によりリアルタイムの結果が得られます。

  • 単一画像、バッチ画像、ビデオ、さらには Web カメラ ポート入力に対して効率的な推論を直接実行する機能

  • Pytorch 重みファイルを Android で使用される ONXX 形式に簡単に変換してから、OPENCV で使用される形式に変換したり、CoreML を通じて IOS 形式に変換してモバイル アプリケーションに直接デプロイしたりできます。

  • 最後に、YOLO V5 の最大 140FPS のオブジェクト認識速度は非常に印象的で、ユーザー エクスペリエンスは優れています。

2.yolo v5テスト

現在の yolo v5 プロジェクトのアドレスはhttps://github.com/ultralytics/yolovで、バージョンは v7.0 に更新されています。

2.1. Python テスト

2.1.1. インストール

git clone https://github.com/ultralytics/yolov5  # clone
cd yolov5
pip install -r requirements.txt  # install

2.1.2. 推論

  • yolov5 ハブ推論を使用すると、最新モデルが YOLOv5 リリースから自動的にダウンロードされます。

    	import torch
    	# Model
    	model = torch.hub.load("ultralytics/yolov5", "yolov5s")  # or yolov5n - yolov5x6, custom
    	# Images
    	img = "https://ultralytics.com/images/zidane.jpg"  # or file, Path, PIL, OpenCV, numpy, list
    	# Inference
    	results = model(img)
    	# Results
    	results.print()  # or .show(), .save(), .crop(), .pandas(), etc.
    	```
    
    
  • detect.py を使用した推論
    detect.py はさまざまなソースで推論を実行します。モデルは最新の YOLOv5 リリースから自動的にダウンロードされ、結果は run/detect に保存されます。

    python detect.py --weights yolov5s.pt --source 0                               # webcam
                                                   img.jpg                         # image
                                                   vid.mp4                         # video
                                                   screen                          # screenshot
                                                   path/                           # directory
                                                   list.txt                        # list of images
                                                   list.streams                    # list of streams
                                                   'path/*.jpg'                    # glob
                                                   'https://youtu.be/LNwODJXcvt4'  # YouTube
                                                   'rtsp://example.com/media.mp4'  # RTSP, RTMP, HTTP stream
    

2.1.3. テスト出力

前処理、推論、nms の 3 つの指標時間データに焦点を当て、パラメーター --dnn と --half の使用法と操作効率の比較に注目してください。

(yolo_pytorch) E:\DeepLearning\yolov5>python detect.py --weights yolov5n.pt --source data/images/bus.jpg
detect: weights=['yolov5n.pt'], source=data/images/bus.jpg, data=data\coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs\detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1
YOLOv5  v7.0-167-g5deff14 Python-3.9.16 torch-1.13.1+cu117 CUDA:0 (NVIDIA GeForce GTX 1080 Ti, 11264MiB)

Fusing layers...
YOLOv5n summary: 213 layers, 1867405 parameters, 0 gradients
image 1/1 E:\DeepLearning\yolov5\data\images\bus.jpg: 640x480 4 persons, 1 bus, 121.0ms
Speed: 1.0ms pre-process, 121.0ms inference, 38.0ms NMS per image at shape (1, 3, 640, 640)
Results saved to runs\detect\exp2


(yolo_pytorch) E:\DeepLearning\yolov5>python detect.py --weights yolov5n.pt --source data/images/bus.jpg --device 0
detect: weights=['yolov5n.pt'], source=data/images/bus.jpg, data=data\coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=0, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs\detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=True, vid_stride=1
YOLOv5  v7.0-167-g5deff14 Python-3.9.16 torch-1.13.1+cu117 CUDA:0 (NVIDIA GeForce GTX 1080 Ti, 11264MiB)

Fusing layers...
YOLOv5n summary: 213 layers, 1867405 parameters, 0 gradients
image 1/1 E:\DeepLearning\yolov5\data\images\bus.jpg: 640x480 4 persons, 1 bus, 11.0ms
Speed: 0.0ms pre-process, 11.0ms inference, 7.0ms NMS per image at shape (1, 3, 640, 640)
Results saved to runs\detect\exp2


(yolo_pytorch) E:\DeepLearning\yolov5>python detect.py --weights yolov5n.pt --source data/images/bus.jpg --dnn
detect: weights=['yolov5n.pt'], source=data/images/bus.jpg, data=data\coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs\detect, name=exp, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=True, vid_stride=1
YOLOv5  v7.0-167-g5deff14 Python-3.9.16 torch-1.13.1+cu117 CUDA:0 (NVIDIA GeForce GTX 1080 Ti, 11264MiB)

Fusing layers...
YOLOv5n summary: 213 layers, 1867405 parameters, 0 gradients
image 1/1 E:\DeepLearning\yolov5\data\images\bus.jpg: 640x480 4 persons, 1 bus, 10.0ms
Speed: 0.0ms pre-process, 10.0ms inference, 4.0ms NMS per image at shape (1, 3, 640, 640)
Results saved to runs\detect\exp3

他のテストの比較

        pre-process、 inference、   nms
cpu:        1           121       38
gpu:        0           11         7
dnn:        0		     10         4
gpu-half:    0           10         4
dnn-half:    1           11         4 

2.2. C++ テスト

ここでは、opencv dnn モジュールを使用して、yolov5 によってエクスポートされた onnx 形式モデルをテスト用にロードします。

2.2.1. モデルのエクスポート

実際、公式 Web サイトではモデルのバージョンごとに onnx 形式のエクスポート ファイルが提供されていますが、これらはすべて半精度モデルであり、opencv dnn で直接使用することはできません。

ここでは、onnx モデルをエクスポートするための例として yolov5x を取り上げます。初めて使用する場合は、次のように py ファイルのパラメーターを表示するか、コマンド ラインから表示できます。エクスポートするときは、opencv dnn バージョンに適応する適切な onnx opset バージョンを選択することに注意してください

(yolo_pytorch) E:\DeepLearning\yolov5>python export.py --weights yolov5x.pt --include onnx --opset 12
export: data=E:\DeepLearning\yolov5\data\coco128.yaml, weights=['yolov5x.pt'], imgsz=[640, 640], batch_size=1, device=cpu, half=False, inplace=False, keras=False, optimize=False, int8=False, dynamic=False, simplify=False, opset=12, verbose=False, workspace=4, nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45, conf_thres=0.25, include=['onnx']
YOLOv5  v7.0-167-g5deff14 Python-3.9.16 torch-1.13.1+cu117 CPU

Fusing layers...
YOLOv5x summary: 444 layers, 86705005 parameters, 0 gradients

PyTorch: starting from yolov5x.pt with output shape (1, 25200, 85) (166.0 MB)

ONNX: starting export with onnx 1.14.0...
ONNX: export success  10.0s, saved as yolov5x.onnx (331.2 MB)

Export complete (15.0s)
Results saved to E:\DeepLearning\yolov5
Detect:          python detect.py --weights yolov5x.onnx
Validate:        python val.py --weights yolov5x.onnx
PyTorch Hub:     model = torch.hub.load('ultralytics/yolov5', 'custom', 'yolov5x.onnx')
Visualize:       https://netron.app

2.2.2、opencv dnn C++ コードテスト

テーマのコードは yolov4 と同じですが、主な違いは次のとおりです。

  • 状況に応じて拡大縮小するか塗りつぶすかの前処理を実行して、サイズがネットワーク入力と一致するようにすることができます。formatToSquare()関数を参照してください。
  • 後処理コードのネットワーク出力のデータ処理に若干の調整が加えられています。

完全なコードは次のとおりです

#pragma once

#include "opencv2/opencv.hpp"

#include <fstream>
#include <sstream>
#include <random>

using namespace cv;
using namespace dnn;

 float inpWidth;
 float inpHeight;
 float confThreshold, scoreThreshold, nmsThreshold;
 std::vector<std::string> classes;
 std::vector<cv::Scalar> colors;

 bool letterBoxForSquare = true;

 cv::Mat formatToSquare(const cv::Mat &source);

 void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& out, Net& net);

 void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(100, 255);

int main()
{
    
    
    // 根据选择的检测模型文件进行配置 
    confThreshold = 0.25;
    scoreThreshold = 0.45;
    nmsThreshold = 0.5;
    float scale = 1/255.0;  //0.00392
    Scalar mean = {
    
    0,0,0};
    bool swapRB = true;
    inpWidth = 640;
    inpHeight = 640;

    String model_dir = R"(E:\DeepLearning\yolov5)";
    String modelPath = model_dir + R"(\yolov5n.onnx)";
    String configPath;

    String framework = "";
    int backendId = cv::dnn::DNN_BACKEND_CUDA;
    int targetId = cv::dnn::DNN_TARGET_CUDA;

    String classesFile = R"(model\object_detection_classes_yolov3.txt)";

    // Open file with classes names.
    if(!classesFile.empty()) {
    
    
        const std::string& file = classesFile;
        std::ifstream ifs(file.c_str());
        if(!ifs.is_open())
            CV_Error(Error::StsError, "File " + file + " not found");
        std::string line;
        while(std::getline(ifs, line)) {
    
    
            classes.push_back(line);
            colors.push_back(cv::Scalar(dis(gen), dis(gen), dis(gen)));
        }
    } 
    // Load a model.
    Net net = readNet(modelPath, configPath, framework);
    net.setPreferableBackend(backendId);
    net.setPreferableTarget(targetId);

    std::vector<String> outNames = net.getUnconnectedOutLayersNames();
    {
    
    
        int dims[] = {
    
    1,3,inpHeight,inpWidth};
        cv::Mat tmp = cv::Mat::zeros(4, dims, CV_32F);
        std::vector<cv::Mat> outs;

        net.setInput(tmp);
        for(int i = 0; i<10; i++)
            net.forward(outs, outNames); // warmup
    }

    // Create a window
    static const std::string kWinName = "Deep learning object detection in OpenCV";

    cv::namedWindow(kWinName, 0);

    // Open a video file or an image file or a camera stream.
    VideoCapture cap;
    //cap.open(0);
    cap.open(R"(E:\DeepLearning\yolov5\data\images\bus.jpg)");

    cv::TickMeter tk;
    // Process frames.
    Mat frame, blob;

    while(waitKey(1) < 0) {
    
    
        //tk.reset();
        //tk.start();

        cap >> frame;
        if(frame.empty()) {
    
    
            waitKey();
            break;
        }

        // Create a 4D blob from a frame.
        cv::Mat modelInput = frame;
        if(letterBoxForSquare && inpWidth == inpHeight)
            modelInput = formatToSquare(modelInput);
            
        blobFromImage(modelInput, blob, scale, cv::Size2f(inpWidth, inpHeight), mean, swapRB, false);

        // Run a model.
        net.setInput(blob);

        std::vector<Mat> outs;
        //tk.reset();
        //tk.start();

        auto tt1 = cv::getTickCount();
        net.forward(outs, outNames);
        auto tt2 = cv::getTickCount();

        tk.stop();
        postprocess(frame, modelInput.size(), outs, net);
        //tk.stop();

        // Put efficiency information.
        std::vector<double> layersTimes;
        double freq = getTickFrequency() / 1000;
        double t = net.getPerfProfile(layersTimes) / freq;
        std::string label = format("Inference time: %.2f ms  (%.2f ms)", t, /*tk.getTimeMilli()*/ (tt2 - tt1) / cv::getTickFrequency() * 1000);
        cv::putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));

        cv::imshow(kWinName, frame);
    }
    return 0;
}

cv::Mat formatToSquare(const cv::Mat &source)
{
    
    
    int col = source.cols;
    int row = source.rows;
    int _max = MAX(col, row);
    cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
    source.copyTo(result(cv::Rect(0, 0, col, row)));
    return result;
}

void postprocess(Mat& frame, cv::Size inputSz, const std::vector<Mat>& outs, Net& net)
{
    
    
    // yolov5 has an output of shape (batchSize, 25200, 85) (Num classes + box[x,y,w,h] + confidence[c])

    auto tt1 = cv::getTickCount();

    //float x_factor = frame.cols / inpWidth;
    //float y_factor = frame.rows / inpHeight;
    float x_factor = inputSz.width / inpWidth;
    float y_factor = inputSz.height / inpHeight;

    std::vector<int> class_ids;
    std::vector<float> confidences;
    std::vector<cv::Rect> boxes;

    int rows = outs[0].size[1];
    int dimensions = outs[0].size[2];

    float *data = (float *)outs[0].data;

    for(int i = 0; i < rows; ++i) {
    
    
        float confidence = data[4];

        if(confidence >= confThreshold) {
    
    
            float *classes_scores = data + 5;

            cv::Mat scores(1, classes.size(), CV_32FC1, classes_scores);
            cv::Point class_id;
            double max_class_score;

            minMaxLoc(scores, 0, &max_class_score, 0, &class_id);

            if(max_class_score > scoreThreshold) {
    
    
                confidences.push_back(confidence);
                class_ids.push_back(class_id.x);

                float x = data[0];
                float y = data[1];
                float w = data[2];
                float h = data[3];

                int left = int((x - 0.5 * w) * x_factor);
                int top = int((y - 0.5 * h) * y_factor);
                int width = int(w * x_factor);
                int height = int(h * y_factor);
               
                boxes.push_back(cv::Rect(left, top, width, height));
            }
        }

        data += dimensions;
    }

    std::vector<int> indices;
    NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, indices);
     
    auto tt2 = cv::getTickCount();
    std::string label = format("NMS time: %.2f ms",  (tt2 - tt1) / cv::getTickFrequency() * 1000);
    cv::putText(frame, label, Point(0, 30), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0));

    for(size_t i = 0; i < indices.size(); ++i) {
    
    
        int idx = indices[i];
        Rect box = boxes[idx];
        drawPred(class_ids[idx], confidences[idx], box.x, box.y,
                 box.x + box.width, box.y + box.height, frame);
    }
}

void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)
{
    
    
    rectangle(frame, Point(left, top), Point(right, bottom), Scalar(0, 255, 0));

    std::string label = format("%.2f", conf);
    Scalar color = Scalar::all(255);
    if(!classes.empty()) {
    
    
        CV_Assert(classId < (int)classes.size());
        label = classes[classId] + ": " + label;
        color = colors[classId];
    }

    int baseLine;
    Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

    top = max(top, labelSize.height);
    rectangle(frame, Point(left, top - labelSize.height),
              Point(left + labelSize.width, top + baseLine), color, FILLED);
    cv::putText(frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.5, Scalar());
}

2.2.3. テスト結果

前回の Python テストで GPU を使用した場合、前方推論には 10 ミリ秒、NMS には 4 ミリ秒かかりましたが、ここで opencv dnn を使用して dnn を開くと、前方推論には約 7 ミリ秒、NMS には約 0.3 ミリ秒かかりました。
ここに画像の説明を挿入します

3. カスタム データセットのトレーニング

ここでは、yolov5s を事前トレーニング モデルとして使用し、4 種類の車両タイプを含むターゲット検出モデルをトレーニングします。

3.1. データセットの準備

まず、自分で画像にラベルを付けます。たとえば、voc 形式を例として、ラベル付けには labelImg ツールを使用します。coco のデフォルトのラベル付けファイル形式は xml であり、スクリプトを通じて txt に変換する必要があります (さらに、 labelme ツールを直接使用して、yolo) で必要な txt 形式で直接保存します。

ここでは、フォルダーJPEGImagesとにのみ焦点を当てますlabels注釈が完了したら、画像と生成された注釈ファイルを任意のディレクトリに配置します。たとえばE:\DeepLearning\yolov5\custom-data\vehicle画像と注釈ファイルをそれぞれ画像フォルダーとラベル フォルダーに配置します(yolov5 のデフォルト パス。それ以外の場合は、yolov5 の img2label_paths 関数を変更する必要があります) /utils/dataloaders.py 2 つのパラメーター)。

vehicle
├── images
│   ├── 20151127_114556.jpg
│   ├── 20151127_114946.jpg
│   └── 20151127_115133.jpg
├── labels
│   ├── 20151127_114556.txt
│   ├── 20151127_114946.txt
│   └── 20151127_115133.txt

その後、訓練セット、検証セット、テストセット(オプション)のリストファイルtrain.txt、val.txt、test.txtを用意します(3つのファイルには画像の絶対パスが格納されており、比率は7:2:1 など、ランダムに選択されます。

3.2. 設定ファイル

data/coco.yaml ファイルと model/yolov5s.yaml ファイルをデータ セット ディレクトリにコピーし、変更を加えます。

たとえば、データセット説明ファイルmyvoc.yaml

train: E:/DeepLearning/yolov5/custom-data/vehicle/train.txt
val: E:/DeepLearning/yolov5/custom-data/vehicle/val.txt
 
# number of classes
nc: 4
 
# class names
names: ["car", "huoche", "guache", "keche"]

ネットワーク モデル構成ファイルは、yolov5s.yamlパラメーター nc をターゲット検出カテゴリの実際の数に変更するだけです。

# Parameters
nc: 4  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

3.3. トレーニング

前述したように、準備作業が完了した後のディレクトリ構造は次のとおりです。
ここに画像の説明を挿入しますその後、20 エポックをトレーニングします。シングル GPU トレーニングのスクリプトは次のとおりです。

python train.py
	 --weights yolov5s.pt 
	 --cfg custom-data\vehicle\yolov5s.yaml 
	 --data custom-data\vehicle\myvoc.yaml 
	 --epoch 20 
	 --batch-size=32 
	 --img 640 
	 --device 0

トレーニングの出力内容は、

E:\DeepLearning\yolov5>python train.py --weights yolov5s.pt --cfg custom-data\vehicle\yolov5s.yaml --data custom-data\vehicle\myvoc.yaml --epoch 20 --batch-size=32 --img 640 --device 0
train: weights=yolov5s.pt, cfg=custom-data\vehicle\yolov5s.yaml, data=custom-data\vehicle\myvoc.yaml, hyp=data\hyps\hyp.scratch-low.yaml, epochs=20, batch_size=32, imgsz=640, rect=False, resume=False, nosave=False, noval=False, noautoanchor=False, noplots=False, evolve=None, bucket=, cache=None, image_weights=False, device=0, multi_scale=False, single_cls=False, optimizer=SGD, sync_bn=False, workers=8, project=runs\train, name=exp, exist_ok=False, quad=False, cos_lr=False, label_smoothing=0.0, patience=100, freeze=[0], save_period=-1, seed=0, local_rank=-1, entity=None, upload_dataset=False, bbox_interval=-1, artifact_alias=latest
fatal: unable to access 'http://github.com/ultralytics/yolov5.git/': Recv failure: Connection was reset
Command 'git fetch origin' timed out after 5 seconds
YOLOv5  v7.0-167-g5deff14 Python-3.9.16 torch-1.13.1+cu117 CUDA:0 (NVIDIA GeForce GTX 1080 Ti, 11264MiB)

hyperparameters: lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0, copy_paste=0.0
Comet: run 'pip install comet_ml' to automatically track and visualize YOLOv5  runs in Comet
TensorBoard: Start with 'tensorboard --logdir runs\train', view at http://localhost:6006/

                 from  n    params  module                                  arguments
  0                -1  1      3520  models.common.Conv                      [3, 32, 6, 2, 2]
  1                -1  1     18560  models.common.Conv                      [32, 64, 3, 2]
  2                -1  1     18816  models.common.C3                        [64, 64, 1]
  3                -1  1     73984  models.common.Conv                      [64, 128, 3, 2]
  4                -1  2    115712  models.common.C3                        [128, 128, 2]
  5                -1  1    295424  models.common.Conv                      [128, 256, 3, 2]
  6                -1  3    625152  models.common.C3                        [256, 256, 3]
  7                -1  1   1180672  models.common.Conv                      [256, 512, 3, 2]
  8                -1  1   1182720  models.common.C3                        [512, 512, 1]
  9                -1  1    656896  models.common.SPPF                      [512, 512, 5]
 10                -1  1    131584  models.common.Conv                      [512, 256, 1, 1]
 11                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
 12           [-1, 6]  1         0  models.common.Concat                    [1]
 13                -1  1    361984  models.common.C3                        [512, 256, 1, False]
 14                -1  1     33024  models.common.Conv                      [256, 128, 1, 1]
 15                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
 16           [-1, 4]  1         0  models.common.Concat                    [1]
 17                -1  1     90880  models.common.C3                        [256, 128, 1, False]
 18                -1  1    147712  models.common.Conv                      [128, 128, 3, 2]
 19          [-1, 14]  1         0  models.common.Concat                    [1]
 20                -1  1    296448  models.common.C3                        [256, 256, 1, False]
 21                -1  1    590336  models.common.Conv                      [256, 256, 3, 2]
 22          [-1, 10]  1         0  models.common.Concat                    [1]
 23                -1  1   1182720  models.common.C3                        [512, 512, 1, False]
 24      [17, 20, 23]  1     24273  models.yolo.Detect                      [4, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]
YOLOv5s summary: 214 layers, 7030417 parameters, 7030417 gradients, 16.0 GFLOPs

Transferred 342/349 items from yolov5s.pt
AMP: checks passed
optimizer: SGD(lr=0.01) with parameter groups 57 weight(decay=0.0), 60 weight(decay=0.0005), 60 bias
train: Scanning E:\DeepLearning\yolov5\custom-data\vehicle\train... 998 images, 0 backgrounds, 0 corrupt: 100%|██████████| 998/998 [00:07<00:00, 141.97it/s]
train: New cache created: E:\DeepLearning\yolov5\custom-data\vehicle\train.cache
val: Scanning E:\DeepLearning\yolov5\custom-data\vehicle\val... 998 images, 0 backgrounds, 0 corrupt: 100%|██████████| 998/998 [00:13<00:00, 72.66it/s]
val: New cache created: E:\DeepLearning\yolov5\custom-data\vehicle\val.cache

AutoAnchor: 4.36 anchors/target, 1.000 Best Possible Recall (BPR). Current anchors are a good fit to dataset
Plotting labels to runs\train\exp13\labels.jpg...
Image sizes 640 train, 640 val
Using 8 dataloader workers
Logging results to runs\train\exp13
Starting training for 20 epochs...

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       0/19      6.36G    0.09633      0.038    0.03865         34        640: 100%|██████████| 32/32 [00:19<00:00,  1.66it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:11<00:00,  1.45it/s]
                   all        998       2353      0.884      0.174      0.248     0.0749

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       1/19       9.9G    0.06125    0.03181    0.02363         26        640: 100%|██████████| 32/32 [00:14<00:00,  2.18it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.50it/s]
                   all        998       2353      0.462      0.374       0.33      0.105

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       2/19       9.9G    0.06124    0.02353    0.02014         18        640: 100%|██████████| 32/32 [00:14<00:00,  2.22it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.58it/s]
                   all        998       2353      0.469      0.472      0.277      0.129

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       3/19       9.9G    0.05214    0.02038     0.0175         27        640: 100%|██████████| 32/32 [00:14<00:00,  2.22it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.56it/s]
                   all        998       2353       0.62       0.64      0.605      0.279

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       4/19       9.9G    0.04481    0.01777    0.01598         23        640: 100%|██████████| 32/32 [00:14<00:00,  2.17it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.60it/s]
                   all        998       2353      0.803      0.706      0.848      0.403

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       5/19       9.9G     0.0381    0.01624    0.01335         19        640: 100%|██████████| 32/32 [00:14<00:00,  2.16it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.55it/s]
                   all        998       2353      0.651      0.872        0.8      0.414

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       6/19       9.9G    0.03379    0.01534    0.01134         28        640: 100%|██████████| 32/32 [00:14<00:00,  2.18it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.58it/s]
                   all        998       2353       0.94      0.932      0.978      0.608

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       7/19       9.9G    0.03228    0.01523    0.00837         10        640: 100%|██████████| 32/32 [00:14<00:00,  2.21it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:09<00:00,  1.67it/s]
                   all        998       2353      0.862      0.932      0.956      0.591

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       8/19       9.9G     0.0292    0.01458   0.007451         20        640: 100%|██████████| 32/32 [00:14<00:00,  2.21it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.56it/s]
                   all        998       2353       0.97      0.954      0.986      0.658

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
       9/19       9.9G    0.02739    0.01407   0.006553         29        640: 100%|██████████| 32/32 [00:15<00:00,  2.12it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.58it/s]
                   all        998       2353      0.982      0.975      0.993       0.74

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      10/19       9.9G     0.0248    0.01362   0.005524         30        640: 100%|██████████| 32/32 [00:14<00:00,  2.14it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.55it/s]
                   all        998       2353      0.985      0.973      0.993      0.757

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      11/19       9.9G    0.02377    0.01271   0.005606         27        640: 100%|██████████| 32/32 [00:15<00:00,  2.13it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.52it/s]
                   all        998       2353      0.964      0.975      0.989      0.725

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      12/19       9.9G    0.02201    0.01247   0.005372         33        640: 100%|██████████| 32/32 [00:14<00:00,  2.19it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.57it/s]
                   all        998       2353      0.988      0.988      0.994       0.83

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      13/19       9.9G    0.02103    0.01193   0.004843         22        640: 100%|██████████| 32/32 [00:14<00:00,  2.14it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.57it/s]
                   all        998       2353      0.981      0.987      0.994      0.817

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      14/19       9.9G    0.02017    0.01167    0.00431         22        640: 100%|██████████| 32/32 [00:14<00:00,  2.20it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:09<00:00,  1.60it/s]
                   all        998       2353       0.96      0.952      0.987      0.782

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      15/19       9.9G    0.01847    0.01158   0.004043         32        640: 100%|██████████| 32/32 [00:14<00:00,  2.20it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.56it/s]
                   all        998       2353      0.988      0.992      0.994      0.819

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      16/19       9.9G    0.01771     0.0114   0.003859         24        640: 100%|██████████| 32/32 [00:14<00:00,  2.20it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.55it/s]
                   all        998       2353      0.967       0.96       0.99      0.832

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      17/19       9.9G    0.01665    0.01077   0.003739         32        640: 100%|██████████| 32/32 [00:14<00:00,  2.22it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.59it/s]
                   all        998       2353      0.992      0.995      0.994       0.87

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      18/19       9.9G    0.01559    0.01067   0.003549         45        640: 100%|██████████| 32/32 [00:14<00:00,  2.21it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:10<00:00,  1.53it/s]
                   all        998       2353      0.991      0.995      0.995      0.867

      Epoch    GPU_mem   box_loss   obj_loss   cls_loss  Instances       Size
      19/19       9.9G    0.01459    0.01009   0.003031         31        640: 100%|██████████| 32/32 [00:14<00:00,  2.18it/s]
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:11<00:00,  1.42it/s]
                   all        998       2353      0.994      0.995      0.994      0.885

20 epochs completed in 0.143 hours.
Optimizer stripped from runs\train\exp13\weights\last.pt, 14.4MB
Optimizer stripped from runs\train\exp13\weights\best.pt, 14.4MB

Validating runs\train\exp13\weights\best.pt...
Fusing layers...
YOLOv5s summary: 157 layers, 7020913 parameters, 0 gradients, 15.8 GFLOPs
                 Class     Images  Instances          P          R      mAP50   mAP50-95: 100%|██████████| 16/16 [00:11<00:00,  1.37it/s]
                   all        998       2353      0.994      0.995      0.994      0.885
                   car        998       1309      0.995      0.999      0.995      0.902
                huoche        998        507      0.993      0.988      0.994      0.895
                guache        998        340      0.988      0.993      0.994      0.877
                 keche        998        197      0.999          1      0.995      0.866
Results saved to runs\train\exp13

トレーニング プロセス中に、テンソルボードを使用してトレーニング カーブを視覚的に表示できます。yolov5 ディレクトリで開始しtensorboard --logdir runs\trainhttp://localhost:6006/アクセスして表示します。
ここに画像の説明を挿入します
トレーニング速度は非常に速く、998 枚の画像があり、20epoc のトレーニングにかかる​​時間はわずか約 8 分です。トレーニング保存モデルはruns\train\exp13ディレクトリに保存されます。

その他の関連スクリーンショット

結果.png

train_batch1.jpg
スクリプトを使用してpython detect.py --weights runs\train\exp13\weights\best.pt --source custom-data\vehicle\images\11.jpg次の
ここに画像の説明を挿入します
結果グラフをテストします。
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/wanggao_1990/article/details/132758180