Ir al contenido

YOLOv7: Bag-of-Freebies entrenable

YOLOv7 es un detector de objetos en tiempo real de última generación que supera a todos los detectores de objetos conocidos tanto en velocidad como en precisión en el rango de 5 FPS a 160 FPS. Tiene la mayor precisión (56.8% AP) entre todos los detectores de objetos en tiempo real conocidos con 30 FPS o más en GPU V100. Además, YOLOv7 supera a otros detectores de objetos como YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5, y muchos otros en velocidad y precisión. El modelo está entrenado en el conjunto de datos MS COCO desde cero sin utilizar ningún otro conjunto de datos o pesos pre-entrenados. El código fuente de YOLOv7 está disponible en GitHub.

Comparación de YOLOv7 con detectores de objetos SOTA

Comparación de detectores de objetos SOTA

De los resultados en la tabla de comparación de YOLO, sabemos que el método propuesto tiene la mejor relación velocidad-precisión de manera integral. Si comparamos YOLOv7-tiny-SiLU con YOLOv5-N (r6.1), nuestro método es 127 fps más rápido y 10.7% más preciso en AP. Además, YOLOv7 tiene un 51.4% de AP a una velocidad de fotogramas de 161 fps, mientras que PPYOLOE-L con el mismo AP tiene una velocidad de fotogramas de solo 78 fps. En términos de uso de parámetros, YOLOv7 es un 41% menor que PPYOLOE-L.

Si comparamos YOLOv7-X con una velocidad de inferencia de 114 fps con YOLOv5-L (r6.1) con una velocidad de inferencia de 99 fps, YOLOv7-X puede mejorar la AP en un 3.9%. Si YOLOv7-X se compara con YOLOv5-X (r6.1) de escala similar, la velocidad de inferencia de YOLOv7-X es 31 fps más rápida. Además, en términos de la cantidad de parámetros y cálculo, YOLOv7-X reduce el 22% de los parámetros y el 8% del cálculo en comparación con YOLOv5-X (r6.1), pero mejora la AP en un 2.2% (Fuente).

Rendimiento

Modelo Parámetros
(M)
FLOPs
(G)
Tamaño
(píxeles)
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%

Visión general

La detección de objetos en tiempo real es un componente importante en muchos sistemas de visión artificial, incluyendo el seguimiento multi-objeto, la conducción autónoma, la robótica y el análisis de imágenes médicas. En los últimos años, el desarrollo de la detección de objetos en tiempo real se ha centrado en el diseño de arquitecturas eficientes y en la mejora de la velocidad de inferencia de varias CPUs, GPUs y unidades de procesamiento neuronal (NPUs). YOLOv7 es compatible con dispositivos GPU móviles y GPU, desde el borde hasta la nube.

A diferencia de los detectores de objetos en tiempo real tradicionales que se centran en la optimización de la arquitectura, YOLOv7 introduce un enfoque en la optimización del proceso de entrenamiento. Esto incluye módulos y métodos de optimización diseñados para mejorar la precisión de la detección de objetos sin aumentar el coste de la inferencia, un concepto conocido como el "trainable bag-of-freebies".

Características clave

YOLOv7 introduce varias características clave:

  1. Re-parametrización del Modelo: YOLOv7 propone un modelo re-parametrizado planificado, que es una estrategia aplicable a capas en diferentes redes con el concepto de ruta de propagación del gradiente.

  2. Asignación dinámica de etiquetas: El entrenamiento del modelo con múltiples capas de salida presenta un nuevo problema: "¿Cómo asignar objetivos dinámicos para las salidas de diferentes ramas?". Para resolver este problema, YOLOv7 introduce un nuevo método de asignación de etiquetas llamado asignación de etiquetas guiada de lo grueso a lo fino.

  3. Escalado Extendido y Compuesto: YOLOv7 propone métodos de "escalado extendido" y "compuesto" para el detector de objetos en tiempo real que puede utilizar eficazmente los parámetros y la computación.

  4. Eficiencia: El método propuesto por YOLOv7 puede reducir eficazmente alrededor del 40% de los parámetros y el 50% del cálculo del detector de objetos en tiempo real de última generación, y tiene una velocidad de inferencia más rápida y una mayor precisión de detección.

Ejemplos de uso

Hasta el momento de escribir esto, Ultralytics solo admite la inferencia ONNX y TensorRT para YOLOv7.

Exportación ONNX

Para usar el modelo ONNX de YOLOv7 con Ultralytics:

  1. (Opcional) Instala Ultralytics y exporta un modelo ONNX para que las dependencias necesarias se instalen automáticamente:

    pip install ultralytics
    yolo export model=yolo11n.pt format=onnx
    
  2. Exporta el modelo YOLOv7 deseado utilizando el exportador en el repositorio de 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. Modifique el gráfico del modelo ONNX para que sea compatible con Ultralytics utilizando el siguiente 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. A continuación, puedes cargar el modelo ONNX modificado y ejecutar la inferencia con él en Ultralytics de forma normal:

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

Exportación a TensorRT

  1. Siga los pasos 1 y 2 en la sección Exportación ONNX.

  2. Instale el TensorRT Paquete de python:

    pip install tensorrt
    
  3. Ejecute el siguiente script para convertir el modelo ONNX modificado al motor TensorRT:

    from ultralytics.utils.export import export_engine
    
    export_engine("yolov7-ultralytics.onnx", half=True)
    
  4. Cargue y ejecute el modelo en Ultralytics:

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

Citas y agradecimientos

Nos gustaría reconocer a los autores de YOLOv7 por sus importantes contribuciones en el campo de la detección de objetos en tiempo real:

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

El artículo original de YOLOv7 se puede encontrar en arXiv. Los autores han hecho que su trabajo esté disponible públicamente y se puede acceder a la base de código en GitHub. Agradecemos sus esfuerzos para avanzar en el campo y hacer que su trabajo sea accesible a la comunidad en general.

Preguntas frecuentes

¿Qué es YOLOv7 y por qué se considera un avance en la detección de objetos en tiempo real?

YOLOv7 es un modelo de detección de objetos en tiempo real de vanguardia que alcanza una velocidad y precisión sin igual. Supera a otros modelos, como YOLOX, YOLOv5 y PPYOLOE, tanto en el uso de parámetros como en la velocidad de inferencia. Las características distintivas de YOLOv7 incluyen su re-parametrización del modelo y la asignación dinámica de etiquetas, que optimizan su rendimiento sin aumentar los costes de inferencia. Para obtener más detalles técnicos sobre su arquitectura y las métricas de comparación con otros detectores de objetos de última generación, consulte el documento de YOLOv7.

¿Cómo mejora YOLOv7 con respecto a modelos YOLO anteriores como YOLOv4 e YOLOv5?

YOLOv7 introduce varias innovaciones, incluyendo la re-parametrización del modelo y la asignación dinámica de etiquetas, que mejoran el proceso de entrenamiento y aumentan la precisión de la inferencia. En comparación con YOLOv5, YOLOv7 aumenta significativamente la velocidad y la precisión. Por ejemplo, YOLOv7-X mejora la precisión en un 2.2% y reduce los parámetros en un 22% en comparación con YOLOv5-X. Se pueden encontrar comparaciones detalladas en la tabla de rendimiento Comparación de YOLOv7 con detectores de objetos SOTA.

¿Puedo usar YOLOv7 con las herramientas y plataformas de Ultralytics?

Hasta ahora, Ultralytics solo admite la inferencia ONNX y TensorRT de YOLOv7. Para ejecutar la versión exportada ONNX y TensorRT de YOLOv7 con Ultralytics, consulte la sección Ejemplos de uso.

¿Cómo entreno un modelo YOLOv7 personalizado utilizando mi conjunto de datos?

Para instalar y entrenar un modelo YOLOv7 personalizado, sigue estos pasos:

  1. Clonar el repositorio YOLOv7:
    git clone https://github.com/WongKinYiu/yolov7
    
  2. Navegue al directorio clonado e instale las dependencias:
    cd yolov7
    pip install -r requirements.txt
    
  3. Prepara tu conjunto de datos y configura los parámetros del modelo de acuerdo con las instrucciones de uso proporcionadas en el repositorio. Para obtener más orientación, visita el repositorio de YOLOv7 en GitHub para obtener la información y las actualizaciones más recientes.

  4. Después del entrenamiento, puedes exportar el modelo a ONNX o TensorRT para usarlo en Ultralytics como se muestra en Ejemplos de uso.

¿Cuáles son las principales características y optimizaciones introducidas en YOLOv7?

YOLOv7 ofrece varias características clave que revolucionan la detección de objetos en tiempo real:

  • Re-parametrización del Modelo: Mejora el rendimiento del modelo optimizando las rutas de propagación del gradiente.
  • Asignación dinámica de etiquetas: Utiliza un método guiado de lo grueso a lo fino para asignar objetivos dinámicos para las salidas a través de diferentes ramas, mejorando la precisión.
  • Escalado extendido y compuesto: Utiliza eficientemente los parámetros y la computación para escalar el modelo para diversas aplicaciones en tiempo real.
  • Eficiencia: Reduce el número de parámetros en un 40 % y el cálculo en un 50 % en comparación con otros modelos de última generación, al tiempo que se consiguen velocidades de inferencia más rápidas.

Para obtener más detalles sobre estas características, consulte la sección Descripción general de YOLOv7.



📅 Creado hace 1 año ✏️ Actualizado hace 2 meses

Comentarios