YOLOv7: Trainierbare Bag-of-Freebies
YOLOv7 ist ein hochmoderner Echtzeit-Objektdetektor, der alle bekannten Objektdetektoren sowohl in Geschwindigkeit als auch in Genauigkeit im Bereich von 5 FPS bis 160 FPS übertrifft. Es weist die höchste Genauigkeit (56,8 % AP) unter allen bekannten Echtzeit-Objektdetektoren mit 30 FPS oder höher auf einer GPU V100 auf. Darüber hinaus übertrifft YOLOv7 andere Objektdetektoren wie YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5 und viele andere in 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.

Vergleich von SOTA-Objektdetektoren
Aus den Ergebnissen in der YOLO-Vergleichstabelle wissen wir, dass die vorgeschlagene Methode insgesamt den besten Kompromiss zwischen Geschwindigkeit und Genauigkeit aufweist. Wenn wir YOLOv7-tiny-SiLU mit YOLOv5-N (r6.1) vergleichen, ist unsere Methode 127 fps schneller und 10,7 % genauer bei 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 aufweist. Hinsichtlich des Parameterverbrauchs ist YOLOv7 41 % geringer als PPYOLOE-L.
Vergleicht man YOLOv7-X mit einer Inferenzgeschwindigkeit von 114 fps mit YOLOv5-L (r6.1) mit 99 fps Inferenzgeschwindigkeit, kann YOLOv7-X die AP um 3,9 % verbessern. Wird YOLOv7-X mit YOLOv5-X (r6.1) ähnlicher Größenordnung verglichen, ist die Inferenzgeschwindigkeit von YOLOv7-X um 31 fps schneller. Darüber hinaus reduziert YOLOv7-X hinsichtlich der Anzahl der Parameter und des Rechenaufwands 22 % der Parameter und 8 % des Rechenaufwands 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
Die Echtzeit-Objektdetektion ist eine wichtige Komponente in vielen Computer-Vision-Systemen, einschließlich Multi-Objekt-Tracking, autonomem Fahren, Robotik und medizinischer Bildanalyse. In den letzten Jahren konzentrierte sich die Entwicklung der Echtzeit-Objektdetektion auf den Entwurf effizienter Architekturen und die Verbesserung der Inference-Geschwindigkeit verschiedener CPUs, GPUs und neuronaler Verarbeitungseinheiten (NPUs). YOLOv7 unterstützt sowohl mobile GPU- als auch GPU-Geräte, von Edge bis zur Cloud.
Im Gegensatz zu traditionellen Echtzeit-Objektdetektoren, die sich auf die Architektur-Optimierung konzentrieren, legt YOLOv7 den Fokus auf die Optimierung des Trainingsprozesses. Dies umfasst Module und Optimierungsmethoden, die darauf abzielen, die Genauigkeit der Objektdetektion zu verbessern, ohne die Inferenzkosten zu erhöhen – ein Konzept, das als „trainable bag-of-freebies“ bekannt ist.
Hauptmerkmale
YOLOv7 führt mehrere Schlüsselmerkmale ein:
Modell-Re-Parametrisierung: YOLOv7 schlägt ein geplantes re-parametrisiertes Modell vor, eine Strategie, die auf Schichten in verschiedenen Netzwerken mit dem Konzept des Gradientenpropagationspfades anwendbar ist.
Dynamische Label-Zuweisung: Das Training des Modells mit mehreren Ausgabeschichten wirft eine neue Frage auf: „Wie werden dynamische Ziele für die Ausgaben verschiedener Zweige zugewiesen?“ 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.
Erweitertes und Compound Scaling: 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 etwa 40 % der Parameter und 50 % der Rechenleistung eines hochmodernen Echtzeit-Objektdetektors effektiv reduzieren und weist eine schnellere Inferenzgeschwindigkeit sowie eine höhere detect-Genauigkeit auf.
Anwendungsbeispiele
Zum Zeitpunkt der Erstellung dieses Dokuments unterstützt Ultralytics nur ONNX- und TensorRT-Inferenz für YOLOv7.
ONNX-Export
Um das YOLOv7 ONNX-Modell mit Ultralytics zu verwenden:
(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=onnxExportieren Sie das gewünschte YOLOv7-Modell, indem Sie den Exporter 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
TensorRTPython-Paket:pip install tensorrtFü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}
}
Die Originalarbeit zu YOLOv7 ist auf arXiv verfügbar. Die Autoren haben ihre Arbeit öffentlich zugänglich gemacht, und der Quellcode kann auf GitHub abgerufen werden. Wir schätzen ihre Bemühungen, das Fachgebiet voranzutreiben und ihre Arbeit einer breiteren Gemeinschaft zugänglich zu machen.
FAQ
Was ist YOLOv7 und warum gilt es als Durchbruch in der Echtzeit-Objekterkennung?
YOLOv7 ist ein hochmodernes Echtzeit-Objekterkennungsmodell, das unübertroffene Geschwindigkeit und Genauigkeit erreicht. Es übertrifft andere Modelle wie YOLOX, YOLOv5 und PPYOLOE sowohl in der Parameternutzung als auch in der Inferenzgeschwindigkeit. Zu den herausragenden Merkmalen von YOLOv7 gehören seine Modell-Re-Parametrisierung und dynamische Label-Zuweisung, die seine Leistung optimieren, ohne die Inferenzkosten zu erhöhen. Für weitere technische Details zu seiner Architektur und Vergleichsmetriken mit anderen hochmodernen Objektdetektoren verweisen wir auf das YOLOv7 Paper.
Wie verbessert sich YOLOv7 gegenüber früheren YOLO-Modellen wie YOLOv4 und YOLOv5?
YOLOv7 führt mehrere Innovationen ein, darunter Modell-Re-Parametrisierung und dynamische Label-Zuweisung, die den Trainingsprozess verbessern und die Inferenzgenauigkeit steigern. Im Vergleich zu YOLOv5 steigert YOLOv7 Geschwindigkeit und Genauigkeit erheblich. Zum Beispiel verbessert YOLOv7-X die Genauigkeit um 2,2 % und reduziert die Parameter um 22 % im Vergleich zu YOLOv5-X. Detaillierte Vergleiche finden sich in der Leistungstabelle YOLOv7 comparison with SOTA object detectors.
Kann ich YOLOv7 mit Ultralytics-Tools und -Plattformen verwenden?
Derzeit unterstützt Ultralytics nur YOLOv7 ONNX- und TensorRT-Inferenz. Um die ONNX- und TensorRT-exportierte Version von YOLOv7 mit Ultralytics auszuführen, siehe den Abschnitt Anwendungsbeispiele.
Wie trainiere ich ein benutzerdefiniertes YOLOv7-Modell mit meinem Datensatz?
Um ein benutzerdefiniertes YOLOv7-Modell zu installieren und zu trainieren, folgen Sie diesen Schritten:
- 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 im Repository bereitgestellten Nutzungsanweisungen. 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 Hauptmerkmale und Optimierungen wurden in YOLOv7 eingeführt?
YOLOv7 bietet mehrere Schlüsselfunktionen, die die Echtzeit-Objektdetektion 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 Details zu diesen Funktionen finden Sie im Abschnitt YOLOv7 Overview.