Kフォールド・クロス・バリデーションUltralytics
はじめに
この包括的なガイドでは、Ultralytics エコシステム内のオブジェクト検出データセットに対する K-Fold Cross Validation の実装について説明します。YOLO 検出フォーマットと、sklearn、pandas、PyYaml などの主要なPython ライブラリを活用して、必要なセットアップ、特徴ベクトルの生成プロセス、K-Fold データセット分割の実行をガイドします。
このチュートリアルでは、Fruit Detection データセットまたはカスタム・データ・ソースのいずれを使用するプロジェクトであっても、K-Fold Cross Validation を理解し適用することで、機械学習モデルの信頼性と頑健性を高めることを目的としています。このチュートリアルでは 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
.
- Ultralytics ライブラリー:
-
注釈がYOLO 検出フォーマットであることを確認してください。
- このチュートリアルでは、すべての注釈ファイルは
Fruit-Detection/labels
ディレクトリにある。
- このチュートリアルでは、すべての注釈ファイルは
物体検出データセットの特徴ベクトルの生成
-
まずPython ファイルを新規作成し、必要なライブラリをインポートする。
-
データセットのすべてのラベルファイルを取得する。
-
さて、データセットのYAMLファイルの中身を読んで、クラスラベルのインデックスを抽出しましょう。
-
空の
pandas
データフレーム。 -
注釈ファイルに存在する各クラスラベルのインスタンスを数える。
for label in labels: lbl_counter = Counter() with open(label,'r') as lf: lines = lf.readlines() for l in lines: # classes for YOLO label uses integer at first position of each line lbl_counter[int(l.split(' ')[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クロスバリデーションを適用することができる。
Kフォールド・データセット分割
-
では
KFold
クラスsklearn.model_selection
を生成する。k
データセットの分割。- 重要だ:
- セッティング
shuffle=True
は、分割におけるクラスのランダムな分布を保証します。 - セッティング
random_state=M
どこM
を整数にすれば、再現性のある結果を得ることができる。
- セッティング
- 重要だ:
-
データセットは現在、以下のように分割されている。
k
のリストを持つ。train
そしてval
インデックスを作成します。これらの結果をより明確に表示するために、DataFrameを作成する。 -
では、各フォールドのクラス・ラベルの分布を、次のように計算する。
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
理想的なシナリオは、すべてのクラスの比率が、各スプリットで、またクラス間で、適度に似ていることです。しかし、これはデータセットの仕様に依存します。
-
次に、各スプリットのディレクトリとデータセットのYAMLファイルを作成します。
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)
-
最後に、画像とラベルを各スプリットのディレクトリ('train'または'val')にコピーする。
- 注:コードのこの部分に要する時間は、データセットのサイズとシステムのハードウェアによって異なります。
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
-
まず、YOLO のモデルをロードする。
-
次に、データセットの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 を使用したが、これらのステップは他の機械学習モデルにもほとんど適用できることを忘れないでほしい。これらのステップを理解することで、あなた自身の機械学習プロジェクトでクロスバリデーションを効果的に適用することができます。ハッピー・コーディング!