Passer au contenu

YOLOv7 : Sac de cadeaux gratuit pouvant être entraîné

YOLOv7 est un détecteur d'objets en temps réel de pointe qui surpasse tous les détecteurs d'objets connus en termes de vitesse et de précision dans la plage de 5 FPS à 160 FPS. Il possède la plus haute précision (56,8 % AP) parmi tous les détecteurs d'objets en temps réel connus avec 30 FPS ou plus sur GPU V100. De plus, YOLOv7 surpasse d'autres détecteurs d'objets tels que YOLOR, YOLOX, Scaled-YOLOv4, YOLOv5 et bien d'autres en termes de vitesse et de précision. Le modèle est entraîné sur l'ensemble de données MS COCO à partir de zéro sans utiliser d'autres ensembles de données ni de poids pré-entraînés. Le code source de YOLOv7 est disponible sur GitHub.

Comparaison de YOLOv7 avec les détecteurs d'objets SOTA

Comparaison des détecteurs d'objets SOTA

D'après les résultats du tableau comparatif YOLO, nous savons que la méthode proposée offre le meilleur compromis vitesse-précision. Si nous comparons YOLOv7-tiny-SiLU avec YOLOv5-N (r6.1), notre méthode est 127 fps plus rapide et 10,7 % plus précise en AP. De plus, YOLOv7 a 51,4 % d'AP à une fréquence d'images de 161 fps, tandis que PPYOLOE-L avec la même AP n'a qu'une fréquence d'images de 78 fps. En termes d'utilisation des paramètres, YOLOv7 est 41 % inférieur à PPYOLOE-L.

Si nous comparons YOLOv7-X avec une vitesse d'inférence de 114 fps à YOLOv5-L (r6.1) avec une vitesse d'inférence de 99 fps, YOLOv7-X peut améliorer l'AP de 3,9 %. Si YOLOv7-X est comparé à YOLOv5-X (r6.1) d'une échelle similaire, la vitesse d'inférence de YOLOv7-X est de 31 fps plus rapide. De plus, en termes de quantité de paramètres et de calcul, YOLOv7-X réduit de 22 % les paramètres et de 8 % le calcul par rapport à YOLOv5-X (r6.1), mais améliore l'AP de 2,2 % (Source).

Performance

Modèle Paramètres
(M)
FLOPs
(G)
Taille
(pixels)
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%

Aperçu

La détection d’objets en temps réel est un élément important dans de nombreux systèmes de vision par ordinateur, y compris le suivi multi-objets, la conduite autonome, la robotique et l’analyse d’images médicales. Ces dernières années, le développement de la détection d’objets en temps réel s’est concentré sur la conception d’architectures efficaces et l’amélioration de la vitesse d’inférence de divers CPU, GPU et unités de traitement neuronal (NPU). YOLOv7 prend en charge les appareils GPU mobiles et GPU, de la périphérie au cloud.

Contrairement aux détecteurs d'objets en temps réel traditionnels qui se concentrent sur l'optimisation de l'architecture, YOLOv7 introduit une approche axée sur l'optimisation du processus de formation. Cela comprend des modules et des méthodes d'optimisation conçus pour améliorer la précision de la détection d'objets sans augmenter le coût d'inférence, un concept connu sous le nom de « trainable bag-of-freebies ».

Principales caractéristiques

YOLOv7 introduit plusieurs fonctionnalités clés :

  1. Re-paramétrisation du modèle : YOLOv7 propose un modèle re-paramétré planifié, qui est une stratégie applicable aux couches de différents réseaux avec le concept de chemin de propagation du gradient.

  2. Attribution dynamique d'étiquettes : L'entraînement du modèle avec plusieurs couches de sortie présente un nouveau problème : « Comment attribuer des cibles dynamiques aux sorties des différentes branches ? » Pour résoudre ce problème, YOLOv7 introduit une nouvelle méthode d'attribution d'étiquettes appelée attribution d'étiquettes guidée du grossier au fin.

  3. Mise à l'échelle étendue et composée : YOLOv7 propose des méthodes de « mise à l'échelle étendue » et « composée » pour le détecteur d'objets en temps réel qui peuvent utiliser efficacement les paramètres et le calcul.

  4. Efficacité : La méthode proposée par YOLOv7 peut réduire efficacement d'environ 40 % les paramètres et de 50 % le calcul du détecteur d'objets en temps réel de pointe, et a une vitesse d'inférence plus rapide et une précision de détection plus élevée.

Exemples d'utilisation

Au moment de la rédaction, Ultralytics ne prend en charge que l'inférence ONNX et TensorRT pour YOLOv7.

Exportation ONNX

Pour utiliser le modèle YOLOv7 ONNX avec Ultralytics:

  1. (Facultatif) Installez Ultralytics et exportez un modèle ONNX pour que les dépendances requises soient automatiquement installées :

    pip install ultralytics
    yolo export model=yolo11n.pt format=onnx
    
  2. Pour exporter le modèle YOLOv7 souhaité, utilisez l'outil d'exportation dans le référentiel 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. Modifiez le graphe du modèle ONNX pour qu'il soit compatible avec Ultralytics à l'aide du script suivant :

    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. Vous pouvez ensuite charger le modèle ONNX modifié et exécuter l'inférence avec celui-ci dans Ultralytics normalement :

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

Exportation TensorRT

  1. Suivez les étapes 1 et 2 de la section Exportation ONNX.

  2. Installez le TensorRT Paquet Python :

    pip install tensorrt
    
  3. Exécutez le script suivant pour convertir le modèle ONNX modifié en moteur TensorRT :

    from ultralytics.utils.export import export_engine
    
    export_engine("yolov7-ultralytics.onnx", half=True)
    
  4. Charger et exécuter le modèle dans Ultralytics :

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

Citations et remerciements

Nous tenons à remercier les auteurs de YOLOv7 pour leurs contributions significatives dans le domaine de la détection d'objets en temps réel :

@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'article original sur YOLOv7 est disponible sur arXiv. Les auteurs ont rendu leur travail accessible au public, et le code source est accessible sur GitHub. Nous apprécions leurs efforts pour faire progresser le domaine et rendre leur travail accessible à la communauté au sens large.

FAQ

Qu'est-ce que YOLOv7 et pourquoi est-il considéré comme une avancée dans le domaine de la détection d'objets en temps réel ?

YOLOv7 est un modèle de détection d'objets en temps réel de pointe qui atteint une vitesse et une précision inégalées. Il surpasse d'autres modèles, tels que YOLOX, YOLOv5 et PPYOLOE, tant en termes d'utilisation des paramètres que de vitesse d'inférence. Les caractéristiques distinctives de YOLOv7 incluent sa re-paramétrisation du modèle et son assignation dynamique d'étiquettes, qui optimisent ses performances sans augmenter les coûts d'inférence. Pour plus de détails techniques sur son architecture et les métriques de comparaison avec d'autres détecteurs d'objets de pointe, consultez l'article sur YOLOv7.

Comment YOLOv7 améliore-t-il les modèles YOLO précédents tels que YOLOv4 et YOLOv5 ?

YOLOv7 introduit plusieurs innovations, notamment la re-paramétrisation du modèle et l'assignation dynamique d'étiquettes, qui améliorent le processus d'entraînement et augmentent la précision de l'inférence. Comparé à YOLOv5, YOLOv7 améliore considérablement la vitesse et la précision. Par exemple, YOLOv7-X améliore la précision de 2,2 % et réduit les paramètres de 22 % par rapport à YOLOv5-X. Des comparaisons détaillées sont disponibles dans le tableau de performances Comparaison de YOLOv7 avec les détecteurs d'objets SOTA.

Puis-je utiliser YOLOv7 avec les outils et plateformes Ultralytics ?

À l'heure actuelle, Ultralytics ne prend en charge que l'inférence ONNX et TensorRT pour YOLOv7. Pour exécuter la version de YOLOv7 exportée en ONNX et TensorRT avec Ultralytics, consultez la section Exemples d'utilisation.

Comment puis-je entraîner un modèle YOLOv7 personnalisé en utilisant mon ensemble de données ?

Pour installer et entraîner un modèle YOLOv7 personnalisé, suivez ces étapes :

  1. Cloner le dépôt YOLOv7 :
    git clone https://github.com/WongKinYiu/yolov7
    
  2. Naviguez jusqu'au répertoire cloné et installez les dépendances :
    cd yolov7
    pip install -r requirements.txt
    
  3. Préparez votre jeu de données et configurez les paramètres du modèle conformément aux instructions d'utilisation fournies dans le dépôt. Pour plus d'informations, consultez le dépôt GitHub de YOLOv7 pour obtenir les dernières informations et mises à jour.

  4. Après l’entraînement, vous pouvez exporter le modèle vers ONNX ou TensorRT pour l’utiliser dans Ultralytics, comme indiqué dans Exemples d’utilisation.

Quelles sont les principales caractéristiques et optimisations introduites dans YOLOv7 ?

YOLOv7 offre plusieurs fonctionnalités clés qui révolutionnent la détection d'objets en temps réel :

  • Re-paramétrisation du modèle : Améliore les performances du modèle en optimisant les chemins de propagation du gradient.
  • Assignation dynamique d'étiquettes : Utilise une méthode guidée du général au particulier pour attribuer des cibles dynamiques pour les sorties sur différentes branches, améliorant ainsi la précision.
  • Mise à l'échelle étendue et composée : Utilise efficacement les paramètres et le calcul pour mettre à l'échelle le modèle pour diverses applications en temps réel.
  • Efficacité : Réduit le nombre de paramètres de 40 % et le calcul de 50 % par rapport aux autres modèles de pointe tout en atteignant des vitesses d'inférence plus rapides.

Pour plus de détails sur ces fonctionnalités, consultez la section Présentation de YOLOv7.



📅 Créé il y a 1 an ✏️ Mis à jour il y a 2 mois

Commentaires