Link to this sectionUltralyticsを使用したK-Fold交差検証#
Link to this sectionはじめに#
この包括的なガイドでは、Ultralyticsエコシステム内における物体検出データセットのK-Fold交差検証の実装方法を解説します。YOLO検出フォーマットと、sklearn、pandas、PyYAMLなどの主要なPythonライブラリを活用し、必要なセットアップ、特徴ベクトル生成のプロセス、およびK-Foldデータセット分割の実行手順を説明します。
プロジェクトがFruit Detectionデータセットであれ、カスタムデータソースであれ、このチュートリアルは機械学習モデルの信頼性と堅牢性を向上させるためのK-Fold交差検証の理解と適用を目的としています。このチュートリアルではk=5分割を使用しますが、最適な分割数はデータセットやプロジェクトの特性に応じて異なることに留意してください。
それでは始めましょう。
Link to this sectionセットアップ#
-
アノテーションはYOLO検出フォーマットである必要があります。
-
このガイドでは、アノテーションファイルがローカルで利用可能であることを前提としています。
-
デモンストレーションには、Fruit Detectionデータセットを使用します。
- このデータセットには合計8479枚の画像が含まれています。
- 6つのクラスラベルが含まれており、各インスタンス数は以下の通りです。
| クラスラベル | インスタンス数 |
|---|---|
| Apple | 7049 |
| Grapes | 7202 |
| Pineapple | 1613 |
| Orange | 15549 |
| Banana | 3536 |
| Watermelon | 1976 |
-
必要なPythonパッケージは以下の通りです:
ultralyticssklearnpandaspyyaml
-
このチュートリアルでは
k=5分割で運用します。ただし、使用するデータセットに最適な分割数を決定してください。
-
プロジェクト用に新しいPython仮想環境(
venv)を作成して有効化します。pip(または好みのパッケージマネージャー)を使用してインストールします:- Ultralyticsライブラリ:
pip install -U ultralytics。あるいは、公式リポジトリをクローンすることも可能です。 - Scikit-learn、pandas、PyYAML:
pip install -U scikit-learn pandas pyyaml
- Ultralyticsライブラリ:
-
アノテーションがYOLO検出フォーマットであることを確認してください。
- このチュートリアルでは、すべてのアノテーションファイルは
Fruit-Detection/labelsディレクトリに配置されています。
- このチュートリアルでは、すべてのアノテーションファイルは
Link to this section物体検出データセット用の特徴ベクトル生成#
-
まず、以下の手順のために新しい
example.pyというPythonファイルを作成します。 -
データセットのすべてのラベルファイルを取得します。
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' -
次に、データセットの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()) -
空の
pandasDataFrameを初期化します。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) -
アノテーションファイルに存在する各クラスラベルのインスタンス数をカウントします。
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` -
以下は、データを格納した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交差検証を適用することが可能になります。
Link to this sectionK-Foldデータセット分割#
-
Now we will use the
KFoldclass fromsklearn.model_selectionto generateksplits of the dataset.- 重要:
shuffle=Trueを設定することで、分割内でクラスがランダムに分布されるようになります。- By setting
random_state=MwhereMis a chosen integer, you can obtain repeatable results.
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)) - 重要:
-
これでデータセットは
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" -
Now we will calculate the distribution of class labels for each fold as a ratio of the classes present in
valto those present intrain.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理想的には、すべてのクラス比率が各分割間およびクラス間で妥当な程度に類似していることが望ましいですが、これはデータセットの特性に依存します。
-
続いて、各分割用のディレクトリとデータセット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, ) -
最後に、各分割の画像とラベルを対応するディレクトリ('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)
Link to this sectionレコードの保存(オプション)#
オプションとして、K-Fold分割およびラベル分布のDataFrameレコードをCSVファイルとして保存し、今後の参照用に使用できます。
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")Link to this sectionK-Foldデータ分割を使用したYOLOの学習#
-
まず、YOLOモデルを読み込みます。
from ultralytics import YOLO weights_path = "path/to/weights.pt" # use yolo26n.pt for a small model model = YOLO(weights_path, task="detect") -
次に、データセットの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 -
また、Ultralytics data.split.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)
Link to this section結論#
このガイドでは、YOLO物体検出モデルの学習にK-Fold交差検証を使用するプロセスを解説しました。データセットをK個のパーティションに分割し、フォールド間でバランスの取れたクラス分布を確保する方法を学習しました。
また、データ分割とラベル分布を可視化するためのレポートDataFrameを作成する手順を学び、訓練セットと検証セットの構造を明確に把握することができました。
オプションとして、将来の参照用にレコードを保存しました。これは大規模プロジェクトやモデルのパフォーマンスに関するトラブルシューティングを行う際に特に役立ちます。
最後に、ループ内で各分割を使用して実際のモデル学習を実行し、さらなる分析と比較のために学習結果を保存しました。
このK-Fold交差検証の手法は、利用可能なデータを最大限に活用する堅牢な方法であり、モデルのパフォーマンスが異なるデータサブセット間で信頼性が高く一貫していることを保証するのに役立ちます。これにより、特定のデータパターンに過学習しにくく、汎用性と信頼性の高いモデルが得られます。
このガイドではYOLOを使用しましたが、これらの手順は他の機械学習モデルにもほとんど適用可能です。これらの手順を理解することで、自身の機械学習プロジェクトで効果的に交差検証を適用できるようになります。
Link to this sectionよくある質問 (FAQ)#
Link to this sectionK-Fold交差検証とは何か、そしてなぜ物体検出において役立つのか?#
K-Fold交差検証は、モデルのパフォーマンスをより確実に評価するために、データセットを「k」個のサブセット(フォールド)に分割する手法です。各フォールドは訓練データと検証データの両方の役割を果たします。物体検出においてK-Fold交差検証を使用することは、Ultralytics YOLOモデルのパフォーマンスが異なるデータ分割間で堅牢かつ汎用的であることを保証し、信頼性を高めるのに役立ちます。Ultralytics YOLOでK-Fold交差検証を設定するための詳細な手順については、Ultralyticsを使用したK-Fold交差検証を参照してください。
Link to this sectionUltralytics YOLOを使用してK-Fold交差検証を実装するにはどうすればよいか?#
Ultralytics YOLOでK-Fold交差検証を実装するには、以下の手順に従う必要があります:
- アノテーションがYOLO検出フォーマットであることを確認する。
sklearn、pandas、pyyamlなどのPythonライブラリを使用する。- データセットから特徴ベクトルを作成する。
- Split your dataset using
KFoldfromsklearn.model_selection. - 各分割でYOLOモデルを学習する。
包括的なガイドについては、ドキュメントのK-Foldデータセット分割セクションを参照してください。
Link to this sectionなぜ物体検出に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, instance segmentation, semantic segmentation, and classification. Additionally, it integrates seamlessly with tools like Ultralytics Platform for no-code model training and deployment. For more details, explore the benefits and features on our Ultralytics YOLO page.
Link to this sectionUltralytics YOLOのためにアノテーションが正しいフォーマットであることを確認するにはどうすればよいか?#
アノテーションはYOLO検出フォーマットに従う必要があります。各アノテーションファイルには、オブジェクトクラスと、画像内でのバウンディングボックス座標を記述する必要があります。YOLOフォーマットにより、物体検出モデルの学習に向けた効率的で標準化されたデータ処理が保証されます。適切なアノテーションフォーマットの詳細については、YOLO検出フォーマットガイドをご覧ください。
Link to this sectionFruit Detection以外のカスタムデータセットでK-Fold交差検証を使用できるか?#
はい、アノテーションがYOLO検出フォーマットであれば、どのカスタムデータセットでもK-Fold交差検証を使用できます。データセットパスとクラスラベルをカスタムデータセット固有のものに置き換えてください。この柔軟性により、あらゆる物体検出プロジェクトにおいてK-Fold交差検証を使用した堅牢なモデル評価のメリットを享受できます。実践的な例については、特徴ベクトルの生成セクションを確認してください。