YOLOv7: Bolsa de regalos 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 en velocidad y precisión a otros detectores de objetos como YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5, y muchos otros. El modelo se entrena en el conjunto de datos MS COCO desde cero, sin utilizar otros conjuntos de datos ni pesos preentrenados. El código fuente de YOLOv7 está disponible en GitHub.
Comparación de los detectores de objetos SOTA
A partir de los resultados de la tabla comparativa de YOLO , sabemos que el método propuesto presenta la mejor relación velocidad-precisión de forma global. Si comparamos YOLOv7-tiny-SiLU con YOLOv5(r6.1), nuestro método es 127 fps más rápido y un 10,7% más preciso en AP. Además, YOLOv7 tiene un 51,4% de AP con una tasa de fotogramas de 161 fps, mientras que PPYOLOE-L con el mismo AP sólo tiene una tasa de fotogramas de 78 fps. En cuanto al uso de parámetros, YOLOv7 es un 41% menos que PPYOLOE-L.
Si comparamos YOLOv7-X, con una velocidad de inferencia de 114 fps, con YOLOv5(r6.1), con una velocidad de inferencia de 99 fps, YOLOv7-X puede mejorar AP en un 3,9%. Si se compara YOLOv7-X con YOLOv5(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 cantidad de parámetros y de cálculo, YOLOv7-X reduce el 22% de los parámetros y el 8% del cálculo en comparación con YOLOv5(r6.1), pero mejora 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 |
APrueba 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 por ordenador, comoel seguimiento multiobjeto, 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 diseñar arquitecturas eficientes y mejorar la velocidad de inferencia de diversas CPU, GPU y unidades de procesamiento neuronal (NPU). YOLOv7 es compatible con dispositivos 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 inferencia, un concepto conocido como "trainable bag-of-freebies".
Características principales
YOLOv7 introduce varias características clave:
-
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 trayectoria de propagación de gradiente.
-
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 denominado asignación de etiquetas guiada por pistas de grueso a fino.
-
Escalado extendido y compuesto: YOLOv7 propone métodos de "escalado extendido" y "compuesto" para el detector de objetos en tiempo real que pueden utilizar eficazmente los parámetros y el cálculo.
-
Eficacia: 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 más avanzado, y tiene una velocidad de inferencia más rápida y una mayor precisión de detección.
Ejemplos de uso
En el momento de redactar este documento, Ultralytics sólo admite la inferencia ONNX y TensorRT para YOLOv7.
Exportación ONNX
Para utilizar el modelo YOLOv7 ONNX con Ultralytics:
- (Opcional) Instale Ultralytics y exporte un modelo ONNX para que se instalen automáticamente las dependencias necesarias:
pip install ultralytics
yolo export model=yolo11n.pt format=onnx
- Exporte el modelo YOLOv7 deseado utilizando el exportador del 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
- 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")
- A continuación, puede cargar el modelo ONNX modificado y ejecutar la inferencia con él en Ultralytics normalmente:
from ultralytics import ASSETS, YOLO
model = YOLO("yolov7-ultralytics.onnx", task="detect")
results = model(ASSETS / "bus.jpg")
Exportación de TensorRT
-
Siga los pasos 1-2 de la sección Exportación deONNX .
-
Instale el
TensorRT
Paquete Python :
pip install tensorrt
- Ejecute el siguiente script para convertir el modelo ONNX modificado al motor TensorRT :
# Based off of https://github.com/NVIDIA/TensorRT/blob/release/10.7/samples/python/introductory_parser_samples/onnx_resnet50.py
import tensorrt as trt
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
def GiB(val):
return val * 1 << 30
def build_engine_onnx(model_file):
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network(0)
config = builder.create_builder_config()
parser = trt.OnnxParser(network, TRT_LOGGER)
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, GiB(4))
with open(model_file, "rb") as model:
if not parser.parse(model.read()):
print("ERROR: Failed to parse the ONNX file.")
for error in range(parser.num_errors):
print(parser.get_error(error))
return None
config.set_flag(trt.BuilderFlag.FP16)
engine_bytes = builder.build_serialized_network(network, config)
with open(model_file.replace("onnx", "engine"), "wb") as f:
f.write(engine_bytes)
build_engine_onnx("yolov7-ultralytics.onnx") # path to the modified ONNX file
- 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
Queremos agradecer a los autores de YOLOv7 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 sobre YOLOv7 puede consultarse en arXiv. Los autores han puesto su trabajo a disposición del público y se puede acceder al código base en GitHub. Agradecemos sus esfuerzos por hacer avanzar este campo y poner su trabajo a disposición de la comunidad en general.
PREGUNTAS FRECUENTES
¿Qué es YOLOv7 y por qué se considera un gran avance en la detección de objetos en tiempo real?
YOLOv7 es un modelo puntero de detección de objetos en tiempo real que alcanza una velocidad y una precisión inigualables. Supera a otros modelos, como YOLOX, YOLOv5 y PPYOLOE, tanto en el uso de parámetros como en la velocidad de inferencia. Entre las características distintivas de YOLOv7 se encuentran la reparametrizació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 comparaciones métricas con otros detectores de objetos de última generación, consulte el artículo YOLOv7.
¿En qué mejora YOLOv7 a modelos anteriores de YOLO como YOLOv4 y YOLOv5?
YOLOv7 introduce varias innovaciones, como la reparametrización del modelo y la asignación dinámica de etiquetas, que mejoran el proceso de formación y 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. Encontrará comparaciones detalladas en la tabla de rendimiento Comparación de YOLOv7 con los detectores de objetos SOTA.
¿Puedo utilizar YOLOv7 con las herramientas y plataformas de Ultralytics ?
Por ahora, Ultralytics sólo soporta 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, siga estos pasos:
- Clonar el repositorio YOLOv7:
git clone https://github.com/WongKinYiu/yolov7
- Navegue hasta el directorio clonado e instale las dependencias:
cd yolov7 pip install -r requirements.txt
-
Prepare su conjunto de datos y configure los parámetros del modelo de acuerdo con las instrucciones de uso proporcionadas en el repositorio. Para obtener más orientación, visite el repositorio GitHub de YOLOv7 para consultar la información y las actualizaciones más recientes.
-
Después del entrenamiento, puede exportar el modelo a ONNX o TensorRT para su uso en Ultralytics como se muestra en Ejemplos de uso.
¿Cuáles son las principales características y optimizaciones introducidas en YOLOv7?
YOLOv7 ofrece varias funciones clave que revolucionan la detección de objetos en tiempo real:
- Reparametrizació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 por pistas de grueso a fino para asignar objetivos dinámicos para salidas a través de diferentes ramas, mejorando la precisión.
- Escalado ampliado y compuesto: Utiliza eficientemente los parámetros y el cálculo para escalar el modelo para diversas aplicaciones en tiempo real.
- Eficacia: Reduce el recuento de parámetros en un 40% y el cómputo en un 50% en comparación con otros modelos del estado de la técnica, al tiempo que logra velocidades de inferencia más rápidas.
Para más detalles sobre estas funciones, consulte la sección Visión general de YOLOv7.