Ultralytics YOLO27:

YOLOv7: Trainierbare kostenlose Verbesserungen#

YOLOv7, veröffentlicht im Juli 2022, stellte zum Zeitpunkt seiner Veröffentlichung einen bedeutenden Fortschritt bei der Objekterkennung in Echtzeit dar. Das Modell erreichte 56,8 % AP auf einer GPU V100 und setzte damit bei seiner Einführung neue Maßstäbe. YOLOv7 übertraf zeitgenössische Objekterkennungsmodelle wie YOLOR, YOLOX, Scaled-YOLOv4 und YOLOv5 hinsichtlich Geschwindigkeit und Genauigkeit. Das Modell wird ohne Verwendung anderer Datensätze oder vortrainierter Gewichte von Grund auf mit dem MS-COCO-Datensatz trainiert. 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 YOLOv7 mit modernen Objekterkennungsmodellen

Vergleich moderner Objekterkennungsmodelle#

Aus den Ergebnissen der YOLO-Vergleichstabelle wissen wir, dass die vorgeschlagene Methode insgesamt das beste Verhältnis zwischen Geschwindigkeit und Genauigkeit bietet. Wenn wir YOLOv7-tiny-SiLU mit YOLOv5-N (r6.1) vergleichen, ist unsere Methode um 127 fps schneller und bei AP um 10,7 % genauer. Außerdem erreicht YOLOv7 51,4 % AP bei einer Bildrate von 161 fps, während PPYOLOE-L bei derselben AP nur eine Bildrate von 78 fps erreicht. Hinsichtlich der Anzahl der Parameter benötigt YOLOv7 41 % weniger als PPYOLOE-L.

Wenn wir YOLOv7-X mit einer Inferenzgeschwindigkeit von 114 fps mit YOLOv5-L (r6.1) mit 99 fps vergleichen, kann YOLOv7-X die AP um 3,9 % verbessern. Wird YOLOv7-X mit YOLOv5-X (r6.1) ähnlicher Größe verglichen, ist YOLOv7-X bei der Inferenzgeschwindigkeit um 31 fps schneller. Außerdem reduziert YOLOv7-X im Vergleich zu YOLOv5-X (r6.1) die Anzahl der Parameter um 22 % und den Rechenaufwand um 8 %, verbessert die AP jedoch um 2,2 % (Quelle).

Leistung
ModellParameter
(M)
FLOPs
(G)
Größe
(Pixel)
FPSAPTest / Validierung
50-95
APTest
50
APTest
75
APTest
S
APTest
M
APTest
L
YOLOX-S9.026.864010240.5% / 40.5%-----
YOLOX-M25.373.86408147.2% / 46.9%-----
YOLOX-L54.2155.66406950.1% / 49.7%-----
YOLOX-X99.1281.96405851.5% / 51.1%-----
PPYOLOE-S7.917.464020843.1% / 42.7%60.5%46.6%23.2%46.4%56.9%
PPYOLOE-M23.449.964012348.9% / 48.6%66.5%53.0%28.6%52.9%63.8%
PPYOLOE-L52.2110.16407851.4% / 50.9%68.9%55.6%31.4%55.3%66.1%
PPYOLOE-X98.4206.66404552.2% / 51.9%69.9%56.5%33.3%56.3%66.4%
YOLOv5-N (r6.1)1.94.5640159- / 28.0%-----
YOLOv5-S (r6.1)7.216.5640156- / 37.4%-----
YOLOv5-M (r6.1)21.249.0640122- / 45.4%-----
YOLOv5-L (r6.1)46.5109.164099- / 49.0%-----
YOLOv5-X (r6.1)86.7205.764083- / 50.7%-----
YOLOR-CSP52.9120.464010651.1% / 50.8%69.6%55.7%31.7%55.3%64.7%
YOLOR-CSP-X96.9226.86408753.0% / 52.7%71.4%57.9%33.7%57.1%66.8%
YOLOv7-tiny-SiLU6.213.864028638.7% / 38.7%56.7%41.7%18.8%42.4%51.9%
YOLOv736.9104.764016151.4% / 51.2%69.7%55.9%31.8%55.5%65.0%
YOLOv7-X71.3189.964011453.1% / 52.9%71.2%57.8%33.8%57.1%67.4%
YOLOv5-N6 (r6.1)3.218.41280123- / 36.0%-----
YOLOv5-S6 (r6.1)12.667.21280122- / 44.8%-----
YOLOv5-M6 (r6.1)35.7200.0128090- / 51.3%-----
YOLOv5-L6 (r6.1)76.8445.6128063- / 53.7%-----
YOLOv5-X6 (r6.1)140.7839.2128038- / 55.0%-----
YOLOR-P637.2325.612807653.9% / 53.5%71.4%58.9%36.1%57.7%65.6%
YOLOR-W679.8453.212806655.2% / 54.8%72.7%60.5%37.7%59.1%67.1%
YOLOR-E6115.8683.212804555.8% / 55.7%73.4%61.1%38.4%59.7%67.7%
YOLOR-D6151.7935.612803456.5% / 56.1%74.1%61.9%38.9%60.4%68.7%
YOLOv7-W670.4360.012808454.9% / 54.6%72.6%60.1%37.3%58.7%67.1%
YOLOv7-E697.2515.212805656.0% / 55.9%73.5%61.2%38.0%59.9%68.4%
YOLOv7-D6154.7806.812804456.6% / 56.3%74.0%61.8%38.8%60.1%69.5%
YOLOv7-E6E151.7843.212803656.8% / 56.8%74.4%62.1%39.3%60.5%69.0%

Übersicht#

Die Objekterkennung in Echtzeit ist ein wichtiger Bestandteil vieler Computer-Vision-Systeme, einschließlich der Mehrfach-Objektverfolgung, des autonomen Fahrens, der Robotik und der medizinischen Bildanalyse. In den vergangenen Jahren konzentrierte sich die Entwicklung der Objekterkennung in Echtzeit auf den Entwurf effizienter Architekturen und die Verbesserung der Inferenzgeschwindigkeit verschiedener CPUs, GPUs und neuronaler Verarbeitungseinheiten (NPUs). YOLOv7 unterstützt sowohl mobile GPUs als auch GPU-Geräte – vom Edge-Bereich bis zur Cloud.

Im Gegensatz zu herkömmlichen Objekterkennungsmodellen für Echtzeitanwendungen, die sich auf die Optimierung der Architektur konzentrieren, legt YOLOv7 den Schwerpunkt auf die Optimierung des Trainingsprozesses. Dazu gehören Module und Optimierungsmethoden, die die Genauigkeit der Objekterkennung verbessern, ohne die Inferenzkosten zu erhöhen – ein Konzept, das als „trainierbare kostenlose Verbesserungen“ bezeichnet wird.

Wichtige Funktionen#

YOLOv7 führt mehrere zentrale Funktionen ein:

  1. Neuparametrisierung des Modells: YOLOv7 schlägt ein geplantes neuparametrisiertes Modell vor – eine Strategie, die mithilfe des Konzepts von Gradientenpfaden auf Schichten verschiedener Netzwerke angewendet werden kann.

  2. Dynamische Zuordnung von Bezeichnungen: Das Training des Modells mit mehreren Ausgabeschichten bringt eine neue Frage mit sich: „Wie lassen sich dynamische Zielwerte den Ausgaben verschiedener Zweige zuordnen?“ Um dieses Problem zu lösen, führt YOLOv7 eine neue Methode zur Zuordnung von Bezeichnungen ein, die als grob-zu-fein-geleitete Zuordnung von Bezeichnungen bezeichnet wird.

  3. Erweiterte und zusammengesetzte Skalierung: YOLOv7 schlägt Methoden zur „Erweiterung“ und zur „zusammengesetzten Skalierung“ für Objekterkennungsmodelle in Echtzeit vor, die Parameter und Rechenleistung effektiv nutzen können.

  4. Effizienz: Die von YOLOv7 vorgeschlagene Methode kann die Anzahl der Parameter moderner Objekterkennungsmodelle für Echtzeitanwendungen effektiv um etwa 40 % und den Rechenaufwand um 50 % reduzieren und bietet gleichzeitig eine höhere Inferenzgeschwindigkeit und Erkennungsgenauigkeit.

Verwendungsbeispiele#

Ultralytics veröffentlicht keine vortrainierten Gewichte für yolov7.pt oder ultralytics/cfg/models/v7/-YAML-Dateien, und natives PyTorch-Training sowie native PyTorch-Inferenz für YOLOv7 werden vom Ultralytics Python-Paket nicht unterstützt. Du kannst jedoch einen im ursprünglichen YOLOv7-Repository trainierten YOLOv7-Checkpoint in Ultralytics verwenden, indem du ihn wie unten gezeigt nach ONNX oder TensorRT exportierst.

ONNX-Export#

So verwendest du ein YOLOv7-ONNX-Modell mit Ultralytics:

  1. (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
  2. Exportiere das gewünschte YOLOv7-Modell mit dem Exporter im YOLOv7-Repository:

    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
  3. Passe den ONNX-Modellgraphen mit dem folgenden Skript so an, dass er mit Ultralytics kompatibel ist:

    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")
  4. Anschließend kannst du das angepasste ONNX-Modell laden und damit wie gewohnt in Ultralytics eine Inferenz ausführen:

    from ultralytics import ASSETS, YOLO
    
    model = YOLO("yolov7-ultralytics.onnx", task="detect")
    
    results = model(ASSETS / "bus.jpg")

TensorRT-Export#

  1. Befolge die Schritte 1–2 im Abschnitt ONNX-Export.

  2. Installiere das TensorRT Python-Paket:

    pip install tensorrt
  3. Führe das folgende Skript aus, um das angepasste ONNX-Modell in eine TensorRT-Engine zu konvertieren:

    from ultralytics.utils.export import onnx2engine
    
    onnx2engine("yolov7-ultralytics.onnx", quantize=16)
  4. 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 auf dem Gebiet der Objekterkennung in Echtzeit danken:

Zitat
@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}
}

Die offizielle YOLOv7-Arbeit wurde in CVF 2023 Open Access veröffentlicht; ein Vorabdruck ist auf arXiv verfügbar. Die Autoren haben ihre Arbeit öffentlich zugänglich gemacht, und die Codebasis kann auf GitHub abgerufen werden. Wir würdigen ihre Anstrengungen, das Fachgebiet voranzubringen und ihre Arbeit einer breiteren Gemeinschaft zugänglich zu machen.

FAQ#

  • YOLOv7, veröffentlicht im Juli 2022, war zum Zeitpunkt seiner Veröffentlichung ein bedeutendes Modell für die Objekterkennung in Echtzeit, das eine ausgezeichnete Geschwindigkeit und Genauigkeit erreichte. Es übertraf zeitgenössische Modelle wie YOLOX, YOLOv5 und PPYOLOE sowohl bei der Anzahl der Parameter als auch bei der Inferenzgeschwindigkeit. Zu den charakteristischen Merkmalen von YOLOv7 gehören die Neuparametrisierung des Modells und die dynamische Zuordnung von Bezeichnungen, die seine Leistung optimieren, ohne die Inferenzkosten zu erhöhen. Weitere technische Details zur Architektur und zu Vergleichsmetriken mit anderen modernen Objekterkennungsmodellen findest du in der YOLOv7-Arbeit.

  • YOLOv7 führt mehrere Innovationen ein, darunter die Neuparametrisierung des Modells und die dynamische Zuordnung von Bezeichnungen, die den Trainingsprozess verbessern und die Inferenzgenauigkeit erhöhen. Im Vergleich zu YOLOv5 steigert YOLOv7 Geschwindigkeit und Genauigkeit deutlich. Beispielsweise verbessert YOLOv7-X die Genauigkeit im Vergleich zu YOLOv5-X um 2,2 % und reduziert die Anzahl der Parameter um 22 %. Detaillierte Vergleiche findest du in der Leistungstabelle Vergleich von YOLOv7 mit modernen Objekterkennungsmodellen.

  • Derzeit 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 im Abschnitt Nutzungsbeispiele nach.

  • Führe zum Installieren und Trainieren eines benutzerdefinierten YOLOv7-Modells die folgenden Schritte aus:

    1. Klone das YOLOv7-Repository:

      git clone https://github.com/WongKinYiu/yolov7
    2. Wechsle in das geklonte Verzeichnis und installiere die Abhängigkeiten:

      cd yolov7
      pip install -r requirements.txt
    3. Bereite deinen Datensatz vor und konfiguriere die Modellparameter gemäß den im Repository bereitgestellten Nutzungsanweisungen. Weitere Hinweise und aktuelle Informationen findest du im YOLOv7-GitHub-Repository.

    4. Nach dem Training kannst du das Modell wie in den Nutzungsbeispielen gezeigt zur Verwendung in Ultralytics nach ONNX oder TensorRT exportieren.

  • YOLOv7 bietet mehrere zentrale Funktionen, die die Objekterkennung in Echtzeit grundlegend verbessern:

    • Neuparametrisierung des Modells: Verbessert die Leistung des Modells durch die Optimierung von Gradientenpfaden.
    • Dynamische Zuordnung von Bezeichnungen: Verwendet eine grob-zu-fein-geleitete Methode, um dynamische Zielwerte den Ausgaben verschiedener Zweige zuzuordnen und dadurch die Genauigkeit zu verbessern.
    • Erweiterte und zusammengesetzte Skalierung: Nutzt Parameter und Rechenleistung effizient, um das Modell für verschiedene Echtzeitanwendungen zu skalieren.
    • Effizienz: Reduziert die Anzahl der Parameter um 40 % und den Rechenaufwand um 50 % im Vergleich zu anderen modernen Modellen und erreicht gleichzeitig höhere Inferenzgeschwindigkeiten.

    Weitere Informationen zu diesen Funktionen findest du im Abschnitt YOLOv7-Übersicht.

Kommentare