الوحدة 3 — الكشف ذو المرحلة الواحدة: YOLO وSSD
انتهت الوحدة السابقة إلى نتيجة عمليّة: عائلة R-CNN تُقدّم دقّة ممتازة لكنّها بطيئة جدًّا للتطبيقات الزمنية الحقيقية. لتحليل فيديو كاميرا التقاطع بسرعة 30 إطارًا في الثانية على جهاز متواضع، نحتاج إلى مقاربة أخرى: كواشف ذات مرحلة واحدة تنتج التنبّؤات مباشرة من الشبكة بلا مرحلة اقتراح.
المبدأ الأساسي: تنبّؤات كثيفة على شبكة
الفكرة الجوهرية بسيطة: نُقسّم الصورة إلى شبكة خلايا، ونجعل كلّ خليّة مسؤولة عن التنبّؤ بالأجسام التي يقع مركزها فيها. لكلّ خليّة، تُنتج الشبكة عدّة تنبّؤات مباشرةً:
- إحداثيات صناديق: إزاحة نسبةً إلى الخليّة، وعرض وارتفاع
- درجة ثقة تُقدّر احتمال احتواء الخليّة على جسم
- توزيع احتمالي على الأصناف
لا مرحلة اقتراح، لا شبكتان منفصلتان، لا حساب مضاعف. مرور أمامي واحد على الصورة يُعطي كلّ التنبّؤات دفعةً واحدة. هذا ما يعطي هذه العائلة اسمها الشائع: «تنظر مرّة واحدة فقط» (You Only Look Once).
YOLO: تاريخ من التبسيط
YOLOv1 الذي طرحه Joseph Redmon في 2016 قسّم الصورة إلى شبكة 7×7، ولم يستخدم مراسي. كان سريعًا لكنّه ضعيفًا على الأجسام الصغيرة والمزدحمة، وهذا بالضبط ما نواجهه على تقاطع طرق مزدحم عند ساعة الذروة.
طرح YOLOv2 المراسي (سنعود إليها في الوحدة 4)، وYOLOv3 هرم السمات على ثلاث مقاييس متعدّدة لالتقاط الأجسام بأحجامها المختلفة. YOLOv4 وYOLOv5 حسّنا الأداء عبر تقنيات تدريب أفضل: تكثيف Mosaic، وMixUp، وضبط أنيق للأوزان.
اليوم، YOLOv8 من Ultralytics هو المرجع العملي. أضاف ثلاث فوائد ملموسة: بلا مراسي (anchor-free) — التنبّؤ المباشر لموقع الجسم دون مراسي مُعرَّ فة سلفًا، ما يُبسّط التدريب؛ فصل رؤوس التصنيف والصندوق لخفض التداخل بين المهمّتين؛ ودعم متكامل للتقطيع والتصنيف في المكتبة نفسها.
يُقدّم YOLOv8-n (النسخة nano) قرابة 100 إطار في الثانية على GPU متوسّط، وهو ما يُغطّي حاجات المشروع الزمنية بسهولة.
from ultralytics import YOLO
# تحميل النموذج المدرب مسبقا على COCO
model = YOLO("yolov8n.pt") # nano: اسرع وأخف
# model = YOLO("yolov8m.pt") # medium: توازن جيد
# model = YOLO("yolov8l.pt") # large: دقة اعلى
# كشف على صورة من كاميرا التقاطع
results = model(
"carrefour_10h32.jpg",
conf=0.5, # عتبة الثقة
iou=0.45, # عتبة NMS (الوحدة 4)
classes=[0, 2, 5], # مشاة، سيارة، حافلة في COCO
)
# نقرا اول نتيجة (صورة واحدة)
result = results[0]
boxes = result.boxes.xyxy # (N, 4)
scores = result.boxes.conf # (N,)
labels = result.boxes.cls # (N,)
print(f"عدد الاجسام المكتشفة: {len(boxes)}")
SSD: مقاييس متعدّدة على طبقات مختلفة
Single Shot MultiBox Detector (Liu et al.، 2016) طبّق فكرة قريبة، لكنّه اختار الكشف على مقاييس متعدّدة من طبقات مختلفة للشبكة. الطبقات المبكرة، ذات الدقّة العالية، تكشف الأجسام الصغيرة. والطبقات العميقة، ذات الدقّة المنخفضة والحقل الاستقبالي الواسع، تكشف الأجسام الكبيرة.
هذا التصميم يعالج مباشرة تحدّي مشروعنا: مُشاة صغير في أعمق الصورة مقابل حافلة تحتلّ ربع الإطار. SSD كان أوّل من عالج هذا صراحةً، وطُبّق لاحقًا في YOLOv3 وما بعده باسم Feature Pyramid Network (FPN).
RetinaNet وFocal Loss: مشكلة عدم توازن الأصناف
الكواشف ذات المرحلة الواحدة عانت من مشكلة كامنة: معظم مواضع الشبكة خلفية، وأقلّية ضئيلة تحتوي على أجسام. حين نستخدم إنتروبيا متقاطعة قياسية، آلاف مواضع الخلفية سهلة التصنيف تُهيمن على التدرّج وتُقزّم إسهام الأجسام النادرة والصعبة.
طرح RetinaNet (Lin et al.، 2017) Focal Loss، خسارة معدّلة تُخفض وزن الأمثلة السهلة وتُبرز الصعبة:
حيث احتمال النموذج للصنف الصحيح. حين يكون التنبّؤ صائبًا وواثقًا ()، العامل يُقارب الصفر، فيصير إسهام هذا المثال في الخسارة مهملًا. أمّا الأمثلة الصعبة، حيث صغير، فتحتفظ بوزن كامل تقريبًا.
القيمة هي الأكثر استعمالًا. يُحوّل هذا التعديل كواشف المرحلة الواحدة إلى منافسين حقيقيين لعائلة R-CNN على الدقّة، دون فقدان مزيّة السرعة.