コンテンツへスキップ

Kフォールド・クロス・バリデーションUltralytics

はじめに

This comprehensive guide illustrates the implementation of K-Fold Cross Validation for object detection datasets within the Ultralytics ecosystem. We'll leverage the YOLO detection format and key Python libraries such as sklearn, pandas, and PyYaml to guide you through the necessary setup, the process of generating feature vectors, and the execution of a K-Fold dataset split.

Kフォールド交差検証の概要

Whether your project involves the Fruit Detection dataset or a custom data source, this tutorial aims to help you comprehend and apply K-Fold Cross Validation to bolster the reliability and robustness of your machine learning models. While we're applying k=5 このチュートリアルでは、最適な回数はデータセットやプロジェクトの仕様によって異なることを念頭に置いています。

では、さっそく見ていこう!

セットアップ

  • 注釈は、YOLO 検出フォーマットでなければなりません。

  • このガイドでは、注釈ファイルがローカルにあることを前提としています。

  • このデモでは、Fruit Detectionデータセットを使用する。

    • このデータセットには合計8479枚の画像が含まれている。
    • これは6つのクラス・ラベルを含み、それぞれのインスタンス総数は以下の通りである。
クラスラベルインスタンス数
アップル7049
ブドウ7202
パイナップル1613
オレンジ15549
バナナ3536
スイカ1976
  • 必要なPython パッケージは以下の通り:

    • ultralytics
    • sklearn
    • pandas
    • pyyaml
  • このチュートリアルでは k=5 回である。しかし、特定のデータセットに最適なフォールド数を決定する必要がある。

  • 新しいPython 仮想環境 (venv)をプロジェクトに追加し、アクティベートする。使用方法 pip (またはお好みのパッケージ・マネージャー)をインストールする:

    • Ultralytics ライブラリー: pip install -U ultralytics.または、公式の レポ.
    • Scikit-learn、pandas、PyYAML: pip install -U scikit-learn pandas pyyaml.
  • 注釈がYOLO 検出フォーマットであることを確認してください。

    • このチュートリアルでは、すべての注釈ファイルは Fruit-Detection/labels ディレクトリにある。

物体検出データセットの特徴ベクトルの生成

  1. まず、新しい example.py Python 以下の手順のファイル。

  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ファイルの中身を読んで、クラスラベルのインデックスを抽出しましょう。

    yaml_file = "path/to/data.yaml"  # your data YAML with data directories and names dictionary
    with open(yaml_file, "r", encoding="utf8") as y:
        classes = yaml.safe_load(y)["names"]
    cls_idx = sorted(classes.keys())
    
  4. 空の pandas データフレーム。

    import pandas as pd
    
    indx = [label.stem for label in labels]  # uses base filename as ID (no extension)
    labels_df = pd.DataFrame([], columns=cls_idx, index=indx)
    
  5. 注釈ファイルに存在する各クラスラベルのインスタンスを数える。

    from collections import Counter
    
    for label in labels:
        lbl_counter = Counter()
    
        with open(label, "r") 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(" ")[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フォールド・データセット分割

  1. では KFold クラス sklearn.model_selection を生成する。 k データセットの分割。

    • 重要だ:
      • セッティング shuffle=True は、分割におけるクラスのランダムな分布を保証します。
      • セッティング random_state=M どこ M を整数にすれば、再現性のある結果を得ることができる。
    from sklearn.model_selection import KFold
    
    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=indx, columns=folds)
    
    for idx, (train, val) in enumerate(kfolds, start=1):
        folds_df[f"split_{idx}"].loc[labels_df.iloc[train].index] = "train"
        folds_df[f"split_{idx}"].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 (unchanged)
    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
    
    for image, label in zip(images, labels):
        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分割とラベル配布のDataFrameのレコードをCSVファイルとして保存し、後で参照することができます。

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

K-Fold データ分割を使用したトレーニングYOLO

  1. まず、YOLO のモデルをロードする。

    from ultralytics import YOLO
    
    weights_path = "path/to/weights.pt"
    model = YOLO(weights_path, task="detect")
    
  2. 次に、データセットのYAMLファイルを反復処理してトレーニングを実行します。結果は project そして name 引数で指定する。デフォルトでは、このディレクトリは'exp/runs#'であり、#は整数インデックスである。

    results = {}
    
    # Define your additional arguments here
    batch = 16
    project = "kfold_demo"
    epochs = 100
    
    for k in range(ksplit):
        dataset_yaml = ds_yamls[k]
        model.train(data=dataset_yaml, epochs=epochs, batch=batch, project=project)  # include any train arguments
        results[k] = model.metrics  # save output metrics for further analysis
    

結論

このガイドでは、YOLO オブジェクト検出モデルのトレーニングに K-Fold 交差検証を使用するプロセスを探った。データセットをK個のパーティションに分割し、異なるフォールド間でバランスのとれたクラス分布を確保する方法を学びました。

また、レポートDataFramesを作成し、データの分割と分割されたラベル分布を可視化する手順も検討した。

これは、大規模なプロジェクトや、モデルの性能をトラブルシューティングするときに特に役立つ。

最後に、各スプリットを使用した実際のモデル学習をループで実行し、さらなる分析と比較のために学習結果を保存した。

このK-Foldクロスバリデーションのテクニックは、利用可能なデータを最大限に活用するロバストな方法であり、モデルのパフォーマンスが信頼でき、異なるデータ・サブセット間で一貫していることを保証するのに役立ちます。その結果、特定のデータ・パターンに過剰適合する可能性が低く、より一般化可能で信頼性の高いモデルが出来上がります。

このガイドではYOLO を使用したが、これらのステップは他の機械学習モデルにもほとんど適用できることを忘れないでほしい。これらのステップを理解することで、あなた自身の機械学習プロジェクトでクロスバリデーションを効果的に適用することができます。ハッピー・コーディング!

よくあるご質問

K-Foldクロスバリデーションとは何か、なぜ物体検出に有用なのか?

K-Fold Cross Validation is a technique where the dataset is divided into 'k' subsets (folds) to evaluate model performance more reliably. Each fold serves as both training and validation data. In the context of object detection, using K-Fold Cross Validation helps to ensure your Ultralytics YOLO model's performance is robust and generalizable across different data splits, enhancing its reliability. For detailed instructions on setting up K-Fold Cross Validation with Ultralytics YOLO, refer to K-Fold Cross Validation with Ultralytics.

Ultralytics YOLO を使って K-Fold 交差検証を実装するには?

K-Fold Cross Validation をUltralytics YOLO で実施するには、以下のステップに従う必要がある:

  1. 注釈がYOLO 検出フォーマットであることを確認する。
  2. のようなPython ライブラリを使用する。 sklearn, pandasそして pyyaml.
  3. データセットから特徴ベクトルを作成します。
  4. を使用してデータセットを分割します。 KFold より sklearn.model_selection.
  5. YOLO モデルを各スプリットでトレーニングする。

包括的なガイドについては、ドキュメントのK-Fold Dataset Splitセクションを参照してください。

なぜ物体検出にUltralytics YOLO を使う必要があるのか?

Ultralytics YOLO offers state-of-the-art, real-time object detection with high accuracy and efficiency. It's versatile, supporting multiple computer vision tasks such as detection, segmentation, and classification. Additionally, it integrates seamlessly with tools like Ultralytics HUB for no-code model training and deployment. For more details, explore the benefits and features on our Ultralytics YOLO page.

注釈がUltralytics YOLO の正しいフォーマットであることを確認するにはどうすればよいですか?

Your annotations should follow the YOLO detection format. Each annotation file must list the object class, alongside its bounding box coordinates in the image. The YOLO format ensures streamlined and standardized data processing for training object detection models. For more information on proper annotation formatting, visit the YOLO detection format guide.

フルーツ検出以外のカスタムデータセットでK-Foldクロスバリデーションを使用できますか?

注釈がYOLO 検出形式であれば、どのようなカスタムデータセットでも K-Fold Cross Validation を使用できます。データセットのパスとクラスラベルは、カスタムデータセット固有のものに置き換えてください。この柔軟性により、どのような物体検出プロジェクトでも、K-Fold Cross Validationを使用したロバストなモデル評価の恩恵を受けることができます。実用的な例として、特徴ベクトルの生成のセクションをご覧ください。

📅 Created 11 months ago ✏️ Updated 29 days ago

コメント