Meet YOLO26: next-gen vision AI.

Link to this sectionYOLOv7: Trainable Bag-of-Freebies#

YOLOv7, rilasciato nel luglio 2022, è stato un significativo passo avanti nel rilevamento di oggetti in tempo reale al momento del suo lancio. Ha raggiunto il 56,8% di AP su GPU V100, stabilendo nuovi benchmark al momento dell'introduzione. YOLOv7 ha superato i rilevatori di oggetti contemporanei come YOLOR, YOLOX, Scaled-YOLOv4 e YOLOv5 in termini di velocità e accuratezza. Il modello è addestrato da zero sul dataset MS COCO senza l'utilizzo di altri dataset o pesi pre-addestrati. Il codice sorgente per YOLOv7 è disponibile su GitHub. Nota che modelli più recenti come YOLO11 e YOLO26 hanno da allora raggiunto una maggiore accuratezza con una migliore efficienza.

Confronto di YOLOv7 con rilevatori di oggetti SOTA

Link to this sectionConfronto tra rilevatori di oggetti SOTA#

Dai risultati nella tabella di confronto YOLO, sappiamo che il metodo proposto presenta complessivamente il miglior compromesso tra velocità e accuratezza. Se confrontiamo YOLOv7-tiny-SiLU con YOLOv5-N (r6.1), il nostro metodo è più veloce di 127 fps e più accurato del 10,7% in termini di AP. Inoltre, YOLOv7 ha un AP del 51,4% a una frequenza di 161 fps, mentre PPYOLOE-L, con lo stesso AP, ha una frequenza di soli 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) a 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 è superiore di 31 fps. Inoltre, in termini di quantità di parametri e computazione, YOLOv7-X riduce i parametri del 22% e la computazione dell'8% rispetto a YOLOv5-X (r6.1), ma migliora l'AP del 2,2% (Fonte).

Performance
ModelloParams
(M)
FLOPs
(G)
Dimensioni
(pixel)
FPSAPtest / val
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%

Link to this sectionPanoramica#

Il rilevamento di oggetti in tempo reale è una componente importante in molti sistemi di computer vision, inclusi il tracciamento di oggetti, 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 dispositivi GPU mobile che 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 addestramento. Questo include moduli e metodi di ottimizzazione progettati per migliorare l'accuratezza del rilevamento di oggetti senza aumentare il costo di inferenza, un concetto noto come "trainable bag-of-freebies".

Link to this sectionCaratteristiche principali#

YOLOv7 introduce diverse funzionalità chiave:

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

  2. Assegnazione dinamica delle etichette: L'addestramento del modello con più strati di output presenta un nuovo problema: "Come assegnare target dinamici per gli output di rami diversi?" Per risolvere questo problema, YOLOv7 introduce un nuovo metodo di assegnazione delle etichette chiamato assegnazione delle etichette guidata da lead da grossolano a fine.

  3. Scaling esteso e composto: YOLOv7 propone metodi di "estensione" e "scaling composto" per il rilevatore di oggetti in tempo reale che possono utilizzare efficacemente parametri e calcolo.

  4. Efficienza: Il metodo proposto da YOLOv7 può ridurre efficacemente circa il 40% dei parametri e il 50% del calcolo dei rilevatori di oggetti in tempo reale allo stato dell'arte, e ha una velocità di inferenza più rapida e una maggiore accuratezza di rilevamento.

Link to this sectionEsempi di Utilizzo#

Ultralytics non pubblica pesi preaddestrati yolov7.pt o YAML ultralytics/cfg/models/v7/, e l'addestramento e l'inferenza nativi in PyTorch per YOLOv7 non sono supportati dal pacchetto Python di Ultralytics. Tuttavia, puoi importare un checkpoint YOLOv7 addestrato nel repository originale YOLOv7 in Ultralytics esportandolo in ONNX o TensorRT, come mostrato di seguito.

Link to this sectionEsportazione ONNX#

Per utilizzare il modello ONNX di YOLOv7 con Ultralytics:

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

    pip install ultralytics
    yolo export model=yolo26n.pt format=onnx
  2. Esporta il modello YOLOv7 desiderato utilizzando l'esportatore 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 grafo del modello ONNX per renderlo 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 l'inferenza con esso in Ultralytics normalmente:

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

Link to this sectionEsportazione TensorRT#

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

  2. Installa il pacchetto Python TensorRT:

    pip install tensorrt
  3. Esegui il seguente script per convertire il modello ONNX modificato nel 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")

Link to this sectionCitazioni e riconoscimenti#

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

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

Il paper ufficiale di YOLOv7 è stato pubblicato su CVF 2023 Open Access, con un preprint su arXiv. Gli autori hanno reso il loro lavoro pubblicamente disponibile e la codebase può essere consultata su GitHub. Apprezziamo i loro sforzi nel far progredire il campo e nel rendere il loro lavoro accessibile alla comunità più ampia.

Link to this sectionFAQ#

Link to this sectionCos'è YOLOv7 e perché è considerato una svolta nel rilevamento di oggetti in tempo reale?#

YOLOv7, rilasciato a luglio 2022, è stato un importante modello di rilevamento di oggetti in tempo reale che ha raggiunto velocità e accuratezza eccellenti al momento del suo rilascio. Ha superato i modelli contemporanei come YOLOX, YOLOv5 e PPYOLOE sia nell'uso 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 ulteriori dettagli tecnici sulla sua architettura e sulle metriche di confronto con altri rilevatori di oggetti allo stato dell'arte, fai riferimento al paper di YOLOv7.

Link to this sectionCome migliora YOLOv7 rispetto ai 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 migliorano 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 possono essere trovati nella tabella delle prestazioni Confronto di YOLOv7 con i rilevatori di oggetti SOTA.

Link to this sectionPosso utilizzare YOLOv7 con gli strumenti e le piattaforme Ultralytics?#

Ad oggi, Ultralytics supporta solo l'inferenza YOLOv7 ONNX e TensorRT. Per eseguire la versione esportata di YOLOv7 ONNX e TensorRT con Ultralytics, controlla la sezione Esempi di utilizzo.

Link to this sectionCome 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. Naviga nella directory clonata e installa le dipendenze:

    cd yolov7
    pip install -r requirements.txt
  3. Prepara il tuo dataset e configura i parametri del modello seguendo le istruzioni per l'uso fornite nel repository. Per ulteriori indicazioni, visita il repository GitHub di YOLOv7 per le ultime informazioni e aggiornamenti.

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

Link to this sectionQuali sono le funzionalità chiave e le ottimizzazioni introdotte in YOLOv7?#

YOLOv7 offre diverse funzionalità 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 da lead da grossolano a fine per assegnare target dinamici per gli output su rami diversi, migliorando l'accuratezza.
  • Scaling esteso e composto: Utilizza in modo efficiente i parametri e il calcolo 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 allo stato dell'arte, ottenendo velocità di inferenza più elevate.

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

Commenti