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 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 :
-
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.
-
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.
-
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.
-
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:
-
(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
-
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
-
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")
-
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
-
Suivez les étapes 1 et 2 de la section Exportation ONNX.
-
Installez le
TensorRT
Paquet Python :pip install tensorrt
-
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)
-
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 :
- Cloner le dépôt YOLOv7 :
git clone https://github.com/WongKinYiu/yolov7
- Naviguez jusqu'au répertoire cloné et installez les dépendances :
cd yolov7 pip install -r requirements.txt
-
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.
-
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.