Saltar para o conteúdo

YOLOv7: Saco de brindes treinável

O YOLOv7 é um detetor de objectos em tempo real de última geração que ultrapassa todos os detectores de objectos conhecidos, tanto em termos de velocidade como de precisão, na gama de 5 FPS a 160 FPS. Tem a maior precisão (56,8% AP) entre todos os detectores de objectos em tempo real conhecidos com 30 FPS ou mais em GPU V100. Além disso, o YOLOv7 supera outros detectores de objectos como o YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5, e muitos outros em termos de velocidade e precisão. O modelo é treinado no conjunto de dados MS COCO a partir do zero, sem utilizar quaisquer outros conjuntos de dados ou pesos pré-treinados. O código-fonte do YOLOv7 está disponível no GitHub.

Comparação do YOLOv7 com os detectores de objectos SOTA

Comparação dos detectores de objectos SOTA

A partir dos resultados da tabela de comparação YOLO , sabemos que o método proposto tem a melhor relação velocidade-precisão em termos globais. Se compararmos o YOLOv7-tiny-SiLU com o YOLOv5(r6.1), o nosso método é 127 fps mais rápido e 10,7% mais preciso em termos de PA. Além disso, o YOLOv7 tem 51,4% de PA a uma taxa de fotogramas de 161 fps, enquanto o PPYOLOE-L com o mesmo PA tem apenas uma taxa de fotogramas de 78 fps. Em termos de utilização de parâmetros, o YOLOv7 é 41% inferior ao PPYOLOE-L.

Se compararmos o YOLOv7-X com uma velocidade de inferência de 114 fps com o YOLOv5(r6.1) com uma velocidade de inferência de 99 fps, o YOLOv7-X pode melhorar o PA em 3,9%. Se o YOLOv7-X for comparado com o YOLOv5(r6.1) de escala semelhante, a velocidade de inferência do YOLOv7-X é 31 fps mais rápida. Além disso, em termos de quantidade de parâmetros e de computação, o YOLOv7-X reduz 22% dos parâmetros e 8% da computação em comparação com o YOLOv5(r6.1), mas melhora o PA em 2,2%(Fonte).

Desempenho

Modelo Parâmetros
(M)
FLOPs
(G)
Tamanho
(píxeis)
FPS APtest/ val
50-95
APtest
50
APtest
75
APtest
S
APtest
M
AProva
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%

Visão geral

A deteção de objectos em tempo real é um componente importante em muitos sistemas de visão por computador, incluindoo seguimento de vários objectos, a condução autónoma, a robótica e a análise de imagens médicas. Nos últimos anos, o desenvolvimento da deteção de objectos em tempo real tem-se centrado na conceção de arquitecturas eficientes e na melhoria da velocidade de inferência de vários CPUs, GPUs e unidades de processamento neural (NPUs). O YOLOv7 suporta GPU móvel e dispositivos GPU , desde a borda até a nuvem.

Ao contrário dos detectores de objectos tradicionais em tempo real, que se concentram na otimização da arquitetura, o YOLOv7 introduz um enfoque na otimização do processo de formação. Isto inclui módulos e métodos de otimização concebidos para melhorar a precisão da deteção de objectos sem aumentar o custo de inferência, um conceito conhecido como "trainable bag-of-freebies".

Caraterísticas principais

O YOLOv7 apresenta várias caraterísticas fundamentais:

  1. Re-parametrização do modelo: O YOLOv7 propõe um modelo re-parametrizado planeado, que é uma estratégia aplicável a camadas em diferentes redes com o conceito de caminho de propagação de gradiente.

  2. Atribuição dinâmica de etiquetas: A formação do modelo com várias camadas de saída apresenta uma nova questão: "Como atribuir objectivos dinâmicos para as saídas de diferentes ramos?" Para resolver este problema, o YOLOv7 introduz um novo método de atribuição de rótulos denominado atribuição de rótulos guiada por chumbo grosso a fino.

  3. Escalonamento estendido e composto: O YOLOv7 propõe métodos de "extensão" e "escala composta" para o detetor de objectos em tempo real que podem utilizar eficazmente os parâmetros e a computação.

  4. Eficiência: O método proposto pelo YOLOv7 pode reduzir eficazmente cerca de 40% dos parâmetros e 50% da computação do detetor de objectos em tempo real topo de gama, e tem uma velocidade de inferência mais rápida e uma maior precisão de deteção.

Exemplos de utilização

No momento em que este artigo foi escrito, Ultralytics apenas suporta a inferência ONNX e TensorRT para o YOLOv7.

Exportação ONNX

Para utilizar o modelo YOLOv7 ONNX com o Ultralytics:

  1. (Opcional) Instale Ultralytics e exporte um modelo ONNX para que as dependências necessárias sejam instaladas automaticamente:
pip install ultralytics
yolo export model=yolo11n.pt format=onnx
  1. Exportar o modelo YOLOv7 pretendido utilizando o exportador no repositório 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
  1. Modifique o gráfico do modelo ONNX para ser compatível com o Ultralytics utilizando o seguinte 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")
  1. Pode então carregar o modelo ONNX modificado e executar normalmente a inferência com ele no Ultralytics :
from ultralytics import ASSETS, YOLO

model = YOLO("yolov7-ultralytics.onnx", task="detect")

results = model(ASSETS / "bus.jpg")

Exportação TensorRT

  1. Siga os passos 1-2 na secção ExportaçãoONNX .

  2. Instalar o TensorRT Pacote Python :

pip install tensorrt
  1. Execute o seguinte script para converter o modelo ONNX modificado para o 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
  1. Carregar e executar o modelo no Ultralytics:
from ultralytics import ASSETS, YOLO

model = YOLO("yolov7-ultralytics.engine", task="detect")

results = model(ASSETS / "bus.jpg")

Citações e agradecimentos

Gostaríamos de agradecer aos autores do YOLOv7 pelas suas contribuições significativas no domínio da deteção de objectos em tempo 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}
}

O artigo original do YOLOv7 pode ser encontrado no arXiv. Os autores tornaram o seu trabalho publicamente disponível e a base de código pode ser acedida no GitHub. Agradecemos os seus esforços para fazer avançar o campo e tornar o seu trabalho acessível à comunidade em geral.

FAQ

O que é o YOLOv7 e porque é considerado um avanço na deteção de objectos em tempo real?

O YOLOv7 é um modelo avançado de deteção de objectos em tempo real que atinge uma velocidade e precisão sem paralelo. Ultrapassa outros modelos, tais como YOLOX, YOLOv5 e PPYOLOE, tanto na utilização de parâmetros como na velocidade de inferência. As caraterísticas distintivas do YOLOv7 incluem a re-parametrização do modelo e a atribuição dinâmica de etiquetas, que optimizam o seu desempenho sem aumentar os custos de inferência. Para mais detalhes técnicos sobre a sua arquitetura e métricas de comparação com outros detectores de objectos de última geração, consulte o documento YOLOv7.

Como é que o YOLOv7 melhora em relação aos modelos anteriores YOLO como o YOLOv4 e YOLOv5?

O YOLOv7 introduz várias inovações, incluindo a re-parametrização do modelo e a atribuição dinâmica de etiquetas, que melhoram o processo de formação e aumentam a precisão da inferência. Em comparação com YOLOv5, o YOLOv7 aumenta significativamente a velocidade e a precisão. Por exemplo, o YOLOv7-X melhora a precisão em 2,2% e reduz os parâmetros em 22% em comparação com YOLOv5-X. As comparações detalhadas podem ser encontradas na tabela de desempenho YOLOv7 comparação com detectores de objectos SOTA.

Posso utilizar o YOLOv7 com as ferramentas e plataformas Ultralytics ?

Atualmente, Ultralytics apenas suporta a inferência YOLOv7 ONNX e TensorRT . Para executar a versão exportada ONNX e TensorRT do YOLOv7 com o Ultralytics, consulte a secção Exemplos de utilização.

Como posso treinar um modelo YOLOv7 personalizado utilizando o meu conjunto de dados?

Para instalar e treinar um modelo YOLOv7 personalizado, siga estes passos:

  1. Clonar o repositório YOLOv7:
    git clone https://github.com/WongKinYiu/yolov7
    
  2. Navegue até ao diretório clonado e instale as dependências:
    cd yolov7
    pip install -r requirements.txt
    
  3. Prepare o seu conjunto de dados e configure os parâmetros do modelo de acordo com as instruções de utilização fornecidas no repositório. Para mais orientações, visite o repositório GitHub do YOLOv7 para obter as informações e actualizações mais recentes.

  4. Após o treino, pode exportar o modelo para ONNX ou TensorRT para utilização no Ultralytics , conforme mostrado em Exemplos de utilização.

Quais são as principais caraterísticas e optimizações introduzidas no YOLOv7?

O YOLOv7 oferece várias caraterísticas chave que revolucionam a deteção de objectos em tempo real:

  • Re-parametrização do modelo: Melhora o desempenho do modelo, optimizando os caminhos de propagação do gradiente.
  • Atribuição dinâmica de rótulos: Utiliza um método guiado por chumbo grosso a fino para atribuir alvos dinâmicos para saídas em diferentes ramos, melhorando a precisão.
  • Escalonamento estendido e composto: Utiliza parâmetros e computação de forma eficiente para escalar o modelo para várias aplicações em tempo real.
  • Eficiência: Reduz a contagem de parâmetros em 40% e a computação em 50% em comparação com outros modelos de última geração, ao mesmo tempo que atinge velocidades de inferência mais rápidas.

Para mais informações sobre estas funcionalidades, consulte a secção Descrição geral do YOLOv7.



📅C riado há 1 ano ✏️ Atualizado há 3 dias

Comentários