YOLOv7: Trainable Bag-of-Freebies#
YOLOv7, im Juli 2022 veröffentlicht, war zum Zeitpunkt seiner Veröffentlichung ein bedeutender Fortschritt in der Echtzeit-Objekterkennung. Es erreichte 56,8 % AP auf einer GPU V100 und setzte bei seiner Einführung neue Maßstäbe. YOLOv7 übertraf zeitgenössische Objektdetektoren wie YOLOX, YOLOX, Scaled-YOLOv4 und YOLOv5 in Bezug auf Geschwindigkeit und Genauigkeit. Das Modell wird von Grund auf auf dem MS COCO-Datensatz trainiert, ohne andere Datensätze oder vortrainierte Gewichte zu verwenden. Der Quellcode für YOLOv7 ist auf GitHub verfügbar. Beachte, dass neuere Modelle wie YOLO11 und YOLO26 inzwischen eine höhere Genauigkeit bei verbesserter Effizienz erreicht haben.

Vergleich von SOTA Objektdetektoren#
Aus den Ergebnissen in der YOLO Vergleichstabelle wissen wir, dass die vorgeschlagene Methode umfassend das beste Verhältnis zwischen Geschwindigkeit und Genauigkeit aufweist. Wenn wir YOLOv7-tiny-SiLU mit YOLOv5-N (r6.1) vergleichen, ist unsere Methode um 127 fps schneller und um 10,7 % genauer beim AP. Zudem erreicht YOLOv7 51,4 % AP bei einer Bildrate von 161 fps, während PPYOLOE-L bei gleichem AP nur eine Bildrate von 78 fps aufweist. In Bezug auf die Parameternutzung liegt YOLOv7 um 41 % unter dem von 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 den AP um 3,9 % verbessern. Wenn YOLOv7-X mit YOLOv5-X (r6.1) ähnlicher Größe verglichen wird, ist die Inferenzgeschwindigkeit von YOLOv7-X um 31 fps höher. Darüber hinaus reduziert YOLOv7-X im Vergleich zu YOLOv5-X (r6.1) hinsichtlich der Anzahl der Parameter und der Rechenleistung 22 % der Parameter und 8 % der Rechenleistung, verbessert jedoch den AP um 2,2 % (Quelle).
| 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% |
Übersicht#
Echtzeit-Objekterkennung ist eine wichtige Komponente in vielen Computer Vision-Systemen, einschließlich Multi-Objektverfolgung, autonomem Fahren, Robotik und medizinscher Bildanalyse. In den letzten Jahren hat sich die Entwicklung der Echtzeit-Objekterkennung auf das Entwerfen 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, von der Edge bis zur Cloud.
Im Gegensatz zu herkömmlichen Echtzeit-Objekterkennungsmodellen, die sich auf die Architekturoptimierung konzentrieren, legt YOLOv7 den Fokus auf die Optimierung des Trainingsprozesses. Dies beinhaltet Module und Optimierungsmethoden, die darauf ausgelegt sind, die Genauigkeit der Objekterkennung zu verbessern, ohne die Inferenzkosten zu erhöhen – ein Konzept, das als "trainable bag-of-freebies" bekannt ist.
Hauptfunktionen#
YOLOv7 führt mehrere wichtige Funktionen ein:
-
Modell-Reparametrisierung: YOLOv7 schlägt ein geplantes reparametrisiertes Modell vor, eine Strategie, die auf Schichten in verschiedenen Netzwerken mit dem Konzept des Gradienten-Propagationspfads anwendbar ist.
-
Dynamische Label-Zuweisung: Das Training des Modells mit mehreren Ausgabeschichten bringt ein neues Problem mit sich: "Wie weist man dynamische Ziele für die Ausgaben verschiedener Zweige zu?" Um dieses Problem zu lösen, führt YOLOv7 eine neue Methode der Label-Zuweisung ein, die als "coarse-to-fine lead guided label assignment" bezeichnet wird.
-
Erweiterte und zusammengesetzte Skalierung: YOLOv7 schlägt "Extend"- und "Compound Scaling"-Methoden für den Echtzeit-Objekterkennungs-Algorithmus vor, die Parameter und Rechenleistung effektiv nutzen können.
-
Effizienz: Die von YOLOv7 vorgeschlagene Methode kann die Anzahl der Parameter um etwa 40 % und den Rechenaufwand um 50 % gegenüber modernsten Echtzeit-Objekterkennungsmodellen reduzieren und bietet gleichzeitig eine schnellere Inferenzgeschwindigkeit sowie eine höhere Erkennungsgenauigkeit.
Anwendungsbeispiele#
Ultralytics veröffentlicht keine vortrainierten yolov7.pt-Gewichte oder ultralytics/cfg/models/v7/-YAMLs, und das native PyTorch-Training sowie die Inferenz für YOLOv7 werden vom Ultralytics Python-Paket nicht unterstützt. Du kannst jedoch einen YOLOv7-Checkpoint, der im Upstream YOLOv7-Repository trainiert wurde, in Ultralytics einbinden, indem du ihn nach ONNX oder TensorRT exportierst, wie unten gezeigt.
ONNX-Export#
Um das YOLOv7 ONNX-Modell mit Ultralytics zu verwenden:
-
(Optional) Installiere Ultralytics und exportiere ein ONNX-Modell, damit die erforderlichen Abhängigkeiten automatisch installiert werden:
pip install ultralytics yolo export model=yolo26n.pt format=onnx -
Exportiere das gewünschte YOLOv7-Modell mit dem Exporter im YOLOv7-Repo:
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 -
Ändere den ONNX-Modellgraphen, um ihn mit dem folgenden Skript 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") -
Du kannst anschließend das geänderte ONNX-Modell laden und die Inferenz wie gewohnt in Ultralytics ausführen:
from ultralytics import ASSETS, YOLO model = YOLO("yolov7-ultralytics.onnx", task="detect") results = model(ASSETS / "bus.jpg")
TensorRT-Export#
-
folge den Schritten 1-2 im Abschnitt ONNX-Export.
-
Installiere das
TensorRTPython-Paket:pip install tensorrt -
Führe das folgende Skript aus, um das geänderte ONNX-Modell in eine TensorRT-Engine zu konvertieren:
from ultralytics.utils.export import export_engine export_engine("yolov7-ultralytics.onnx", half=True) -
Lade das Modell und führe es in Ultralytics aus:
from ultralytics import ASSETS, YOLO model = YOLO("yolov7-ultralytics.engine", task="detect") results = model(ASSETS / "bus.jpg")
Zitate und Danksagungen#
Wir möchten den Autoren von YOLOv7 für ihre bedeutenden Beiträge im Bereich der Echtzeit-Objekterkennung danken:
@inproceedings{wang2023yolov7,
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},
booktitle={Proceedings of the IEEE/CVF conference on Computer Vision and Pattern Recognition (CVPR)},
pages={7464--7475},
year={2023}
}Das offizielle YOLOv7-Paper wurde im CVF 2023 Open Access veröffentlicht, mit einem Preprint auf arXiv. Die Autoren haben ihre Arbeit öffentlich zugänglich gemacht, und auf die Codebasis kann auf GitHub zugegriffen werden. Wir schätzen ihre Bemühungen, das Feld voranzubringen und ihre Arbeit der breiteren Community zugänglich zu machen.
FAQ#
Was ist YOLOv7 und warum gilt es als Durchbruch bei der Echtzeit-Objekterkennung?#
YOLOv7, im Juli 2022 veröffentlicht, war ein bedeutendes Echtzeit-Objekterkennungsmodell, das zum Zeitpunkt seiner Veröffentlichung eine hervorragende Geschwindigkeit und Genauigkeit erreichte. Es übertraf zeitgenössische Modelle wie YOLOX, YOLOv5 und PPYOLOE sowohl bei der Parameternutzung als auch bei der Inferenzgeschwindigkeit. Zu den herausragenden Merkmalen von YOLOv7 gehören die Modell-Reparametrisierung und die dynamische Label-Zuweisung, die seine Leistung optimieren, ohne die Inferenzkosten zu erhöhen. Weitere technische Details zu seiner Architektur und Vergleichsmetriken mit anderen hochmodernen Objektdetektoren findest du im YOLOv7-Paper.
Wie verbessert YOLOv7 die vorherigen YOLO-Modelle wie YOLOv4 und YOLOv5?#
YOLOv7 führt mehrere Innovationen ein, darunter Modell-Reparametrisierung und dynamische Label-Zuweisung, die den Trainingsprozess verbessern und die Inferenzgenauigkeit erhöhen. Verglichen mit YOLOv5 steigert YOLOv7 Geschwindigkeit und Genauigkeit erheblich. Beispielsweise verbessert YOLOv7-X die Genauigkeit um 2,2 % und reduziert die Parameter im Vergleich zu YOLOv5-X um 22 %. Detaillierte Vergleiche findest du in der Leistungstabelle YOLOv7-Vergleich mit SOTA-Objektdetektoren.
Kann ich YOLOv7 mit Ultralytics-Tools und -Plattformen verwenden?#
Bisher unterstützt Ultralytics nur die ONNX- und TensorRT-Inferenz für YOLOv7. Um die exportierte ONNX- und TensorRT-Version von YOLOv7 mit Ultralytics auszuführen, sieh dir den Abschnitt Nutzungsbeispiele an.
Wie trainiere ich ein benutzerdefiniertes YOLOv7-Modell mit meinem Datensatz?#
Um ein benutzerdefiniertes YOLOv7-Modell zu installieren und zu trainieren, befolge diese Schritte:
-
Klone das YOLOv7-Repository:
git clone https://github.com/WongKinYiu/yolov7 -
Navigiere in das geklonte Verzeichnis und installiere die Abhängigkeiten:
cd yolov7 pip install -r requirements.txt -
Bereite deinen Datensatz vor und konfiguriere die Modellparameter gemäß den Nutzungsanweisungen im Repository. Für weitere Anleitungen besuche das YOLOv7 GitHub-Repository für die neuesten Informationen und Updates.
-
Nach dem Training kannst du das Modell zur Verwendung in Ultralytics nach ONNX oder TensorRT exportieren, wie in Nutzungsbeispiele gezeigt.
Was sind die Hauptfunktionen und Optimierungen, die in YOLOv7 eingeführt wurden?#
YOLOv7 bietet mehrere Hauptfunktionen, die die Echtzeit-Objekterkennung revolutionieren:
- Modell-Reparametrisierung: Verbessert die Leistung des Modells durch Optimierung der Gradienten-Propagationspfade.
- Dynamische Label-Zuweisung: Nutzt eine "Coarse-to-Fine"-Methode, um dynamische Ziele für Ausgaben über verschiedene Zweige hinweg zuzuweisen, was die Genauigkeit verbessert.
- Erweiterte und zusammengesetzte Skalierung: Nutzt Parameter und Rechenleistung effizient, um das Modell für verschiedene Echtzeitanwendungen zu skalieren.
- Effizienz: Reduziert die Parameteranzahl um 40 % und den Rechenaufwand um 50 % im Vergleich zu anderen modernen Modellen und erreicht dabei schnellere Inferenzgeschwindigkeiten.
Weitere Details zu diesen Funktionen findest du im Abschnitt YOLOv7-Übersicht.