YOLOOv7: حقيبة مجانية قابلة للتدريب
YOLOv7 هو أحدث كاشف للأجسام في الوقت الحقيقي يتفوق على جميع أجهزة الكشف عن الأجسام المعروفة من حيث السرعة والدقة في النطاق من 5 إطارات في الثانية إلى 160 إطارًا في الثانية. فهو يتمتع بأعلى دقة (56.8% في الثانية) من بين جميع أجهزة الكشف عن الأجسام المعروفة في الوقت الحقيقي بمعدل 30 إطارًا في الثانية أو أعلى على GPU V100. وعلاوةً على ذلك، يتفوق YOLOv7 على أجهزة كشف الأجسام الأخرى مثل YOLOR و YOLOX و Scaled-YOLOv4 و YOLOv5 وغيرها الكثير من حيث السرعة والدقة. تم تدريب النموذج على مجموعة بيانات MS COCO من الصفر دون استخدام أي مجموعات بيانات أخرى أو أوزان مدربة مسبقًا. الكود المصدري لنموذج YOLOv7 متاح على GitHub.
مقارنة بين كاشفات الأجسام 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% (المصدر).
الأداء
الطراز | بارامز (م) |
(G) |
الحجم (بالبكسل) |
FPS | اختبار APtest/ فال 50-95 |
اختبار APtest 50 |
اختبار APtest 75 |
APtest S |
APtest M |
APtest L |
---|---|---|---|---|---|---|---|---|---|---|
يولوكس-إس | 9.0 | 26.8 | 640 | 102 | 40.5% / 40.5% | - | - | - | - | - |
يولوكس-إم | 25.3 | 73.8 | 640 | 81 | 47.2% / 46.9% | - | - | - | - | - |
يولوكس-إل | 54.2 | 155.6 | 640 | 69 | 50.1% / 49.7% | - | - | - | - | - |
يولوكس-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-ن (ص6.1) | 1.9 | 4.5 | 640 | 159 | - / 28.0% | - | - | - | - | - |
YOLOv5-S (ص6.1) | 7.2 | 16.5 | 640 | 156 | - / 37.4% | - | - | - | - | - |
YOLOv5-م (ص6.1) | 21.2 | 49.0 | 640 | 122 | - / 45.4% | - | - | - | - | - |
YOLOv5-ل (ص6.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% |
يولوف 7 | 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 التركيز على تحسين عملية التدريب. يتضمن ذلك وحدات وأساليب تحسين مصممة لتحسين دقة اكتشاف الأجسام دون زيادة تكلفة الاستدلال، وهو مفهوم يُعرف باسم "حقيبة الأجسام المجانية القابلة للتدريب".
الميزات الرئيسية
يقدم YOLOv7 العديد من الميزات الرئيسية:
-
إعادة تحديد النموذج: يقترح YOLOv7 نموذجًا مخططًا لإعادة المعايرة، وهي استراتيجية قابلة للتطبيق على طبقات في شبكات مختلفة بمفهوم مسار الانتشار المتدرج.
-
تعيين التسمية الديناميكية: يمثل تدريب النموذج مع طبقات مخرجات متعددة مشكلة جديدة: "كيف يمكن تعيين أهداف ديناميكية لمخرجات الفروع المختلفة؟ لحل هذه المشكلة، يقدم YOLOv7 طريقة جديدة لتعيين التسميات تُدعى تعيين التسمية الموجّهة من الخشن إلى الدقيق.
-
القياس الموسع والمركب: يقترح YOLOv7 طرق "التوسيع" و"القياس المركب" لكاشف الأجسام في الوقت الحقيقي التي يمكن أن تستخدم المعلمات والحساب بفعالية.
-
الكفاءة: يمكن للطريقة المقترحة من قبل YOLOv7 أن تقلل بشكل فعال حوالي 40% من المعلمات و50% من العمليات الحسابية لأحدث كاشف للأجسام في الوقت الحقيقي، وتتميز بسرعة استدلال أسرع ودقة كشف أعلى.
أمثلة على الاستخدام
في وقت كتابة هذا التقرير، تدعم Ultralytics استنتاج ONNX و TensorRT فقط لـ YOLOv7.
تصدير ONNX
لاستخدام نموذج YOLOv7 ONNX مع Ultralytics:
-
(اختياري) قم بتثبيت Ultralytics وتصدير نموذج ONNX لتثبيت التبعيات المطلوبة تلقائيًا:
pip install ultralytics yolo export model=yolo11n.pt format=onnx
-
قم بتصدير نموذج YOLOv7 المطلوب باستخدام أداة التصدير في YOLOv7 repo:
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 هو نموذج متطور للكشف عن الأجسام في الوقت الحقيقي يحقق سرعة ودقة لا مثيل لهما. وهو يتفوق على النماذج الأخرى، مثل 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 العديد من الميزات الرئيسية التي تُحدث ثورة في اكتشاف الأجسام في الوقت الحقيقي:
- إعادة تحديد النموذج: تحسين أداء النموذج من خلال تحسين مسارات انتشار التدرج.
- تعيين التسمية الديناميكية: يستخدم طريقة موجهة من الخشنة إلى الدقيقة لتعيين الأهداف الديناميكية للمخرجات عبر الفروع المختلفة، مما يحسن الدقة.
- التحجيم الموسع والمركب: تستخدم المعلمات والحسابات بكفاءة لتوسيع نطاق النموذج لمختلف التطبيقات في الوقت الحقيقي.
- الكفاءة: يقلل عدد المعلمات بنسبة 40% والعمليات الحسابية بنسبة 50% مقارنةً بالنماذج الحديثة الأخرى مع تحقيق سرعات استنتاج أسرع.
لمزيد من التفاصيل حول هذه الميزات، راجع قسم نظرة عامة على YOLOv7.