K-Fold 交叉驗證
- 1、引言
- 1.1 K 折交叉驗證概述
- 2、配置
- 2.1 數據集
- 2.2 安裝包
- 3、 實戰
- 3.1 生成物體檢測數據集的特征向量
- 3.2 K 折數據集拆分
- 3.3 保存記錄
- 3.4 使用 K 折數據分割訓練YOLO
- 4、總結
1、引言
我們將利用YOLO 檢測格式和關鍵的Python 庫(如 sklearn、pandas 和 PyYaml),完成必要的設置、生成特征向量的過程以及 K-Fold 數據集拆分的執行。
1.1 K 折交叉驗證概述
無論你的項目涉及水果檢測數據集還是自定義數據源,都可以使用 K 折交叉驗證,
以提高項目的可靠性和穩健性。
書說簡短,閑言少敘,咱進入正題
2、配置
2.1 數據集
該數據集共包含 8479 幅圖像。
它包括 6 個類別標簽,每個標簽的實例總數如下:
類別 | 計數 |
---|---|
蘋果 | 7049 |
葡萄 | 7202 |
菠蘿 | 1613 |
橙色 | 15549 |
香蕉 | 3536 |
西瓜 | 1976 |
2.2 安裝包
必要的Python 軟件包包括
- ultralytics
- sklearn
- pandas
- pyyaml
這次實例中,我們使用 k=5 折疊次數。
3、 實戰
3.1 生成物體檢測數據集的特征向量
具體步驟如下:
-
1、首先創建一個新的 demo.py Python 文件來執行下面的步驟。
-
2、繼續檢索數據集的所有標簽文件。
from pathlib import Pathdataset_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 DataFrame.
import pandas as pdindex = [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 Counterfor 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 linelbl_counter[int(line.split(" ")[0])] += 1labels_df.loc[label.stem] = lbl_counterlabels_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 折交叉驗證應用于對象檢測數據集。
3.2 K 折數據集拆分
-
1、使用 KFold 從 sklearn.model_selection 以產生 k 對數據集進行分割。
- 敲黑板:
- 設置 shuffle=True 確保了分班中班級的隨機分布。
- 通過設置 random_state=M 其中 M 是一個選定的整數,這樣就可以得到可重復的結果。
- 敲黑板:
from sklearn.model_selection import KFoldksplit = 5
kf = KFold(n_splits=ksplit, shuffle=True, random_state=20) # setting random_state for repeatable resultskfolds = 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、將計算每個褶皺的類別標簽分布,并將其作為褶皺中出現的類別的比率。
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 denominatorratio = val_totals / (train_totals + 1e-7)fold_lbl_distrb.loc[f"split_{n}"] = ratio
最理想的情況是,每次分割和不同類別的所有類別比率都相當相似。不過,這取決于數據集的具體情況。
- 4、為每個分割創建目錄和數據集 YAML 文件。
import datetimesupported_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 directoriessplit_dir = save_path / splitsplit_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 filesdataset_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 shutilfor image, label in zip(images, labels):for split, k_split in folds_df.loc[image.stem].items():# Destination directoryimg_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)
3.3 保存記錄
將 K 折分割和標簽分布數據框的記錄保存為 CSV 文件。
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")
3.4 使用 K 折數據分割訓練YOLO
- 首先,加載YOLO 模型。
from ultralytics import YOLOweights_path = "path/to/weights.pt"
model = YOLO(weights_path, task="detect")
- 其次,遍歷數據集 YAML 文件以運行訓練。結果將保存到由 project 和 name 參數。默認情況下,該目錄為 “exp/runs#”,其中 # 為整數索引。
results = {}# Define your additional arguments here
batch = 16
project = "kfold_demo"
epochs = 100for k in range(ksplit):dataset_yaml = ds_yamls[k]model = YOLO(weights_path, task="detect")model.train(data=dataset_yaml, epochs=epochs, batch=batch, project=project) # include any train argumentsresults[k] = model.metrics # save output metrics for further analysis
4、總結
這篇小魚使用了 K 折交叉驗證來訓練YOLO 物體檢測模型的過程。
還創建報告 DataFrames 的程序,以可視化數據拆分和標簽在這些拆分中的分布,清楚地了解訓練集和驗證集的結構。
此外,還保存了記錄,這在大型項目或排除模型性能故障時尤為有用。
最后,在一個循環中使用每個拆分來執行實際的模型訓練,保存訓練結果,以便進一步分析和比較。
這種 K 折交叉驗證技術是充分利用可用數據的一種穩健方法,有助于確保模型在不同數據子集中的性能是可靠和一致的。這將產生一個更具通用性和可靠性的模型,從而減少對特定數據模式的過度擬合。
我是小魚:
- CSDN 博客專家;
- 阿里云 專家博主;
- 51CTO博客專家;
- 企業認證金牌面試官;
- 多個名企認證&特邀講師等;
- 名企簽約職場面試培訓、職場規劃師;
- 多個國內主流技術社區的認證專家博主;
- 多款主流產品(阿里云等)評測一等獎獲得者;
關注小魚,學習【人工智能&大模型】/【深度學習&機器學習】領域最新最全的知識。