記事ディレクトリ
- 1.Yolo v5とYolo v4の違いの説明
- 2.yolo v5テスト
- 3. カスタム データセットのトレーニング
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\train
、http://localhost:6006/
アクセスして表示します。
トレーニング速度は非常に速く、998 枚の画像があり、20epoc のトレーニングにかかる時間はわずか約 8 分です。トレーニング保存モデルはruns\train\exp13
ディレクトリに保存されます。
その他の関連スクリーンショット
スクリプトを使用してpython detect.py --weights runs\train\exp13\weights\best.pt --source custom-data\vehicle\images\11.jpg
次の
結果グラフをテストします。