Ultralytics YOLO27: انضم إلى قائمة الانتظار.
Get Started
الدرسمبتدئ

قسّم مجموعة البيانات بشكل صحيح

قِس مدى تسرّب البيانات في التقسيمات العشوائية، وقسّم المجموعات الكاملة مثل المقاطع أو الكاميرات أو الأيام باستخدام برنامج نصي، وتحقّق من تغطية الفئات، وثبّت مجموعة الاختبار.

يؤدي التقسيم غير المدروس إلى مقياس تثق به لكنه غير صحيح. عندما تقع إطارات فيديو متجاورة في مجموعتي التدريب والتحقق، يقيس mAP التحقق التذكّر بدلًا من القدرة على التعميم، ولا تظهر الفجوة إلا عند التشغيل الفعلي. يرتبط كل رقم تبلّغ عنه عن النموذج بهذا التقسيم، لذا اختره بعناية مرة واحدة وأبقِه ثابتًا.

النتيجة

قسّم مجموعة البيانات حسب المجموعات باستخدام برنامج نصي، وأثبت عدم عبور أي مجموعة لحدود التقسيم، وثبّت مجموعة الاختبار لإجراء قرار قبول أو رفض نهائي واحد.

المسار السريع
إذا كنت تعرف الأساسيات بالفعل، فإليك النسخة المختصرة.
  1. ابدأ بتقسيم 70/15/15 إلى تدريب/تحقق/اختبار، وعدّله وفقًا لحجم مجموعة البيانات.

  2. قسّم المجموعات كاملةً (المقطع، الكاميرا، اليوم، الموقع، العميل)، ولا تقسّم الإطارات المفردة المترابطة مطلقًا.

  3. تحقّق من ظهور كل فئة في كل تقسيم؛ وعالج النواقص بإضافة مزيد من المجموعات، لا بنقل الإطارات.

  4. اضبط النموذج باستخدام مجموعة التحقق؛ ولا تلمس مجموعة الاختبار إلا مرة واحدة، لاتخاذ قرار القبول أو الرفض النهائي.

عملي

ثلاثة تقسيمات، وثلاث مهام#

التقسيمالحصة المعتادةالمهمة
التدريب70%يتعلّم النموذج أوزانه منها
التحقق15%اختيار أفضل حقبة، ومقارنة عمليات التشغيل، وضبط الإعدادات
الاختبار15%قرار قبول أو رفض نهائي واحد وفقًا لاختبار القبول

تحدّد إرشادات Ultralytics النطاق بنسبة 70–80% للتدريب و10–20% لكل من التحقق والاختبار: يقترح مراحل مشروع الرؤية الحاسوبية تخصيص 10–15% لكل منهما، بينما يستخدم دليل المعالجة المسبقة تقسيمًا بنسبة 70/20/10. احسب الحصص وفق عدد الكائنات وكذلك الصور، إذ قد تحتوي صورة مزدحمة واحدة على تسميات أكثر من عشر صور قليلة العناصر. أهمية النسب المئوية الدقيقة أقل بكثير من أهمية الغرض من كل تقسيم.

تسرّب التقسيمات العشوائية البيانات المترابطة#

الإطاران 124 و125 من المقطع نفسه متطابقان تقريبًا. إذا وقع أحدهما في التدريب والآخر في التحقق، فسيُقيَّم النموذج في التحقق باستخدام صور سبق أن شاهدها فعليًا. قِس ذلك على مجموعة التدريب العملي من جمع بيانات عالية الجودة وممثّلة، التي تبدأ أسماء ملفاتها بمفتاح مجموعة للكاميرا واليوم:

import random
from pathlib import Path

images = sorted(Path("datasets/practice/images").glob("*.jpg"))
random.Random(0).shuffle(images)
train, val = images[:90], images[90:109]  # a random per-image 70/15 split

def group(image):
    return image.stem.rsplit("_", 1)[0]

shared = {group(p) for p in train} & {group(p) for p in val}
print(f"{len(shared)} of {len({group(p) for p in val})} val groups also appear in train")
13 of 13 val groups also appear in train

تظهر كل مجموعة للكاميرا واليوم في التحقق وكذلك في التدريب. في اللقطات الواقعية، يعني ذلك أن إطارات التحقق تشترك مع إطارات التدريب في الإضاءة والخلفية، وغالبًا في العناصر نفسها تمامًا؛ لذا يبدو mAP التحقق ممتازًا، بينما لا يكون mAP التشغيل الفعلي كذلك.

اختر وحدة التقسيم#

اختر المجموعة التي تتوافق مع متطلبات التعميم في بيئة النشر:

عند الشك، قسّم وفق أعمّ وحدة يمكنك تحمّلها؛ فهي تعطي النتيجة الأكثر صدقًا. لا تكون التقسيمات العشوائية على مستوى الصور آمنة إلا عندما تكون كل صورة ملتقطة بصورة مستقلة، مثل صور المنتجات الملتقطة على مدى أسابيع.

قسّم حسب المجموعة باستخدام الشيفرة#

يسند هذا البرنامج النصي المجموعات كاملةً إلى التقسيمات حتى يصل كل تقسيم إلى حصته البالغة 70/15/15، ويكتب قوائم الملفات التي يقبلها ملف YAML للبيانات، ويعرض تغطية الفئات:

import random
from collections import Counter, defaultdict
from pathlib import Path

root = Path("datasets/practice")  # contains images/ and labels/

def group(image):
    return image.stem.rsplit("_", 1)[0]  # "cam2_2026-05-01_000124" -> "cam2_2026-05-01"

groups = defaultdict(list)
for image in sorted((root / "images").glob("*.jpg")):
    groups[group(image)].append(image)

keys = sorted(groups)
random.Random(0).shuffle(keys)  # fixed seed: the same split on every run
total, assigned = sum(len(v) for v in groups.values()), 0
splits = {"train": [], "val": [], "test": []}
for key in keys:  # assign whole groups until each split reaches its 70/15/15 share
    share = assigned / total
    splits["train" if share < 0.70 else "val" if share < 0.85 else "test"] += groups[key]
    assigned += len(groups[key])

counts = {}
for split, images in splits.items():
    (root / f"{split}.txt").write_text("".join(f"./images/{p.name}\n" for p in images))
    labels = [root / "labels" / f"{p.stem}.txt" for p in images]
    counts[split] = Counter(int(r.split()[0]) for f in labels if f.exists() for r in f.read_text().splitlines() if r.strip())

all_classes = set().union(*counts.values())
for split, images in splits.items():
    missing = len(all_classes - set(counts[split]))
    print(f"{split:>5}: {len(images):3d} images, {len({group(p) for p in images}):2d} groups, {missing} of {len(all_classes)} classes missing")
train:  90 images, 11 groups, 5 of 71 classes missing
  val:  20 images,  2 groups, 36 of 71 classes missing
 test:  18 images,  3 groups, 41 of 71 classes missing

طريقة قراءته:

  • لا تعبر أي مجموعة حدود التقسيم، وذلك بحكم طريقة الإنشاء. وهكذا يُعالج التسرّب.
  • يضم التحقق مجموعتين ويفتقد 36 فئة، لذا لا يمكن قياس AP لها. ومع وجود 71 فئة في 128 صورة، لن يعالج أي بذرة هذا النقص؛ والحل الحقيقي هو إضافة مزيد من المجموعات (كاميرات أو أيام إضافية)، كما هو الحال في مجموعة بيانات تشغيل فعلية تضم أكثر من 1,500 صورة لكل فئة.
  • يفتقد التدريب 5 فئات لا تظهر إلا في التحقق أو الاختبار. لا يمكن للنموذج تعلّمها مطلقًا من هذا التقسيم.

قاعدة اتخاذ القرار: عندما تغيب فئة عن أحد التقسيمات، أضف أو انقل مجموعات كاملة تحتوي عليها، ولا تنقل إطارات مفردة مطلقًا، لأن ذلك سيعيد إدخال التسرّب. وجّه مفاتيح train وval وtest في ملف YAML للبيانات إلى ملفات .txt الثلاثة؛ ويتناول كتابة ملف YAML لمجموعة البيانات بقية الملف.

وازن الفئات بين التقسيمات#

في مهام التصنيف، تحافظ train_test_split(..., stratify=labels) في scikit-learn على تساوي نسب الفئات بين التقسيمات باستخدام وسيط واحد. تحتوي صور الكشف على عدة فئات في الوقت نفسه، لذا وازنها على مستوى المجموعة بدلًا من ذلك: بعد group_split.py، قارن أعداد كل فئة بين التقسيمات وبدّل مجموعات كاملة حتى تقع كل فئة ضمن نحو ±20% من حصتها المتوقعة.

مربع حوار إعادة توزيع التقسيمات في Ultralytics Platform: إعادة تعيين 100 صورة عشوائيًا بين التدريب والتحقق والاختبار، مع ضبط التقسيم على 80/20/0 وزر تلقائي

في Ultralytics Platform، تعيد إعادة توزيع التقسيمات تعيين الصور عشوائيًا، ويضبط تلقائي التقسيم الموصى به 80/20 للتدريب/التحقق (وثائق التقسيم). وتزيل الصور المكررة تمامًا أثناء ذلك، لكنها لا تتعرّف على مجموعاتك؛ لذا استخدمها للقطات المستقلة، وحمّل تقسيمات مجمّعة لبيانات الفيديو أو البيانات متعددة الكاميرات.

تابع مجموعتي تحقق على نحو منفصل#

غالبًا ما تحتاج إلى مجموعتي تحقق: مجموعة انحدار منتقاة ومستقرة، ومجموعة تحاكي ظروف التشغيل الفعلية وتتغير مع الإطارات المجمّعة حديثًا. يقبل ملف YAML للبيانات قائمة بمجلدات التحقق، لكنه يدمجها في مجموعة تحقق واحدة ذات نتيجة واحدة:

path: ./datasets/forklift
train: images/train
val:
  - images/val_curated      # stable, your regression suite
  - images/val_production   # rotates with newly collected frames
test: images/test

للاطلاع على نتيجة كل مجموعة، احتفظ بملف YAML للبيانات لكل مجموعة تحقق (مع استخدام train وnames نفسيهما، وتغيير val) وتحقّق من الأوزان المدرّبة باستخدام كل مجموعة:

from ultralytics import YOLO

model = YOLO("runs/detect/train/weights/best.pt")  # your fine-tuned checkpoint
for data in ("val_curated.yaml", "val_production.yaml"):
    metrics = model.val(data=data)
    print(f"{data:<20} mAP50-95={metrics.box.map:.3f}")

يشير الانخفاض في المجموعة المنتقاة إلى تراجع في الأداء؛ أما الانخفاض في مجموعة التشغيل الفعلي فيشير إلى تحوّل المجال.

ثبّت مجموعة الاختبار#

مقارنة عمليات التشغيل على الاختبار تحوّله إلى بيانات تدريب

أعلى أخطاء التقسيم تكلفةً هو مقارنة عشرة نماذج مختلفة على مجموعة الاختبار. ما إن يؤثر الاختبار في أي قرار، حتى تصبح النتيجة النهائية متفائلة. أجرِ جميع عمليات الضبط ومقارنة التشغيل على مجموعة التحقق، ونفّذ اختبار القبول على مجموعة الاختبار مرة واحدة في النهاية.

التقسيم قرار باتجاه واحد

يرتبط كل مقياس تنشره بهذا التقسيم. إعادة الخلط لاحقًا تغيّر كل الأرقام وتجعل مقارنة عمليات التشغيل القديمة والجديدة مستحيلة. احتفظ بوحدة التقسيم والبذرة وقوائم الملفات الثلاث مع مجموعة البيانات.

التحقق المتقاطع بطريقة K-fold لمجموعات البيانات الصغيرة#

التحقق المتقاطع بطريقة K-fold: تُقسّم مجموعة التدريب كاملةً إلى خمس طيات، وتُخصّص كل طية بالتناوب لتكون طية الاختبار بينما تُستخدم الطيات الأخرى للتدريب، ثم يُحسب متوسط نتائج الطيات الخمس

عندما تكون مجموعة البيانات صغيرة (أقل من نحو 500 صورة لكل فئة) ويبدو تقسيم واحد ضعيفًا إحصائيًا، يدرّب التحقق المتقاطع بطريقة K-fold عدد k من النماذج باستخدام تقسيمات متناوبة، ثم يحسب متوسط النتيجة: أي حوسبة تعادل k مرات، مقابل تقدير أكثر ثباتًا بكثير. أنشئ الطيات من مجموعات بالطريقة نفسها، وإلا سيتسرّب التداخل إلى كل طية.

جرّبه

اختر وحدة التقسيم لمشروعك وبرّر اختيارك بجملة واحدة. أعد تسمية الصور أو ربطها بحيث يبدأ اسم كل ملف بمفتاح مجموعته، وشغّل group_split.py، وتحقّق من تغطية الفئات التي يعرضها. المُخرَج المطلوب: قوائم .txt الثلاث، ونتيجة التغطية، والتبرير المكتوب في جملة واحدة والمحفوظ مع مجموعة البيانات.

متى يُعدّ مكتملًا
تكون قد أتممت الدرس عند تحقق جميع الشروط التالية.
  • اختيرت وحدة التقسيم وبُرّر الاختيار بجملة واحدة.

  • يؤكد برنامج نصي عدم ظهور أي مفتاح مجموعة في أكثر من تقسيم واحد.

  • تظهر كل فئة في التدريب والتحقق والاختبار، أو توجد خطة لجمع البيانات لمعالجة النقص.

عرض الحل

بالنسبة إلى كاميرات المستودع الثابتة التي يجب أن تواصل العمل في أيام جديدة، قسّم حسب الكاميرا واليوم: cam2_2026-05-01. بعد group_split.py، تحقّق من عدم عبور أي مجموعة حدود التقسيم:

from pathlib import Path

root = Path("datasets/practice")
groups = {s: {Path(p).stem.rsplit("_", 1)[0] for p in (root / f"{s}.txt").read_text().split()} for s in ("train", "val", "test")}
print("train & val: ", groups["train"] & groups["val"] or "none")
print("train & test:", groups["train"] & groups["test"] or "none")
print("val & test:  ", groups["val"] & groups["test"] or "none")
train & val:  none
train & test: none
val & test:   none

يجتاز تقسيم التدريب العملي فحص التسرّب، لكنه لا يجتاز فحص التغطية: يفتقد التحقق 36 فئة من أصل 71. الحل هو وضع خطة لجمع البيانات، لا إعادة التقسيم. التقط بيانات ليومين إضافيين على الأقل للكاميرا من أجل التحقق والاختبار، على أن يغطي كل منهما الفئات الأهم في المواصفات، ثم أعد تشغيل البرنامجين النصيين.

ما الخطوة التالية

بعد اعتماد تقسيمات سليمة، يضبط الدرس التالي التعزيز ليتوافق مع بيئة النشر دون إنشاء صور مستحيلة.

سجّل الدخول لحفظ التقدم