YOLOv7: مجموعة الحلول المجانية القابلة للتدريب#
تم إطلاق YOLOv7 في يوليو 2022، وكان بمثابة تقدم كبير في مجال اكتشاف الكائنات في الوقت الفعلي وقت صدوره. لقد حقق نسبة AP بلغت 56.8% على وحدة معالجة الرسوميات GPU V100، محققاً معايير قياسية جديدة عند إدخاله. تفوق نموذج YOLOv7 على أدوات اكتشاف الكائنات المعاصرة مثل YOLOR و YOLOX و Scaled-YOLOv4 و YOLOv5 من حيث السرعة والدقة. تم تدريب النموذج على مجموعة بيانات MS COCO من الصفر دون استخدام أي مجموعات بيانات أخرى أو أوزان مدربة مسبقاً. الشفرة المصدرية لنموذج YOLOv7 متوفرة على GitHub. تجدر الإشارة إلى أن النماذج الأحدث مثل YOLO11 وYOLO26 قد حققت منذ ذلك الحين دقة أعلى بكفاءة محسنة.

مقارنة كاشفات الأشياء الحديثة (SOTA)#
من النتائج في جدول مقارنة YOLO، نعلم أن الطريقة المقترحة تمتلك أفضل مقايضة بين السرعة والدقة بشكل شامل. إذا قارنا YOLOv7-tiny-SiLU مع YOLOv5-N (r6.1)، فإن طريقتنا أسرع بـ 127 إطاراً في الثانية وأكثر دقة بنسبة 10.7% من حيث AP. بالإضافة إلى ذلك، يمتلك YOLOv7 نسبة 51.4% AP بمعدل إطارات 161 إطاراً في الثانية، بينما يمتلك PPYOLOE-L بنفس نسبة AP معدل إطارات 78 إطاراً في الثانية فقط. من حيث استخدام المعلمات، يعد YOLOv7 أقل بنسبة 41% من PPYOLOE-L.
إذا قارنا نموذج YOLOv7-X بسرعة استدلال تبلغ 114 إطاراً في الثانية مع نموذج YOLOv5-L (r6.1) بسرعة استدلال تبلغ 99 إطاراً في الثانية، فإن YOLOv7-X يمكنه تحسين معدل AP بنسبة 3.9%. وإذا تم مقارنة YOLOv7-X بنموذج YOLOv5-X (r6.1) ذي الحجم المماثل، فإن سرعة الاستدلال لـ YOLOv7-X تكون أسرع بـ 31 إطاراً في الثانية. بالإضافة إلى ذلك، من حيث حجم المعلمات والحسابات، يوفر YOLOv7-X نسبة 22% من المعلمات و8% من الحسابات مقارنة بنموذج YOLOv5-X (r6.1)، ولكنه يحسن معدل AP بنسبة 2.2% (المصدر).
| النموذج | البارامترات (M) | FLOPs (G) | الحجم (بكسل) | FPS | APاختبار / تحقق 50-95 | APاختبار 50 | APاختبار 75 | APاختبار S | APاختبار M | APاختبار 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% |
نظرة عامة#
يعد اكتشاف الكائنات في الوقت الفعلي مكوناً هاماً في العديد من أنظمة رؤية الكمبيوتر، بما في ذلك تتبع الكائنات المتعددة، والقيادة الذاتية، والروبوتات، وتحليل الصور الطبية. في السنوات الأخيرة، ركز تطور اكتشاف الكائنات في الوقت الفعلي على تصميم بنيات تتسم بالفاعلية وتحسين سرعة الاستدلال لمختلف وحدات المعالجة المركزية (CPUs)، ووحدات معالجة الرسوميات (GPUs)، ووحدات المعالجة العصبية (NPUs). يدعم YOLOv7 كلاً من أجهزة معالجة الرسوميات المحمولة وأجهزة GPU، بدءاً من الحافة (edge) وحتى السحابة.
على عكس كاشفات الأشياء التقليدية في الوقت الفعلي التي تركز على تحسين البنية، يقدم YOLOv7 تركيزاً على تحسين عملية التدريب. يشمل ذلك وحدات وطرق تحسين مصممة لتحسين دقة اكتشاف الأشياء دون زيادة تكلفة الاستدلال، وهو مفهوم يُعرف باسم "مجموعة المزايا المجانية القابلة للتدريب" (trainable bag-of-freebies).
الميزات الرئيسية#
يقدم YOLOv7 العديد من الميزات الرئيسية:
-
إعادة تهيئة النموذج (Model Re-parameterization): يقترح YOLOv7 نموذجاً معاد تهيئته مخططاً له، وهي استراتيجية قابلة للتطبيق على الطبقات في شبكات مختلفة باستخدام مفهوم مسار انتشار التدرج.
-
تعيين التسميات الديناميكي (Dynamic Label Assignment): يطرح تدريب النموذج بطبقات إخراج متعددة مشكلة جديدة: "كيف يتم تعيين أهداف ديناميكية لمخرجات الفروع المختلفة؟" لحل هذه المشكلة، يقدم YOLOv7 طريقة جديدة لتعيين التسميات تسمى تعيين التسميات الموجه بالقيادة من الخشن إلى الدقيق (coarse-to-fine lead guided label assignment).
-
التحجيم الموسع والمركب (Extended and Compound Scaling): يقترح YOLOv7 طرق "توسيع" و"تحجيم مركب" لكاشف الأشياء في الوقت الفعلي والتي يمكنها الاستفادة بفعالية من المعلمات والحسابات.
-
الكفاءة: يمكن للطريقة المقترحة من قبل YOLOv7 تقليل حوالي 40% من المعلمات و50% من الحسابات لكاشف الأشياء في الوقت الفعلي المتطور، وتتميز بسرعة استدلال أسرع ودقة اكتشاف أعلى.
أمثلة الاستخدام#
لا تنشر Ultralytics أوزان yolov7.pt المدربة مسبقاً أو ملفات ultralytics/cfg/models/v7/ YAML، كما أن تدريب PyTorch الأصلي والاستدلال لـ YOLOv7 غير مدعومين بواسطة حزمة Python الخاصة بـ Ultralytics. ومع ذلك، يمكنك جلب نقطة تحقق (checkpoint) لـ YOLOv7 مُدربة في مستودع YOLOv7 الرئيسي إلى Ultralytics عن طريق تصديرها إلى ONNX أو TensorRT، كما هو موضح أدناه.
تصدير ONNX#
لاستخدام نموذج YOLOv7 ONNX مع Ultralytics:
-
(اختياري) قم بتثبيت Ultralytics وتصدير نموذج ONNX للحصول على التبعيات المطلوبة مثبتة تلقائياً:
pip install ultralytics yolo export model=yolo26n.pt format=onnx -
قم بتصدير نموذج YOLOv7 المطلوب باستخدام أداة التصدير في مستودع 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 -
قم بتعديل رسم بياني لنموذج ONNX ليكون متوافقاً مع Ultralytics باستخدام البرنامج النصي التالي:
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") -
يمكنك بعد ذلك تحميل نموذج ONNX المعدل وتشغيل الاستدلال به في Ultralytics بشكل طبيعي:
from ultralytics import ASSETS, YOLO model = YOLO("yolov7-ultralytics.onnx", task="detect") results = model(ASSETS / "bus.jpg")
تصدير TensorRT#
-
اتبع الخطوتين 1-2 في قسم تصدير ONNX.
-
قم بتثبيت حزمة
TensorRTPython:pip install tensorrt -
قم بتشغيل البرنامج النصي التالي لتحويل نموذج ONNX المعدل إلى محرك TensorRT:
from ultralytics.utils.export import export_engine export_engine("yolov7-ultralytics.onnx", half=True) -
تحميل وتشغيل النموذج في Ultralytics:
from ultralytics import ASSETS, YOLO model = YOLO("yolov7-ultralytics.engine", task="detect") results = model(ASSETS / "bus.jpg")
الاقتباسات والشكر#
نود أن نشكر مؤلفي YOLOv7 على مساهماتهم الكبيرة في مجال اكتشاف الأشياء في الوقت الفعلي:
@inproceedings{wang2023yolov7,
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},
booktitle={Proceedings of the IEEE/CVF conference on Computer Vision and Pattern Recognition (CVPR)},
pages={7464--7475},
year={2023}
}تم نشر الورقة البحثية الرسمية لـ YOLOv7 في موقع الوصول المفتوح CVF 2023، مع نسخة أوليّة على موقع arXiv. لقد جعل المؤلفون عملهم متاحاً للعامة، ويمكن الوصول إلى قاعدة الشفرات البرمجية على GitHub. نحن نقدر جهودهم في تطوير هذا المجال وجعل عملهم في متناول المجتمع الأوسع.
الأسئلة الشائعة#
ما هو YOLOv7 ولماذا يُعتبر طفرة في اكتشاف الكائنات في الوقت الفعلي؟#
YOLOv7، الذي تم إطلاقه في يوليو 2022، كان نموذجاً هاماً لاكتشاف الكائنات في الوقت الفعلي وحقق سرعة ودقة ممتازتين وقت صدوره. لقد تفوق على النماذج المعاصرة مثل YOLOX و YOLOv5 و PPYOLOE في استخدام المعلمات وسرعة الاستدلال على حد سواء. تشمل الميزات المميزة لـ YOLOv7 إعادة صياغة النماذج (model re-parameterization) وتعيين التسميات الديناميكية، مما يُمكّن من تحسين أداءه دون زيادة تكاليف الاستدلال. لمزيد من التفاصيل التقنية حول بنيته ومقاييس المقارنة مع أدوات اكتشاف الكائنات الأخرى المتقدمة، يُرجى الرجوع إلى ورقة بحث YOLOv7.
كيف يتحسن YOLOv7 مقارنة بنماذج YOLO السابقة مثل YOLOv4 وYOLOv5؟#
يقدم YOLOv7 العديد من الابتكارات، بما في ذلك إعادة صياغة النماذج وتعيين التسميات الديناميكية، والتي تعزز عملية التدريب وتحسن دقة الاستدلال. مقارنة بـ YOLOv5، يعزز YOLOv7 السرعة والدقة بشكل ملحوظ. على سبيل المثال، يحسن YOLOv7-X الدقة بنسبة 2.2% ويقلل المعلمات بنسبة 22% مقارنة بـ YOLOv5-X. يمكن العثور على مقارنات تفصيلية في جدول الأداء مقارنة YOLOv7 مع أدوات اكتشاف الكائنات SOTA.
هل يمكنني استخدام YOLOv7 مع أدوات ومنصات Ultralytics؟#
اعتباراً من الآن، تدعم Ultralytics فقط استدلال ONNX و TensorRT لـ YOLOv7. لتشغيل الإصدار المُصدر لـ YOLOv7 بتقنية ONNX و TensorRT باستخدام Ultralytics، تحقق من قسم أمثلة الاستخدام.
كيف أقوم بتدريب نموذج YOLOv7 مخصص باستخدام مجموعة البيانات الخاصة بي؟#
لتثبيت وتدريب نموذج YOLOv7 مخصص، اتبع الخطوات التالية:
-
استنسخ مستودع YOLOv7:
git clone https://github.com/WongKinYiu/yolov7 -
انتقل إلى الدليل المستنسخ وقم بتثبيت التبعيات:
cd yolov7 pip install -r requirements.txt -
قم بإعداد مجموعة البيانات الخاصة بك وتهيئة معاملات النموذج وفقاً لـتعليمات الاستخدام الواردة في المستودع. لمزيد من الإرشادات، تفضل بزيارة مستودع YOLOv7 على GitHub للحصول على أحدث المعلومات والتحديثات.
-
بعد التدريب، يمكنك تصدير النموذج إلى ONNX أو TensorRT لاستخدامه في Ultralytics كما هو موضح في قسم أمثلة الاستخدام.
ما هي الميزات والتحسينات الرئيسية التي تم إدخالها في YOLOv7؟#
يقدم YOLOv7 العديد من الميزات الرئيسية التي تحدث ثورة في اكتشاف الأشياء في الوقت الفعلي:
- إعادة تهيئة النموذج: يعزز أداء النموذج من خلال تحسين مسارات انتشار التدرج.
- تعيين التسميات الديناميكي: يستخدم طريقة موجهة بالقيادة من الخشن إلى الدقيق لتعيين أهداف ديناميكية للمخرجات عبر فروع مختلفة، مما يحسن الدقة.
- التحجيم الموسع والمركب: يستخدم بكفاءة المعلمات والحسابات لتوسيع نطاق النموذج لمختلف التطبيقات في الوقت الفعلي.
- الكفاءة: يقلل عدد المعلمات بنسبة 40% والحسابات بنسبة 50% مقارنة بالنماذج المتطورة الأخرى مع تحقيق سرعات استدلال أسرع.
لمزيد من التفاصيل حول هذه الميزات، راجع قسم نظرة عامة على YOLOv7.