Cross-validation K-Fold với Ultralytics#
Giới thiệu#
Hướng dẫn toàn diện này minh họa cách triển khai cross-validation K-Fold cho các dataset phát hiện đối tượng trong hệ sinh thái Ultralytics. Chúng ta sẽ sử dụng định dạng phát hiện YOLO và các thư viện Python chính như sklearn, pandas và PyYAML để hướng dẫn bạn thiết lập cần thiết, tạo vector đặc trưng và thực hiện chia dataset K-Fold.
Dù project của bạn sử dụng dataset Fruit Detection hay một nguồn dữ liệu tùy chỉnh, tutorial này nhằm giúp bạn hiểu và áp dụng cross-validation K-Fold để tăng độ tin cậy và tính robust cho các model machine learning của mình. Trong tutorial này, chúng ta sử dụng k=5 fold, nhưng hãy lưu ý rằng số fold tối ưu có thể thay đổi tùy theo dataset và đặc điểm cụ thể của project. Cross-validation K-Fold mang lại nhiều giá trị nhất khi dataset nhỏ, nhiễu hoặc có độ biến thiên cao; với các dataset lớn và đa dạng, việc chia train/val/test được xây dựng tốt thường là đủ.
Hãy bắt đầu.
Thiết lập#
-
Các annotation của bạn phải ở định dạng phát hiện YOLO.
-
Hướng dẫn này giả định rằng các file annotation có sẵn trên máy local.
-
Trong phần minh họa, chúng ta sử dụng dataset Fruit Detection.
- Dataset này có tổng cộng 8479 ảnh.
- Dataset gồm 6 nhãn class, với tổng số instance của mỗi nhãn được liệt kê bên dưới.
| Nhãn class | Số lượng instance |
|---|---|
| Táo | 7049 |
| Nho | 7202 |
| Dứa | 1613 |
| Cam | 15549 |
| Chuối | 3536 |
| Dưa hấu | 1976 |
-
Các package Python cần thiết gồm:
ultralyticssklearnpandaspyyaml
-
Tutorial này sử dụng
k=5fold. Tuy nhiên, bạn nên xác định số fold phù hợp nhất cho dataset cụ thể của mình.
-
Khởi tạo một môi trường ảo Python mới (
venv) cho project và kích hoạt môi trường đó. Sử dụngpip(hoặc package manager bạn предпоч chọn) để cài đặt:- Thư viện Ultralytics:
pip install -U ultralytics. Ngoài ra, bạn có thể clone repo chính thức. - Scikit-learn, pandas và PyYAML:
pip install -U scikit-learn pandas pyyaml.
- Thư viện Ultralytics:
-
Xác minh rằng các annotation của bạn ở định dạng phát hiện YOLO.
- Trong tutorial này, tất cả file annotation nằm trong thư mục
Fruit-Detection/labels.
- Trong tutorial này, tất cả file annotation nằm trong thư mục
Tạo Vector Đặc trưng cho Dataset Phát hiện Đối tượng#
-
Bắt đầu bằng cách tạo một file Python
example.pymới cho các bước bên dưới. -
Tải các ảnh train và validation đã được cấu hình thông qua owner dataset của package, đồng thời giữ nguyên test split.
from pathlib import Path from ultralytics.data.dataset import YOLODataset from ultralytics.data.utils import check_det_dataset yaml_file = "path/to/data.yaml" data = check_det_dataset(yaml_file) dataset_path = Path(data["path"]) sources = [] for split in ("train", "val"): source = data.get(split) if source: sources.extend(source if isinstance(source, list) else [source]) dataset = YOLODataset(sources, data=data, augment=False) images = [Path(p) for p in dataset.im_files] -
Tiếp theo, đọc nội dung của file YAML dataset và trích xuất index của các nhãn class.
classes = data["names"] cls_idx = sorted(classes.keys()) -
Khởi tạo một DataFrame
pandastrống.import pandas as pd labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images) -
Đếm số instance của từng class-label có trong các file annotation.
from collections import Counter for image, label in zip(images, dataset.labels): lbl_counter = Counter(label["cls"].flatten().astype(int)) labels_df.loc[image, list(lbl_counter)] = list(lbl_counter.values()) -
Dưới đây là chế độ xem mẫu của DataFrame đã được điền dữ liệu:
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
Các hàng sử dụng đường dẫn tuyệt đối đến ảnh, còn các cột tương ứng với index của class-label. Các nhãn bị thiếu vẫn là những hàng background toàn số 0. Cấu trúc dữ liệu này cho phép áp dụng Cross-validation K-Fold cho dataset phát hiện đối tượng.
Chia Dataset K-Fold#
-
Bây giờ, chúng ta sẽ sử dụng class
KFoldtừsklearn.model_selectionđể tạoksplit của dataset.- Quan trọng:
- Thiết lập
shuffle=Trueđảm bảo các class được phân phối ngẫu nhiên trong những split của bạn. - Bằng cách thiết lập
random_state=Mtrong đóMlà một số nguyên được chọn, bạn có thể thu được các kết quả có thể lặp lại.
- Thiết lập
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)) - Quan trọng:
-
Dataset hiện đã được chia thành
kfold, mỗi fold có một danh sách các indextrainvàval. Chúng ta sẽ xây dựng một DataFrame để hiển thị các kết quả này rõ ràng hơn.folds = [f"split_{n}" for n in range(1, ksplit + 1)] folds_df = pd.DataFrame(index=labels_df.index, columns=folds) for i, (train, val) in enumerate(kfolds, start=1): folds_df.loc[labels_df.index[train], f"split_{i}"] = "train" folds_df.loc[labels_df.index[val], f"split_{i}"] = "val" -
Bây giờ, chúng ta sẽ tính phân phối nhãn class cho mỗi fold dưới dạng tỷ lệ giữa các class có trong
valvà các class có trongtrain.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}"] = ratioTrường hợp lý tưởng là tất cả tỷ lệ class tương đối giống nhau trong mỗi split và giữa các class. Tuy nhiên, điều này sẽ phụ thuộc vào đặc điểm cụ thể của dataset.
-
Ghi danh sách ảnh và YAML dataset cho mỗi split. Các danh sách text tránh phải sao chép dataset
klần.import yaml save_path = dataset_path.parent / f"{ksplit}-Fold_Cross-val" save_path.mkdir(parents=True, exist_ok=True) ds_yamls = [] for split in folds_df.columns: for partition in ("train", "val"): split_images = folds_df.index[folds_df[split] == partition] paths = "\n".join(map(str, split_images)) (save_path / f"{split}_{partition}.txt").write_text(f"{paths}\n") dataset_yaml = save_path / f"{split}.yaml" ds_yamls.append(dataset_yaml) with open(dataset_yaml, "w") as ds_y: yaml.safe_dump( { "path": save_path.as_posix(), "train": f"{split}_train.txt", "val": f"{split}_val.txt", "names": classes, }, ds_y, )
Lưu Record (Tùy chọn)#
Bạn có thể tùy chọn lưu các record của DataFrame chia K-Fold và phân phối nhãn dưới dạng file CSV để tham khảo sau này.
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")Train YOLO bằng các Dataset Split K-Fold#
-
Trước tiên, tải model YOLO.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # use yolo26n.pt for a small model model = YOLO(weights_path, task="detect") -
Tiếp theo, lặp qua các file YAML dataset để chạy quá trình train. Kết quả sẽ được lưu vào thư mục được chỉ định bởi các argument
projectvàname. Theo mặc định, thư mục này là 'runs/detect/train#', trong đó # là một index số nguyên.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 -
Bạn cũng có thể sử dụng function Ultralytics data.split.autosplit để tự động chia dataset:
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ết luận#
Trong hướng dẫn này, chúng ta đã tìm hiểu quy trình sử dụng cross-validation K-Fold để train model phát hiện đối tượng YOLO. Chúng ta đã học cách chia tập train và validation thành K partition, đồng thời sử dụng bảng tỷ lệ được tạo để kiểm tra độ cân bằng class sau khi chia ngẫu nhiên.
Chúng ta cũng đã tìm hiểu quy trình tạo các DataFrame báo cáo để trực quan hóa các split dữ liệu và phân phối nhãn trong những split này, giúp chúng ta hiểu rõ cấu trúc của các tập train và validation.
Bạn có thể tùy chọn lưu các record để tham khảo sau này; điều này đặc biệt hữu ích trong các project quy mô lớn hoặc khi khắc phục sự cố về hiệu năng model.
Cuối cùng, chúng ta đã triển khai quá trình train model thực tế bằng cách lần lượt sử dụng từng split trong một vòng lặp, đồng thời lưu kết quả train để phân tích và so sánh thêm.
Kỹ thuật cross-validation K-Fold là một phương pháp robust để tận dụng tối đa dữ liệu hiện có, đồng thời giúp đảm bảo hiệu năng model đáng tin cậy và nhất quán trên các subset dữ liệu khác nhau. Nhờ đó, model có khả năng tổng quát hóa và độ tin cậy cao hơn, ít có khả năng overfit vào các pattern dữ liệu cụ thể.
Hãy nhớ rằng mặc dù chúng ta sử dụng YOLO trong hướng dẫn này, các bước trên phần lớn có thể áp dụng cho những model machine learning khác. Hiểu rõ các bước này cho phép bạn áp dụng cross-validation hiệu quả trong các project machine learning của riêng mình.
FAQ#
Cross-validation K-Fold là một kỹ thuật trong đó dataset được chia thành 'k' subset (fold) để đánh giá hiệu năng model đáng tin cậy hơn. Mỗi fold đóng vai trò vừa là dữ liệu validation vừa là dữ liệu train. Trong bối cảnh phát hiện đối tượng, sử dụng cross-validation K-Fold giúp đảm bảo hiệu năng của model Ultralytics YOLO robust và có khả năng tổng quát hóa trên các split dữ liệu khác nhau, qua đó tăng độ tin cậy. Để xem hướng dẫn chi tiết về cách thiết lập cross-validation K-Fold với Ultralytics YOLO, hãy tham khảo Cross-validation K-Fold với Ultralytics.
Để triển khai cross-validation K-Fold với Ultralytics YOLO, bạn cần thực hiện các bước sau:
- Xác minh annotation ở định dạng phát hiện YOLO.
- Sử dụng các thư viện Python như
sklearn,pandasvàpyyaml. - Tạo vector đặc trưng từ dataset của bạn.
- Chia dataset bằng
KFoldtừsklearn.model_selection. - Train model YOLO trên từng split.
Để xem hướng dẫn toàn diện, hãy tham khảo phần Chia Dataset K-Fold trong tài liệu của chúng tôi.
Workflow trong hướng dẫn này nhắm đến định dạng phát hiện YOLO, nhưng cùng một phương pháp có thể điều chỉnh cho mọi task YOLO — task sẽ thay đổi cách bạn tạo fold, chứ không thay đổi việc cross-validation có hữu ích hay không:
Task Thiết kế fold detectChia ở cấp độ ảnh, cân bằng phân phối object và class giữa các fold. Giữ các ảnh có liên quan (cùng bệnh nhân, chuỗi video, camera hoặc địa điểm) trong cùng một fold. segmentSử dụng chiến lược cấp độ ảnh giống như trong detection, đồng thời bảo toàn mask và độ phủ class trong mỗi fold. classifyƯu tiên các fold stratified để tần suất class luôn cân bằng giữa train và validation. poseChia theo subject hoặc sequence để cùng một người hoặc động vật không bao giờ xuất hiện ở cả hai phía của một fold. obbChia ở cấp độ ảnh, giữ các tile hoặc crop từ cùng một cảnh cùng nhau — điều này đặc biệt quan trọng đối với ảnh chụp từ trên không. Dù là task nào, hãy giữ các sample gần như trùng lặp và có liên quan khỏi những fold đối lập: dạng data leakage này làm tăng các metric validation vượt xa mức model có thể đạt được trong production.
Ultralytics YOLO cung cấp khả năng phát hiện đối tượng real-time tiên tiến với độ chính xác và hiệu quả cao. Model này linh hoạt, hỗ trợ nhiều task computer vision như detection, instance segmentation, semantic segmentation và classification. Ngoài ra, model tích hợp liền mạch với các công cụ như Ultralytics Platform để train và deploy model không cần code. Để biết thêm chi tiết, hãy khám phá các lợi ích và tính năng trên trang Ultralytics YOLO của chúng tôi.
Annotation của bạn phải tuân theo định dạng phát hiện YOLO. Mỗi file annotation phải liệt kê class của object cùng với tọa độ bounding box tương ứng trong ảnh. Định dạng YOLO đảm bảo quá trình xử lý dữ liệu được tinh gọn và chuẩn hóa để train các model phát hiện đối tượng. Để biết thêm thông tin về định dạng annotation chính xác, hãy xem hướng dẫn định dạng phát hiện YOLO.
Có, bạn có thể sử dụng cross-validation K-Fold với bất kỳ dataset tùy chỉnh nào miễn là annotation ở định dạng phát hiện YOLO. Thay thế các path dataset và nhãn class bằng những giá trị cụ thể của dataset tùy chỉnh. Tính linh hoạt này đảm bảo mọi project phát hiện đối tượng đều có thể hưởng lợi từ việc đánh giá model robust bằng cross-validation K-Fold. Để xem ví dụ thực tế, hãy tham khảo phần Tạo Vector Đặc trưng của chúng tôi.