التحقق المتقاطع K-Fold مع Ultralytics

مقدمة

يوضح هذا الدليل الشامل كيفية تنفيذ التحقق المتقاطع K-Fold لمجموعات بيانات اكتشاف الكائنات داخل نظام Ultralytics البيئي. سنستفيد من تنسيق اكتشاف YOLO ومكتبات Python الرئيسية مثل sklearn وpandas وPyYAML لإرشادك خلال الإعداد اللازم، وعملية إنشاء متجهات الميزات، وتنفيذ تقسيم مجموعة البيانات باستخدام K-Fold.

K-fold cross validation data splitting

سواء كان مشروعك يتضمن مجموعة بيانات Fruit Detection أو مصدر بيانات مخصصاً، يهدف هذا البرنامج التعليمي إلى مساعدتك في فهم وتطبيق التحقق المتقاطع K-Fold لتعزيز موثوقية وقوة نماذج التعلم الآلي الخاصة بك. بينما نطبق k=5 طيات لهذا البرنامج التعليمي، ضع في اعتبارك أن العدد الأمثل للطيّات قد يختلف اعتماداً على مجموعة البيانات الخاصة بك وتفاصيل مشروعك.

لنبدأ.

الإعداد

  • يجب أن تكون التعليقات التوضيحية (annotations) الخاصة بك بتنسيق YOLO detection format.

  • يفترض هذا الدليل أن ملفات التعليقات التوضيحية متاحة محلياً.

  • في عرضنا التوضيحي، نستخدم مجموعة بيانات Fruit Detection.

    • تحتوي مجموعة البيانات هذه على إجمالي 8479 صورة.
    • تتضمن 6 تسميات فئات، مع إدراج إجمالي عدد الحالات لكل منها أدناه.
تسمية الفئةعدد الحالات
Apple7049
Grapes7202
Pineapple1613
Orange15549
Banana3536
Watermelon1976
  • حزم Python الضرورية تشمل:

    • ultralytics
    • sklearn
    • pandas
    • pyyaml
  • يعمل هذا البرنامج التعليمي مع k=5 طيات. ومع ذلك، يجب عليك تحديد أفضل عدد من الطيات لمجموعة البيانات الخاصة بك.

  1. قم ببدء بيئة افتراضية لـ Python (venv) لمشروعك وقم بتنشيطها. استخدم pip (أو مدير الحزم المفضل لديك) للتثبيت:

    • مكتبة Ultralytics: pip install -U ultralytics. بدلاً من ذلك، يمكنك استنساخ المستودع الرسمي.
    • Scikit-learn وpandas وPyYAML: pip install -U scikit-learn pandas pyyaml.
  2. تحقق من أن تعليقاتك التوضيحية بتنسيق YOLO detection format.

    • بالنسبة لهذا البرنامج التعليمي، توجد جميع ملفات التعليقات التوضيحية في الدليل Fruit-Detection/labels.

إنشاء متجهات الميزات لمجموعة بيانات اكتشاف الكائنات

  1. ابدأ بإنشاء ملف Python جديد باسم example.py للخطوات التالية.

  2. تابع لاسترداد جميع ملفات التسميات الخاصة بمجموعة البيانات الخاصة بك.

    from pathlib import Path
    
    dataset_path = Path("./Fruit-detection")  # replace with 'path/to/dataset' for your custom data
    labels = sorted(dataset_path.rglob("*labels/*.txt"))  # all data in 'labels'
  3. الآن، اقرأ محتويات ملف YAML الخاص بمجموعة البيانات واستخرج فهارس تسميات الفئات.

    import yaml
    
    yaml_file = "path/to/data.yaml"  # your data YAML with data directories and names dictionary
    with open(yaml_file, encoding="utf8") as y:
        classes = yaml.safe_load(y)["names"]
    cls_idx = sorted(classes.keys())
  4. قم بتهيئة pandas DataFrame فارغ.

    import pandas as pd
    
    index = [label.stem for label in labels]  # uses base filename as ID (no extension)
    labels_df = pd.DataFrame([], columns=cls_idx, index=index)
  5. احسب حالات كل تسمية فئة موجودة في ملفات التعليقات التوضيحية.

    from collections import Counter
    
    for label in labels:
        lbl_counter = Counter()
    
        with open(label) as lf:
            lines = lf.readlines()
    
        for line in lines:
            # classes for YOLO label uses integer at first position of each line
            lbl_counter[int(line.split(" ", 1)[0])] += 1
    
        labels_df.loc[label.stem] = lbl_counter
    
    labels_df = labels_df.fillna(0.0)  # replace `nan` values with `0.0`
  6. فيما يلي عرض عينة لـ DataFrame المملوء:

                                                           0    1    2    3    4    5
    '0000a16e4b057580_jpg.rf.00ab48988370f64f5ca8ea4...'  0.0  0.0  0.0  0.0  0.0  7.0
    '0000a16e4b057580_jpg.rf.7e6dce029fb67f01eb19aa7...'  0.0  0.0  0.0  0.0  0.0  7.0
    '0000a16e4b057580_jpg.rf.bc4d31cdcbe229dd022957a...'  0.0  0.0  0.0  0.0  0.0  7.0
    '00020ebf74c4881c_jpg.rf.508192a0a97aa6c4a3b6882...'  0.0  0.0  0.0  1.0  0.0  0.0
    '00020ebf74c4881c_jpg.rf.5af192a2254c8ecc4188a25...'  0.0  0.0  0.0  1.0  0.0  0.0
     ...                                                  ...  ...  ...  ...  ...  ...
    'ff4cd45896de38be_jpg.rf.c4b5e967ca10c7ced3b9e97...'  0.0  0.0  0.0  0.0  0.0  2.0
    'ff4cd45896de38be_jpg.rf.ea4c1d37d2884b3e3cbce08...'  0.0  0.0  0.0  0.0  0.0  2.0
    'ff5fd9c3c624b7dc_jpg.rf.bb519feaa36fc4bf630a033...'  1.0  0.0  0.0  0.0  0.0  0.0
    'ff5fd9c3c624b7dc_jpg.rf.f0751c9c3aa4519ea3c9d6a...'  1.0  0.0  0.0  0.0  0.0  0.0
    'fffe28b31f2a70d4_jpg.rf.7ea16bd637ba0711c53b540...'  0.0  6.0  0.0  0.0  0.0  0.0

تقوم الصفوف بفهرسة ملفات التسميات، حيث يتوافق كل منها مع صورة في مجموعة البيانات الخاصة بك، وتتوافق الأعمدة مع فهارس تسميات الفئات الخاصة بك. يمثل كل صف متجه ميزات زائفاً، مع عدد كل تسمية فئة موجودة في مجموعة البيانات الخاصة بك. يُمكّن هيكل البيانات هذا من تطبيق التحقق المتقاطع K-Fold على مجموعة بيانات اكتشاف الكائنات.

تقسيم مجموعة البيانات K-Fold

  1. الآن سنستخدم فئة KFold من sklearn.model_selection لإنشاء k من تقسيمات مجموعة البيانات.

    • هام:
      • ضبط shuffle=True يضمن توزيعاً عشوائياً للفئات في تقسيماتك.
      • من خلال ضبط random_state=M حيث M هو عدد صحيح مختار، يمكنك الحصول على نتائج قابلة للتكرار.
    import random
    
    from sklearn.model_selection import KFold
    
    random.seed(0)  # for reproducibility
    ksplit = 5
    kf = KFold(n_splits=ksplit, shuffle=True, random_state=20)  # setting random_state for repeatable results
    
    kfolds = list(kf.split(labels_df))
  2. تم الآن تقسيم مجموعة البيانات إلى k طيات، حيث تحتوي كل منها على قائمة بفهارس train و val. سنقوم بإنشاء DataFrame لعرض هذه النتائج بشكل أوضح.

    folds = [f"split_{n}" for n in range(1, ksplit + 1)]
    folds_df = pd.DataFrame(index=index, columns=folds)
    
    for i, (train, val) in enumerate(kfolds, start=1):
        folds_df[f"split_{i}"].loc[labels_df.iloc[train].index] = "train"
        folds_df[f"split_{i}"].loc[labels_df.iloc[val].index] = "val"
  3. الآن سنحسب توزيع تسميات الفئات لكل طية كنسبة للفئات الموجودة في val إلى تلك الموجودة في train.

    fold_lbl_distrb = pd.DataFrame(index=folds, columns=cls_idx)
    
    for n, (train_indices, val_indices) in enumerate(kfolds, start=1):
        train_totals = labels_df.iloc[train_indices].sum()
        val_totals = labels_df.iloc[val_indices].sum()
    
        # To avoid division by zero, we add a small value (1E-7) to the denominator
        ratio = val_totals / (train_totals + 1e-7)
        fold_lbl_distrb.loc[f"split_{n}"] = ratio

    السيناريو المثالي هو أن تكون جميع نسب الفئات متشابهة بشكل معقول لكل تقسيم وعبر الفئات. ومع ذلك، سيخضع هذا لتفاصيل مجموعة البيانات الخاصة بك.

  4. بعد ذلك، نقوم بإنشاء الأدلة وملفات YAML الخاصة بمجموعة البيانات لكل تقسيم.

    import datetime
    
    supported_extensions = [".jpg", ".jpeg", ".png"]
    
    # Initialize an empty list to store image file paths
    images = []
    
    # Loop through supported extensions and gather image files
    for ext in supported_extensions:
        images.extend(sorted((dataset_path / "images").rglob(f"*{ext}")))
    
    # Create the necessary directories and dataset YAML files
    save_path = Path(dataset_path / f"{datetime.date.today().isoformat()}_{ksplit}-Fold_Cross-val")
    save_path.mkdir(parents=True, exist_ok=True)
    ds_yamls = []
    
    for split in folds_df.columns:
        # Create directories
        split_dir = save_path / split
        split_dir.mkdir(parents=True, exist_ok=True)
        (split_dir / "train" / "images").mkdir(parents=True, exist_ok=True)
        (split_dir / "train" / "labels").mkdir(parents=True, exist_ok=True)
        (split_dir / "val" / "images").mkdir(parents=True, exist_ok=True)
        (split_dir / "val" / "labels").mkdir(parents=True, exist_ok=True)
    
        # Create dataset YAML files
        dataset_yaml = split_dir / f"{split}_dataset.yaml"
        ds_yamls.append(dataset_yaml)
    
        with open(dataset_yaml, "w") as ds_y:
            yaml.safe_dump(
                {
                    "path": split_dir.as_posix(),
                    "train": "train",
                    "val": "val",
                    "names": classes,
                },
                ds_y,
            )
  5. أخيراً، انسخ الصور والتسميات إلى الدليل المعني ('train' أو 'val') لكل تقسيم.

    • ملاحظة: سيتغير الوقت المطلوب لهذا الجزء من الكود بناءً على حجم مجموعة البيانات الخاصة بك وأجهزة النظام لديك.
    import shutil
    
    from tqdm import tqdm
    
    for image, label in tqdm(zip(images, labels), total=len(images), desc="Copying files"):
        for split, k_split in folds_df.loc[image.stem].items():
            # Destination directory
            img_to_path = save_path / split / k_split / "images"
            lbl_to_path = save_path / split / k_split / "labels"
    
            # Copy image and label files to new directory (SamefileError if file already exists)
            shutil.copy(image, img_to_path / image.name)
            shutil.copy(label, lbl_to_path / label.name)

حفظ السجلات (اختياري)

اختيارياً، يمكنك حفظ سجلات تقسيم K-Fold و DataFrames الخاصة بتوزيع التسميات كملفات CSV للرجوع إليها مستقبلاً.

folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")

تدريب YOLO باستخدام تقسيمات بيانات K-Fold

  1. أولاً، قم بتحميل نموذج YOLO.

    from ultralytics import YOLO
    
    weights_path = "path/to/weights.pt"  # use yolo26n.pt for a small model
    model = YOLO(weights_path, task="detect")
  2. بعد ذلك، قم بالتكرار عبر ملفات YAML الخاصة بمجموعة البيانات لتشغيل التدريب. سيتم حفظ النتائج في دليل يحدده الوسيطان project و name. افتراضياً، يكون هذا الدليل هو 'runs/detect/train#' حيث # هو فهرس عدد صحيح.

    results = {}
    
    # Define your additional arguments here
    batch = 16
    project = "kfold_demo"
    epochs = 100
    
    for k, dataset_yaml in enumerate(ds_yamls):
        model = YOLO(weights_path, task="detect")
        results[k] = model.train(
            data=dataset_yaml, epochs=epochs, batch=batch, project=project, name=f"fold_{k + 1}"
        )  # include any additional train arguments
  3. يمكنك أيضاً استخدام دالة Ultralytics data.utils.autosplit للتقسيم التلقائي لمجموعة البيانات:

    from ultralytics.data.split import autosplit
    
    # Automatically split dataset into train/val/test
    autosplit(path="path/to/images", weights=(0.8, 0.2, 0.0), annotated_only=True)

خاتمة

في هذا الدليل، استكشفنا عملية استخدام التحقق المتقاطع K-Fold لتدريب نموذج اكتشاف الكائنات YOLO. تعلمنا كيفية تقسيم مجموعة البيانات الخاصة بنا إلى K أقسام، مما يضمن توزيعاً متوازناً للفئات عبر الطيات المختلفة.

استكشفنا أيضاً إجراء إنشاء تقرير DataFrames لتصور تقسيمات البيانات وتوزيعات التسميات عبر هذه التقسيمات، مما يوفر لنا رؤية واضحة لهيكل مجموعات التدريب والتحقق لدينا.

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

أخيراً، قمنا بتنفيذ التدريب الفعلي للنموذج باستخدام كل تقسيم في حلقة تكرارية، مع حفظ نتائج التدريب الخاصة بنا لإجراء المزيد من التحليل والمقارنة.

تعد تقنية التحقق المتقاطع K-Fold هذه وسيلة قوية لتحقيق أقصى استفادة من البيانات المتاحة لديك، وتساعد على ضمان أن أداء نموذجك موثوق ومتسق عبر مجموعات البيانات الفرعية المختلفة. يؤدي هذا إلى نموذج أكثر قابلية للتعميم وموثوقية يكون أقل عرضة لـ الإفراط في التجهيز لأنماط بيانات معينة.

تذكر أنه على الرغم من أننا استخدمنا YOLO في هذا الدليل، فإن هذه الخطوات قابلة للنقل في الغالب إلى نماذج تعلم آلي أخرى. يسمح لك فهم هذه الخطوات بتطبيق التحقق المتقاطع بفعالية في مشاريع التعلم الآلي الخاصة بك.

الأسئلة الشائعة

ما هو التحقق المتقاطع K-Fold ولماذا هو مفيد في اكتشاف الكائنات؟

التحقق المتقاطع K-Fold هو تقنية يتم فيها تقسيم مجموعة البيانات إلى 'k' مجموعات فرعية (طيات) لتقييم أداء النموذج بشكل أكثر موثوقية. تعمل كل طية كبيانات تدريب وبيانات تحقق. في سياق اكتشاف الكائنات، يساعد استخدام التحقق المتقاطع K-Fold على ضمان أن أداء نموذج Ultralytics YOLO الخاص بك قوي وقابل للتعميم عبر تقسيمات البيانات المختلفة، مما يعزز موثوقيته. للحصول على تعليمات مفصلة حول إعداد التحقق المتقاطع K-Fold مع Ultralytics YOLO، راجع التحقق المتقاطع K-Fold مع Ultralytics.

كيف يمكنني تنفيذ التحقق المتقاطع K-Fold باستخدام Ultralytics YOLO؟

لتنفيذ التحقق المتقاطع K-Fold مع Ultralytics YOLO، تحتاج إلى اتباع هذه الخطوات:

  1. تحقق من أن التعليقات التوضيحية بتنسيق YOLO detection format.
  2. استخدم مكتبات Python مثل sklearn و pandas و pyyaml.
  3. أنشئ متجهات ميزات من مجموعة البيانات الخاصة بك.
  4. قسم مجموعة البيانات الخاصة بك باستخدام KFold من sklearn.model_selection.
  5. درب نموذج YOLO على كل تقسيم.

للحصول على دليل شامل، راجع قسم تقسيم مجموعة البيانات K-Fold في وثائقنا.

لماذا يجب أن أستخدم Ultralytics YOLO لاكتشاف الكائنات؟

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

كيف يمكنني التأكد من أن تعليقاتي التوضيحية بالتنسيق الصحيح لـ Ultralytics YOLO؟

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

هل يمكنني استخدام التحقق المتقاطع K-Fold مع مجموعات بيانات مخصصة بخلاف Fruit Detection؟

نعم، يمكنك استخدام التحقق المتقاطع K-Fold مع أي مجموعة بيانات مخصصة طالما أن التعليقات التوضيحية بتنسيق اكتشاف YOLO. استبدل مسارات مجموعة البيانات وتسميات الفئات بتلك الخاصة بمجموعة بياناتك المخصصة. تضمن هذه المرونة إمكانية استفادة أي مشروع لاكتشاف الكائنات من تقييم قوي للنموذج باستخدام التحقق المتقاطع K-Fold. للحصول على مثال عملي، راجع قسم إنشاء متجهات الميزات لدينا.

التعليقات