YOLOv7: Trainierbare Bag-of-Freebies
YOLOv7 ist ein hochmoderner Echtzeit-Objektdetektor, der alle bekannten Objektdetektoren in Bezug auf Geschwindigkeit und Genauigkeit im Bereich von 5 FPS bis 160 FPS übertrifft. Es hat die höchste Genauigkeit (56,8 % AP) unter allen bekannten Echtzeit-Objektdetektoren mit 30 FPS oder höher auf der GPU V100. Darüber hinaus übertrifft YOLOv7 andere Objektdetektoren wie YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5 und viele andere in Bezug auf Geschwindigkeit und Genauigkeit. Das Modell wird auf dem MS COCO-Datensatz von Grund auf trainiert, ohne andere Datensätze oder vortrainierte Gewichte zu verwenden. Der Quellcode für YOLOv7 ist auf GitHub verfügbar.
Vergleich von SOTA-Objektdetektoren
Aus den Ergebnissen in der YOLO-Vergleichstabelle geht hervor, dass die vorgeschlagene Methode umfassend den besten Kompromiss zwischen Geschwindigkeit und Genauigkeit bietet. Wenn wir YOLOv7-tiny-SiLU mit YOLOv5-N (r6.1) vergleichen, ist unsere Methode 127 fps schneller und 10,7 % genauer in Bezug auf AP. Darüber hinaus erreicht YOLOv7 51,4 % AP bei einer Bildrate von 161 fps, während PPYOLOE-L mit der gleichen AP nur eine Bildrate von 78 fps erreicht. In Bezug auf die Parameternutzung ist YOLOv7 41 % geringer als PPYOLOE-L.
Wenn wir YOLOv7-X mit einer Inferenzgeschwindigkeit von 114 fps mit YOLOv5-L (r6.1) mit einer Inferenzgeschwindigkeit von 99 fps vergleichen, kann YOLOv7-X die AP um 3,9 % verbessern. Wenn YOLOv7-X mit YOLOv5-X (r6.1) ähnlicher Größenordnung verglichen wird, ist die Inferenzgeschwindigkeit von YOLOv7-X 31 fps schneller. Darüber hinaus reduziert YOLOv7-X in Bezug auf die Anzahl der Parameter und die Berechnung 22 % der Parameter und 8 % der Berechnung im Vergleich zu YOLOv5-X (r6.1), verbessert aber die AP um 2,2 % (Quelle).
Performance
Modell | Parameter (M) |
FLOPs (G) |
Größe (Pixel) |
FPS | APTest / Val 50-95 |
APTest 50 |
APTest 75 |
APTest S |
APTest M |
APTest L |
---|---|---|---|---|---|---|---|---|---|---|
YOLOX-S | 9.0 | 26.8 | 640 | 102 | 40,5 % / 40,5 % | - | - | - | - | - |
YOLOX-M | 25.3 | 73.8 | 640 | 81 | 47,2 % / 46,9 % | - | - | - | - | - |
YOLOX-L | 54.2 | 155.6 | 640 | 69 | 50,1% / 49,7% | - | - | - | - | - |
YOLOX-X | 99.1 | 281.9 | 640 | 58 | 51,5% / 51,1% | - | - | - | - | - |
PPYOLOE-S | 7.9 | 17.4 | 640 | 208 | 43,1 % / 42,7 % | 60.5% | 46.6% | 23.2% | 46.4% | 56.9% |
PPYOLOE-M | 23.4 | 49.9 | 640 | 123 | 48,9 % / 48,6 % | 66.5% | 53.0% | 28.6% | 52.9% | 63.8% |
PPYOLOE-L | 52.2 | 110.1 | 640 | 78 | 51,4% / 50,9% | 68.9% | 55.6% | 31.4% | 55.3% | 66.1% |
PPYOLOE-X | 98.4 | 206.6 | 640 | 45 | 52,2% / 51,9% | 69.9% | 56.5% | 33.3% | 56.3% | 66.4% |
YOLOv5-N (r6.1) | 1.9 | 4.5 | 640 | 159 | - / 28.0% | - | - | - | - | - |
YOLOv5-S (r6.1) | 7.2 | 16.5 | 640 | 156 | - / 37.4% | - | - | - | - | - |
YOLOv5-M (r6.1) | 21.2 | 49.0 | 640 | 122 | - / 45.4% | - | - | - | - | - |
YOLOv5-L (r6.1) | 46.5 | 109.1 | 640 | 99 | - / 49.0% | - | - | - | - | - |
YOLOv5-X (r6.1) | 86.7 | 205.7 | 640 | 83 | - / 50,7% | - | - | - | - | - |
YOLOR-CSP | 52.9 | 120.4 | 640 | 106 | 51,1% / 50,8% | 69.6% | 55.7% | 31.7% | 55.3% | 64.7% |
YOLOR-CSP-X | 96.9 | 226.8 | 640 | 87 | 53,0% / 52,7% | 71.4% | 57.9% | 33.7% | 57.1% | 66.8% |
YOLOv7-tiny-SiLU | 6.2 | 13.8 | 640 | 286 | 38.7% / 38.7% | 56.7% | 41.7% | 18.8% | 42.4% | 51.9% |
YOLOv7 | 36.9 | 104.7 | 640 | 161 | 51,4% / 51,2% | 69.7% | 55.9% | 31.8% | 55.5% | 65.0% |
YOLOv7-X | 71.3 | 189.9 | 640 | 114 | 53,1% / 52,9% | 71.2% | 57.8% | 33.8% | 57.1% | 67.4% |
YOLOv5-N6 (r6.1) | 3.2 | 18.4 | 1280 | 123 | - / 36.0% | - | - | - | - | - |
YOLOv5-S6 (r6.1) | 12.6 | 67.2 | 1280 | 122 | - / 44.8% | - | - | - | - | - |
YOLOv5-M6 (r6.1) | 35.7 | 200.0 | 1280 | 90 | - / 51.3% | - | - | - | - | - |
YOLOv5-L6 (r6.1) | 76.8 | 445.6 | 1280 | 63 | - / 53,7% | - | - | - | - | - |
YOLOv5-X6 (r6.1) | 140.7 | 839.2 | 1280 | 38 | - / 55,0% | - | - | - | - | - |
YOLOR-P6 | 37.2 | 325.6 | 1280 | 76 | 53,9% / 53,5% | 71.4% | 58.9% | 36.1% | 57.7% | 65.6% |
YOLOR-W6 | 79.8 | 453.2 | 1280 | 66 | 55,2% / 54,8% | 72.7% | 60.5% | 37.7% | 59.1% | 67.1% |
YOLOR-E6 | 115.8 | 683.2 | 1280 | 45 | 55,8% / 55,7% | 73.4% | 61.1% | 38.4% | 59.7% | 67.7% |
YOLOR-D6 | 151.7 | 935.6 | 1280 | 34 | 56,5% / 56,1% | 74.1% | 61.9% | 38.9% | 60.4% | 68.7% |
YOLOv7-W6 | 70.4 | 360.0 | 1280 | 84 | 54,9% / 54,6% | 72.6% | 60.1% | 37.3% | 58.7% | 67.1% |
YOLOv7-E6 | 97.2 | 515.2 | 1280 | 56 | 56,0% / 55,9% | 73.5% | 61.2% | 38.0% | 59.9% | 68.4% |
YOLOv7-D6 | 154.7 | 806.8 | 1280 | 44 | 56,6% / 56,3% | 74.0% | 61.8% | 38.8% | 60.1% | 69.5% |
YOLOv7-E6E | 151.7 | 843.2 | 1280 | 36 | 56,8% / 56,8% | 74.4% | 62.1% | 39.3% | 60.5% | 69.0% |
Überblick
Echtzeit-Objekterkennung ist eine wichtige Komponente in vielen Computer-Vision-Systemen, einschließlich Multi-Objektverfolgung, autonomem Fahren, Robotik und medizinischer Bildanalyse. In den letzten Jahren hat sich die Entwicklung der Echtzeit-Objekterkennung auf die Entwicklung effizienter Architekturen und die Verbesserung der Inferenzgeschwindigkeit verschiedener CPUs, GPUs und neuronaler Verarbeitungseinheiten (NPUs) konzentriert. YOLOv7 unterstützt sowohl mobile GPU- als auch GPU-Geräte, vom Edge bis zur Cloud.
Im Gegensatz zu herkömmlichen Echtzeit-Objektdetektoren, die sich auf die Architekturoptimierung konzentrieren, legt YOLOv7 den Schwerpunkt auf die Optimierung des Trainingsprozesses. Dazu gehören Module und Optimierungsmethoden, die entwickelt wurden, um die Genauigkeit der Objekterkennung zu verbessern, ohne die Inferenzkosten zu erhöhen, ein Konzept, das als "trainierbare Freebies" bekannt ist.
Hauptmerkmale
YOLOv7 führt mehrere Hauptmerkmale ein:
-
Modell-Re-Parametrisierung: YOLOv7 schlägt ein geplantes, reparametrisiertes Modell vor, eine Strategie, die auf Schichten in verschiedenen Netzwerken mit dem Konzept des Gradienten-Propagierungspfads anwendbar ist.
-
Dynamische Label-Zuweisung: Das Training des Modells mit mehreren Ausgabeschichten stellt ein neues Problem dar: "Wie weist man dynamische Ziele für die Ausgaben verschiedener Zweige zu?" Um dieses Problem zu lösen, führt YOLOv7 eine neue Methode zur Label-Zuweisung ein, die als "Coarse-to-Fine Lead Guided Label Assignment" bezeichnet wird.
-
Erweiterte und kombinierte Skalierung: YOLOv7 schlägt "Extend"- und "Compound Scaling"-Methoden für den Echtzeit-Objektdetektor vor, die Parameter und Berechnungen effektiv nutzen können.
-
Effizienz: Die von YOLOv7 vorgeschlagene Methode kann die Parameter um etwa 40 % und die Berechnungen von hochmodernen Echtzeit-Objektdetektoren um 50 % effektiv reduzieren und bietet eine schnellere Inferenzgeschwindigkeit und eine höhere Erkennungsgenauigkeit.
Anwendungsbeispiele
Zum Zeitpunkt des Verfassens unterstützt Ultralytics nur ONNX- und TensorRT-Inferenz für YOLOv7.
ONNX-Export
So verwenden Sie das YOLOv7 ONNX-Modell mit Ultralytics:
-
(Optional) Installieren Sie Ultralytics und exportieren Sie ein ONNX-Modell, damit die erforderlichen Abhängigkeiten automatisch installiert werden:
pip install ultralytics yolo export model=yolo11n.pt format=onnx
-
Exportieren Sie das gewünschte YOLOv7-Modell, indem Sie den Exporteur im YOLOv7 Repo verwenden:
git clone https://github.com/WongKinYiu/yolov7 cd yolov7 python export.py --weights yolov7-tiny.pt --grid --end2end --simplify --topk-all 100 --iou-thres 0.65 --conf-thres 0.35 --img-size 640 640 --max-wh 640
-
Ändern Sie den ONNX-Modellgraphen mit dem folgenden Skript, um ihn mit Ultralytics kompatibel zu machen:
import numpy as np import onnx from onnx import helper, numpy_helper # Load the ONNX model model_path = "yolov7/yolov7-tiny.onnx" # Replace with your model path model = onnx.load(model_path) graph = model.graph # Fix input shape to batch size 1 input_shape = graph.input[0].type.tensor_type.shape input_shape.dim[0].dim_value = 1 # Define the output of the original model original_output_name = graph.output[0].name # Create slicing nodes sliced_output_name = f"{original_output_name}_sliced" # Define initializers for slicing (remove the first value) start = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_start") end = numpy_helper.from_array(np.array([7], dtype=np.int64), name="slice_end") axes = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_axes") steps = numpy_helper.from_array(np.array([1], dtype=np.int64), name="slice_steps") graph.initializer.extend([start, end, axes, steps]) slice_node = helper.make_node( "Slice", inputs=[original_output_name, "slice_start", "slice_end", "slice_axes", "slice_steps"], outputs=[sliced_output_name], name="SliceNode", ) graph.node.append(slice_node) # Define segment slicing seg1_start = numpy_helper.from_array(np.array([0], dtype=np.int64), name="seg1_start") seg1_end = numpy_helper.from_array(np.array([4], dtype=np.int64), name="seg1_end") seg2_start = numpy_helper.from_array(np.array([4], dtype=np.int64), name="seg2_start") seg2_end = numpy_helper.from_array(np.array([5], dtype=np.int64), name="seg2_end") seg3_start = numpy_helper.from_array(np.array([5], dtype=np.int64), name="seg3_start") seg3_end = numpy_helper.from_array(np.array([6], dtype=np.int64), name="seg3_end") graph.initializer.extend([seg1_start, seg1_end, seg2_start, seg2_end, seg3_start, seg3_end]) # Create intermediate tensors for segments segment_1_name = f"{sliced_output_name}_segment1" segment_2_name = f"{sliced_output_name}_segment2" segment_3_name = f"{sliced_output_name}_segment3" # Add segment slicing nodes graph.node.extend( [ helper.make_node( "Slice", inputs=[sliced_output_name, "seg1_start", "seg1_end", "slice_axes", "slice_steps"], outputs=[segment_1_name], name="SliceSegment1", ), helper.make_node( "Slice", inputs=[sliced_output_name, "seg2_start", "seg2_end", "slice_axes", "slice_steps"], outputs=[segment_2_name], name="SliceSegment2", ), helper.make_node( "Slice", inputs=[sliced_output_name, "seg3_start", "seg3_end", "slice_axes", "slice_steps"], outputs=[segment_3_name], name="SliceSegment3", ), ] ) # Concatenate the segments concat_output_name = f"{sliced_output_name}_concat" concat_node = helper.make_node( "Concat", inputs=[segment_1_name, segment_3_name, segment_2_name], outputs=[concat_output_name], axis=1, name="ConcatSwapped", ) graph.node.append(concat_node) # Reshape to [1, -1, 6] reshape_shape = numpy_helper.from_array(np.array([1, -1, 6], dtype=np.int64), name="reshape_shape") graph.initializer.append(reshape_shape) final_output_name = f"{concat_output_name}_batched" reshape_node = helper.make_node( "Reshape", inputs=[concat_output_name, "reshape_shape"], outputs=[final_output_name], name="AddBatchDimension", ) graph.node.append(reshape_node) # Get the shape of the reshaped tensor shape_node_name = f"{final_output_name}_shape" shape_node = helper.make_node( "Shape", inputs=[final_output_name], outputs=[shape_node_name], name="GetShapeDim", ) graph.node.append(shape_node) # Extract the second dimension dim_1_index = numpy_helper.from_array(np.array([1], dtype=np.int64), name="dim_1_index") graph.initializer.append(dim_1_index) second_dim_name = f"{final_output_name}_dim1" gather_node = helper.make_node( "Gather", inputs=[shape_node_name, "dim_1_index"], outputs=[second_dim_name], name="GatherSecondDim", ) graph.node.append(gather_node) # Subtract from 100 to determine how many values to pad target_size = numpy_helper.from_array(np.array([100], dtype=np.int64), name="target_size") graph.initializer.append(target_size) pad_size_name = f"{second_dim_name}_padsize" sub_node = helper.make_node( "Sub", inputs=["target_size", second_dim_name], outputs=[pad_size_name], name="CalculatePadSize", ) graph.node.append(sub_node) # Build the [2, 3] pad array: # 1st row -> [0, 0, 0] (no padding at the start of any dim) # 2nd row -> [0, pad_size, 0] (pad only at the end of the second dim) pad_starts = numpy_helper.from_array(np.array([0, 0, 0], dtype=np.int64), name="pad_starts") graph.initializer.append(pad_starts) zero_scalar = numpy_helper.from_array(np.array([0], dtype=np.int64), name="zero_scalar") graph.initializer.append(zero_scalar) pad_ends_name = "pad_ends" concat_pad_ends_node = helper.make_node( "Concat", inputs=["zero_scalar", pad_size_name, "zero_scalar"], outputs=[pad_ends_name], axis=0, name="ConcatPadEnds", ) graph.node.append(concat_pad_ends_node) pad_values_name = "pad_values" concat_pad_node = helper.make_node( "Concat", inputs=["pad_starts", pad_ends_name], outputs=[pad_values_name], axis=0, name="ConcatPadStartsEnds", ) graph.node.append(concat_pad_node) # Create Pad operator to pad with zeros pad_output_name = f"{final_output_name}_padded" pad_constant_value = numpy_helper.from_array( np.array([0.0], dtype=np.float32), name="pad_constant_value", ) graph.initializer.append(pad_constant_value) pad_node = helper.make_node( "Pad", inputs=[final_output_name, pad_values_name, "pad_constant_value"], outputs=[pad_output_name], mode="constant", name="PadToFixedSize", ) graph.node.append(pad_node) # Update the graph's final output to [1, 100, 6] new_output_type = onnx.helper.make_tensor_type_proto( elem_type=graph.output[0].type.tensor_type.elem_type, shape=[1, 100, 6] ) new_output = onnx.helper.make_value_info(name=pad_output_name, type_proto=new_output_type) # Replace the old output with the new one graph.output.pop() graph.output.extend([new_output]) # Save the modified model onnx.save(model, "yolov7-ultralytics.onnx")
-
Sie können dann das modifizierte ONNX-Modell laden und damit in Ultralytics normal Inferenz ausführen:
from ultralytics import ASSETS, YOLO model = YOLO("yolov7-ultralytics.onnx", task="detect") results = model(ASSETS / "bus.jpg")
TensorRT-Export
-
Führen Sie die Schritte 1-2 im Abschnitt ONNX-Export aus.
-
Installieren Sie das
TensorRT
Python-Paket:pip install tensorrt
-
Führen Sie das folgende Skript aus, um das modifizierte ONNX-Modell in eine TensorRT-Engine zu konvertieren:
from ultralytics.utils.export import export_engine export_engine("yolov7-ultralytics.onnx", half=True)
-
Laden und Ausführen des Modells in Ultralytics:
from ultralytics import ASSETS, YOLO model = YOLO("yolov7-ultralytics.engine", task="detect") results = model(ASSETS / "bus.jpg")
Zitate und Danksagungen
Wir möchten die YOLOv7-Autoren für ihre bedeutenden Beiträge im Bereich der Echtzeit-Objekterkennung würdigen:
@article{wang2022yolov7,
title={YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors},
author={Wang, Chien-Yao and Bochkovskiy, Alexey and Liao, Hong-Yuan Mark},
journal={arXiv preprint arXiv:2207.02696},
year={2022}
}
Das Original YOLOv7 Paper ist auf arXiv zu finden. Die Autoren haben ihre Arbeit öffentlich zugänglich gemacht, und der Code ist auf GitHub verfügbar. Wir schätzen ihre Bemühungen, das Feld voranzutreiben und ihre Arbeit der breiteren Community zugänglich zu machen.
FAQ
Was ist YOLOv7 und warum gilt es als Durchbruch in der Echtzeit-Objekterkennung?
YOLOv7 ist ein hochmodernes Echtzeit-Objektdektionsmodell, das eine beispiellose Geschwindigkeit und Genauigkeit erreicht. Es übertrifft andere Modelle wie YOLOX, YOLOv5 und PPYOLOE sowohl in der Parameternutzung als auch in der Inferenzgeschwindigkeit. Zu den Unterscheidungsmerkmalen von YOLOv7 gehören seine Modellreparametrisierung und die dynamische Labelzuweisung, die seine Leistung optimieren, ohne die Inferenzkosten zu erhöhen. Weitere technische Details über seine Architektur und Vergleichsmetriken mit anderen State-of-the-Art-Objektdetektoren finden Sie im YOLOv7-Paper.
Wie verbessert YOLOv7 die vorherigen YOLO-Modelle wie YOLOv4 und YOLOv5?
YOLOv7 führt mehrere Innovationen ein, darunter Modellreparametrisierung und dynamische Labelzuweisung, die den Trainingsprozess verbessern und die Inferenzgenauigkeit erhöhen. Im Vergleich zu YOLOv5 steigert YOLOv7 Geschwindigkeit und Genauigkeit deutlich. So verbessert YOLOv7-X beispielsweise die Genauigkeit um 2,2 % und reduziert die Parameter um 22 % im Vergleich zu YOLOv5-X. Detaillierte Vergleiche finden Sie in der Performance-Tabelle YOLOv7 Vergleich mit SOTA-Objektdetektoren.
Kann ich YOLOv7 mit Ultralytics-Tools und -Plattformen verwenden?
Derzeit unterstützt Ultralytics nur YOLOv7 ONNX- und TensorRT-Inferenz. Um die exportierte ONNX- und TensorRT-Version von YOLOv7 mit Ultralytics auszuführen, überprüfen Sie den Abschnitt Anwendungsbeispiele.
Wie trainiere ich ein benutzerdefiniertes YOLOv7-Modell mit meinem Datensatz?
Um ein benutzerdefiniertes YOLOv7-Modell zu installieren und zu trainieren, führen Sie die folgenden Schritte aus:
- Klonen Sie das YOLOv7-Repository:
git clone https://github.com/WongKinYiu/yolov7
- Navigieren Sie zum geklonten Verzeichnis und installieren Sie die Abhängigkeiten:
cd yolov7 pip install -r requirements.txt
-
Bereiten Sie Ihren Datensatz vor und konfigurieren Sie die Modellparameter gemäß den Gebrauchsanweisungen, die im Repository bereitgestellt werden. Für weitere Anleitungen besuchen Sie das YOLOv7 GitHub-Repository für die neuesten Informationen und Updates.
-
Nach dem Training können Sie das Modell nach ONNX oder TensorRT exportieren, um es in Ultralytics zu verwenden, wie in den Anwendungsbeispielen gezeigt.
Welche wichtigen Funktionen und Optimierungen wurden in YOLOv7 eingeführt?
YOLOv7 bietet mehrere Schlüsselfunktionen, die die Echtzeit-Objekterkennung revolutionieren:
- Modell-Re-Parametrisierung: Verbessert die Leistung des Modells durch Optimierung der Gradienten-Propagierungswege.
- Dynamische Label-Zuweisung: Verwendet eine "Coarse-to-Fine Lead Guided"-Methode, um dynamische Ziele für Ausgaben über verschiedene Zweige hinweg zuzuweisen, wodurch die Genauigkeit verbessert wird.
- Erweiterte und kombinierte Skalierung: Nutzt Parameter und Berechnungen effizient, um das Modell für verschiedene Echtzeitanwendungen zu skalieren.
- Effizienz: Reduziert die Anzahl der Parameter um 40 % und die Berechnungen um 50 % im Vergleich zu anderen State-of-the-Art-Modellen und erzielt gleichzeitig schnellere Inferenzgeschwindigkeiten.
Weitere Informationen zu diesen Funktionen finden Sie im Abschnitt YOLOv7 – Übersicht.