YOLOv7: حقيبة المجانيات القابلة للتدريب (Trainable Bag-of-Freebies)
يُعد YOLOv7، الذي تم إصداره في يوليو 2022، تقدمًا كبيرًا في اكتشاف الكائنات في الوقت الفعلي في وقت إصداره. حقق 56.8% AP على وحدة معالجة الرسومات 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 | 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% |
نظرة عامة
يعد اكتشاف الأشياء في الوقت الفعلي مكونًا مهمًا في العديد من أنظمة رؤية الحاسوب، بما في ذلك تتبع الكائنات المتعدد، والقيادة الذاتية، والروبوتات، وتحليل الصور الطبية. في السنوات الأخيرة، ركز تطوير اكتشاف الأشياء في الوقت الفعلي على تصميم بنيات فعالة وتحسين سرعة الاستدلال لمختلف وحدات المعالجة المركزية (CPUs)، ووحدات معالجة الرسومات (GPUs)، ووحدات المعالجة العصبية (NPUs). يدعم YOLOv7 كلاً من أجهزة GPU المحمولة وأجهزة GPU، بدءاً من الحافة وحتى السحابة.
على عكس كاشفات الأشياء التقليدية في الوقت الفعلي التي تركز على تحسين البنية، يقدم YOLOv7 تركيزاً على تحسين عملية التدريب. يشمل ذلك وحدات وطرق تحسين مصممة لتحسين دقة اكتشاف الأشياء دون زيادة تكلفة الاستدلال، وهو مفهوم يُعرف باسم "حقيبة الهدايا القابلة للتدريب" (trainable bag-of-freebies).
الميزات الرئيسية
يقدم YOLOv7 العديد من الميزات الرئيسية:
-
إعادة تحديد معلمات النموذج (Model Re-parameterization): يقترح YOLOv7 نموذجاً مخططاً ومعاد تحديد معلماته، وهي استراتيجية قابلة للتطبيق على الطبقات في شبكات مختلفة مع مفهوم مسار انتشار التدرج.
-
تعيين التسميات الديناميكي (Dynamic Label Assignment): يطرح تدريب النموذج بطبقات إخراج متعددة قضية جديدة: "كيفية تعيين أهداف ديناميكية لمخرجات الفروع المختلفة؟". لحل هذه المشكلة، يقدم YOLOv7 طريقة جديدة لتعيين التسميات تسمى تعيين التسميات الموجه بالقيادة من الخشن إلى الدقيق.
-
التحجيم الممتد والمركب (Extended and Compound Scaling): يقترح YOLOv7 طرق "توسيع" و"تحجيم مركب" لكاشف الأشياء في الوقت الفعلي والتي يمكنها استخدام المعلمات والحسابات بفعالية.
-
الكفاءة: يمكن للطريقة المقترحة بواسطة YOLOv7 تقليل حوالي 40% من المعلمات و50% من الحسابات الخاصة بأحدث كاشف للأشياء في الوقت الفعلي، وتتميز بسرعة استدلال أكبر ودقة اكتشاف أعلى.
أمثلة الاستخدام
لا تقوم Ultralytics بنشر أوزان مدربة مسبقاً لـ yolov7.pt أو ملفات ultralytics/cfg/models/v7/ بتنسيق YAML، كما أن التدريب والاستدلال الأصلي بنظام PyTorch لـ YOLOv7 غير مدعوم من قبل حزمة Ultralytics Python. ومع ذلك، يمكنك جلب نقطة فحص (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.
-
قم بتثبيت حزمة
TensorRTبلغة Python: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 لمساهماتهم الكبيرة في مجال اكتشاف الأشياء في الوقت الفعلي:
@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}
}يمكن العثور على ورقة YOLOv7 الأصلية على arXiv. وقد أتاح المؤلفون عملهم للجمهور، ويمكن الوصول إلى قاعدة الأكواد على GitHub. نحن نقدر جهودهم في تطوير هذا المجال وإتاحة أعمالهم للمجتمع الأوسع.
الأسئلة الشائعة
ما هو YOLOv7 ولماذا يُعتبر اختراقاً في اكتشاف الأشياء في الوقت الفعلي؟
كان YOLOv7، الذي تم إصداره في يوليو 2022، نموذجاً هاماً لاكتشاف الأشياء في الوقت الفعلي حقق سرعة ودقة ممتازتين في وقت إصداره. لقد تفوق على النماذج المعاصرة مثل YOLOX وYOLOv5 وPPYOLOE في كل من استخدام المعلمات وسرعة الاستدلال. تشمل الميزات المميزة لـ YOLOv7 إعادة تحديد معلمات النموذج وتعيين التسميات الديناميكي، والتي تعمل على تحسين أدائه دون زيادة تكاليف الاستدلال. لمزيد من التفاصيل الفنية حول بنيته ومقاييس المقارنة مع كاشفات الأشياء الأخرى المتطورة، راجع ورقة YOLOv7 البحثية.
كيف يعمل YOLOv7 على التحسين مقارنة بنماذج YOLO السابقة مثل YOLOv4 وYOLOv5؟
يقدم YOLOv7 العديد من الابتكارات، بما في ذلك إعادة تحديد معلمات النموذج وتعيين التسميات الديناميكي، والتي تعزز عملية التدريب وتحسن دقة الاستدلال. مقارنة بـ YOLOv5، يعزز YOLOv7 السرعة والدقة بشكل كبير. على سبيل المثال، يعمل YOLOv7-X على تحسين الدقة بنسبة 2.2% وتقليل المعلمات بنسبة 22% مقارنة بـ YOLOv5-X. يمكن العثور على مقارنات تفصيلية في جدول الأداء مقارنة YOLOv7 مع كاشفات الأشياء المتطورة (SOTA).
هل يمكنني استخدام YOLOv7 مع أدوات ومنصات Ultralytics؟
اعتباراً من الآن، تدعم Ultralytics فقط استدلال YOLOv7 عبر ONNX وTensorRT. لتشغيل إصدار 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 العديد من الميزات الرئيسية التي تحدث ثورة في اكتشاف الأشياء في الوقت الفعلي:
- إعادة تحديد معلمات النموذج (Model Re-parameterization): يعزز أداء النموذج من خلال تحسين مسارات انتشار التدرج.
- تعيين التسميات الديناميكي (Dynamic Label Assignment): يستخدم طريقة موجهة بالقيادة من الخشن إلى الدقيق لتعيين أهداف ديناميكية للمخرجات عبر فروع مختلفة، مما يحسن الدقة.
- التحجيم الممتد والمركب (Extended and Compound Scaling): يستخدم المعلمات والحسابات بكفاءة لتوسيع نطاق النموذج لمختلف التطبيقات في الوقت الفعلي.
- الكفاءة: يقلل عدد المعلمات بنسبة 40% والحسابات بنسبة 50% مقارنة بالنماذج المتطورة الأخرى مع تحقيق سرعات استدلال أسرع.
لمزيد من التفاصيل حول هذه الميزات، راجع قسم نظرة عامة على YOLOv7.