Vai al contenuto

YOLOv7: Bag-of-Freebies addestrabile

YOLOv7 è un rilevatore di oggetti in tempo reale all'avanguardia che supera tutti i rilevatori di oggetti conosciuti sia in velocità che in precisione nell'intervallo da 5 FPS a 160 FPS. Ha la massima precisione (56,8% AP) tra tutti i rilevatori di oggetti in tempo reale conosciuti con 30 FPS o superiore su GPU V100. Inoltre, YOLOv7 supera altri rilevatori di oggetti come YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5 e molti altri in velocità e precisione. Il modello è addestrato sul set di dati MS COCO da zero senza utilizzare altri set di dati o pesi pre-addestrati. Il codice sorgente per YOLOv7 è disponibile su GitHub.

Confronto tra YOLOv7 e i rilevatori di oggetti SOTA

Confronto tra i rilevatori di oggetti SOTA

Dai risultati nella tabella di confronto di YOLO sappiamo che il metodo proposto ha il miglior compromesso velocità-precisione in modo completo. Se confrontiamo YOLOv7-tiny-SiLU con YOLOv5-N (r6.1), il nostro metodo è più veloce di 127 fps e più preciso del 10,7% su AP. Inoltre, YOLOv7 ha il 51,4% di AP a una frequenza di fotogrammi di 161 fps, mentre PPYOLOE-L con lo stesso AP ha solo una frequenza di fotogrammi di 78 fps. In termini di utilizzo dei parametri, YOLOv7 è inferiore del 41% rispetto a PPYOLOE-L.

Se confrontiamo YOLOv7-X con una velocità di inferenza di 114 fps con YOLOv5-L (r6.1) con una velocità di inferenza di 99 fps, YOLOv7-X può migliorare l'AP del 3,9%. Se YOLOv7-X viene confrontato con YOLOv5-X (r6.1) di scala simile, la velocità di inferenza di YOLOv7-X è più veloce di 31 fps. Inoltre, in termini di quantità di parametri e calcolo, YOLOv7-X riduce il 22% dei parametri e l'8% del calcolo rispetto a YOLOv5-X (r6.1), ma migliora l'AP del 2,2% (Fonte).

Prestazioni

Modello Parametri
(M)
FLOPs
(G)
Dimensione
(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%

Panoramica

Il rilevamento di oggetti in tempo reale è una componente importante in molti sistemi di computer vision, tra cui il multi-object tracking, la guida autonoma, la robotica e l'analisi di immagini mediche. Negli ultimi anni, lo sviluppo del rilevamento di oggetti in tempo reale si è concentrato sulla progettazione di architetture efficienti e sul miglioramento della velocità di inferenza di varie CPU, GPU e unità di elaborazione neurale (NPU). YOLOv7 supporta sia GPU mobili che dispositivi GPU, dall'edge al cloud.

A differenza dei tradizionali rilevatori di oggetti in tempo reale che si concentrano sull'ottimizzazione dell'architettura, YOLOv7 introduce un focus sull'ottimizzazione del processo di training. Ciò include moduli e metodi di ottimizzazione progettati per migliorare l'accuratezza del rilevamento degli oggetti senza aumentare il costo di inferenza, un concetto noto come "trainable bag-of-freebies".

Caratteristiche principali

YOLOv7 introduce diverse caratteristiche chiave:

  1. Riparamentrizzazione del modello: YOLOv7 propone un modello riparametrizzato pianificato, che è una strategia applicabile ai livelli in diverse reti con il concetto di percorso di propagazione del gradiente.

  2. Assegnazione dinamica delle etichette: Il training del modello con più livelli di output presenta un nuovo problema: "Come assegnare target dinamici per gli output di diversi rami?" Per risolvere questo problema, YOLOv7 introduce un nuovo metodo di assegnazione delle etichette chiamato coarse-to-fine lead guided label assignment.

  3. Scalabilità estesa e composta: YOLOv7 propone metodi di "estensione" e "scalabilità composta" per il rilevatore di oggetti in tempo reale, in grado di utilizzare efficacemente parametri e calcoli.

  4. Efficienza: Il metodo proposto da YOLOv7 può ridurre efficacemente di circa il 40% i parametri e del 50% il calcolo del rilevatore di oggetti in tempo reale all'avanguardia, e ha una velocità di inferenza più elevata e una maggiore accuratezza di rilevamento.

Esempi di utilizzo

Al momento della stesura, Ultralytics supporta solo l'inferenza ONNX e TensorRT per YOLOv7.

Esportazione ONNX

Per utilizzare il modello YOLOv7 ONNX con Ultralytics:

  1. (Opzionale) Installa Ultralytics ed esporta un modello ONNX per avere le dipendenze richieste installate automaticamente:

    pip install ultralytics
    yolo export model=yolo11n.pt format=onnx
    
  2. Esporta il modello YOLOv7 desiderato utilizzando l'exporter nel repository YOLOv7:

    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. Modifica il grafico del modello ONNX per essere compatibile con Ultralytics utilizzando il seguente script:

    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. Puoi quindi caricare il modello ONNX modificato ed eseguire normalmente l'inferenza con esso in Ultralytics:

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

Esportazione TensorRT

  1. Seguire i passaggi 1-2 nella sezione Esportazione ONNX.

  2. Installa il TensorRT Pacchetto Python:

    pip install tensorrt
    
  3. Esegui lo script seguente per convertire il modello ONNX modificato in un motore TensorRT:

    from ultralytics.utils.export import export_engine
    
    export_engine("yolov7-ultralytics.onnx", half=True)
    
  4. Carica ed esegui il modello in Ultralytics:

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

Citazioni e riconoscimenti

Desideriamo ringraziare gli autori di YOLOv7 per i loro significativi contributi nel campo del rilevamento di oggetti in tempo reale:

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

L'articolo originale su YOLOv7 è disponibile su arXiv. Gli autori hanno reso il loro lavoro pubblicamente disponibile e il codice può essere consultato su GitHub. Apprezziamo i loro sforzi nel far progredire il settore e nel rendere il loro lavoro accessibile alla comunità più ampia.

FAQ

Cos'è YOLOv7 e perché è considerato una svolta nella object detection in tempo reale?

YOLOv7 è un modello di rilevamento oggetti in tempo reale all'avanguardia che raggiunge velocità e precisione senza precedenti. Supera altri modelli, come YOLOX, YOLOv5 e PPYOLOE, sia nell'utilizzo dei parametri che nella velocità di inferenza. Le caratteristiche distintive di YOLOv7 includono la sua riparametrizzazione del modello e l'assegnazione dinamica delle etichette, che ne ottimizzano le prestazioni senza aumentare i costi di inferenza. Per maggiori dettagli tecnici sulla sua architettura e sulle metriche di confronto con altri rilevatori di oggetti all'avanguardia, fare riferimento al paper di YOLOv7.

In che modo YOLOv7 migliora i precedenti modelli YOLO come YOLOv4 e YOLOv5?

YOLOv7 introduce diverse innovazioni, tra cui la riparametrizzazione del modello e l'assegnazione dinamica delle etichette, che migliorano il processo di addestramento e aumentano l'accuratezza dell'inferenza. Rispetto a YOLOv5, YOLOv7 aumenta significativamente la velocità e l'accuratezza. Ad esempio, YOLOv7-X migliora l'accuratezza del 2,2% e riduce i parametri del 22% rispetto a YOLOv5-X. Confronti dettagliati sono disponibili nella tabella delle prestazioni Confronto tra YOLOv7 e i rilevatori di oggetti SOTA.

Posso utilizzare YOLOv7 con gli strumenti e le piattaforme Ultralytics?

Al momento, Ultralytics supporta solo l'inferenza YOLOv7 ONNX e TensorRT. Per eseguire la versione esportata ONNX e TensorRT di YOLOv7 con Ultralytics, consultare la sezione Esempi di utilizzo.

Come posso addestrare un modello YOLOv7 personalizzato utilizzando il mio dataset?

Per installare e addestrare un modello YOLOv7 personalizzato, segui questi passaggi:

  1. Clona il repository YOLOv7:
    git clone https://github.com/WongKinYiu/yolov7
    
  2. Spostarsi nella directory clonata e installare le dipendenze:
    cd yolov7
    pip install -r requirements.txt
    
  3. Prepara il tuo set di dati e configura i parametri del modello secondo le istruzioni d'uso fornite nel repository. Per ulteriori indicazioni, visita il repository YOLOv7 GitHub per le informazioni e gli aggiornamenti più recenti.

  4. Dopo l'addestramento, è possibile esportare il modello in ONNX o TensorRT per l'uso in Ultralytics come mostrato in Esempi di utilizzo.

Quali sono le caratteristiche principali e le ottimizzazioni introdotte in YOLOv7?

YOLOv7 offre diverse caratteristiche chiave che rivoluzionano il rilevamento di oggetti in tempo reale:

  • Riparamentrizzazione del modello: Migliora le prestazioni del modello ottimizzando i percorsi di propagazione del gradiente.
  • Assegnazione dinamica delle etichette: Utilizza un metodo guidato coarse-to-fine per assegnare target dinamici per gli output tra diversi rami, migliorando la precisione.
  • Scalabilità estesa e composta: Utilizza in modo efficiente parametri e calcoli per scalare il modello per varie applicazioni in tempo reale.
  • Efficienza: Riduce il numero di parametri del 40% e il calcolo del 50% rispetto ad altri modelli all'avanguardia, ottenendo al contempo velocità di inferenza più elevate.

Per ulteriori dettagli su queste funzionalità, consultare la sezione Panoramica di YOLOv7.



📅 Creato 1 anno fa ✏️ Aggiornato 2 mesi fa

Commenti