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 tập dữ liệu 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 quan trọng như sklearn, pandas và PyYAML để hướng dẫn bạn qua các bước thiết lập cần thiết, quy trình tạo vector đặc trưng và cách chia tập dữ liệu theo K-Fold.
Dù dự án của bạn sử dụng tập dữ liệu Fruit Detection hay một nguồn dữ liệu tùy chỉnh, hướng dẫn 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 vững chắc cho các model machine learning của mình. Trong hướng dẫn này, chúng ta sử dụng k=5 fold; tuy nhiên, hãy lưu ý rằng số fold tối ưu có thể thay đổi tùy theo tập dữ liệu và đặc thù của dự án. Cross-validation K-Fold phát huy hiệu quả cao nhất khi tập dữ liệu nhỏ, nhiễu hoặc có độ biến thiên lớn; với các tập dữ liệu lớn và đa dạng, việc chia train/val/test được thiết kế tốt thường là đủ.
Bắt đầu thôi.
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 cục bộ.
-
Trong phần minh họa, chúng ta sử dụng tập dữ liệu Fruit Detection.
- Tập dữ liệu này có tổng cộng 8479 ảnh.
- Tập dữ liệu gồm 6 nhãn class, cùng tổng số instance của từng 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
-
Hướng dẫn này sử dụng
k=5fold. Tuy nhiên, bạn nên xác định số fold phù hợp nhất với tập dữ liệu cụ thể của mình.
-
Tạo một môi trường ảo Python mới (
venv) cho dự án và kích hoạt môi trường đó. Dùngpip(hoặc trình quản lý package bạn ưu tiê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 annotation của bạn ở định dạng phát hiện YOLO.
- Trong hướng dẫn này, tất cả file annotation đều nằm trong thư mục
Fruit-Detection/labels.
- Trong hướng dẫn này, tất cả file annotation đều nằm trong thư mục
Tạo vector đặc trưng cho tập dữ liệu phát hiện đối tượng#
-
Trước tiên, hãy tạo một file Python
example.pymới để thực hiện các bước bên dưới. -
Tải ảnh huấn luyện và validation đã cấu hình thông qua dataset loader của package, đồng thời giữ nguyên tập test.
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 file YAML của tập dữ liệu và trích xuất chỉ số 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 nhãn class 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à ví dụ về DataFrame sau khi đượ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 chỉ số nhãn class. Các nhãn bị thiếu được biểu diễn bằng hàng nền toàn số 0. Cấu trúc dữ liệu này cho phép áp dụng cross-validation K-Fold cho tập dữ liệu phát hiện đối tượng.
Chia tập dữ liệu theo K-Fold#
-
Tiếp theo, chúng ta sẽ dùng class
KFoldtừsklearn.model_selectionđể tạo các phần chia tập dữ liệuk.- 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 các phần chia. - Bằng cách đặt
random_state=Mtrong đóMlà một số nguyên được chọn, bạn có thể thu được kết quả có thể tái lập.
- Thiết lập
from sklearn.model_selection import KFold ksplit = 5 kf = KFold(n_splits=ksplit, shuffle=True, random_state=20) # đặt random_state để có kết quả có thể tái lập kfolds = list(kf.split(labels_df)) - Quan trọng:
-
Tập dữ liệu hiện đã được chia thành
kfold, mỗi fold có danh sách các chỉ sốtrainvàval. Chúng ta sẽ tạo một DataFrame để trình bày các kết quả này rõ 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" -
Tiếp theo, chúng ta sẽ tính tỷ lệ phân phối nhãn class cho từng fold bằng cách lấy số class có trong
valchia cho số 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}"] = ratioTốt nhất là tỷ lệ của tất cả class tương đối đồng đều ở mỗi phần chia và giữa các class. Tuy nhiên, điều này còn tùy thuộc vào đặc thù của tập dữ liệu.
-
Ghi danh sách ảnh và file YAML của tập dữ liệu cho từng phần chia. Danh sách dạng văn bản giúp tránh phải sao chép tập dữ liệu
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 bản ghi (Tùy chọn)#
Bạn có thể lưu bản ghi về phần chia K-Fold và các DataFrame 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")Huấn luyện YOLO bằng các phần chia dữ liệu K-Fold#
-
Trước tiên, hãy tải model YOLO.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # dùng yolo26n.pt cho model nhỏ model = YOLO(weights_path, task="detect") -
Tiếp theo, lặp qua các file YAML của tập dữ liệu để chạy huấn luyện. Kết quả sẽ được lưu vào thư mục được chỉ định bằng các đối số
projectvàname. Theo mặc định, thư mục này là 'runs/detect/train#', trong đó # là một chỉ 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ể dùng hàm Ultralytics data.split.autosplit để tự động chia tập dữ liệu:
from ultralytics.data.split import autosplit # Tự động chia tập dữ liệu thành 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 để huấn luyện model phát hiện đối tượng YOLO. Chúng ta đã tìm hiểu cách chia tập train và validation thành K phần, cũng như cách dùng bảng tỷ lệ được tạo để kiểm tra mức độ 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 phần chia dữ liệu và phân phối nhãn giữa những phần chia này, qua đó nắm rõ cấu trúc của các tập train và validation.
Chúng ta có thể lưu bản ghi để tham khảo sau này; việc này đặc biệt hữu ích trong các dự án quy mô lớn hoặc khi khắc phục sự cố về hiệu suất model.
Cuối cùng, chúng ta đã triển khai quá trình huấn luyện model thực tế bằng cách lần lượt sử dụng từng phần chia, đồng thời lưu kết quả huấn luyện để phân tích và so sánh thêm.
Kỹ thuật cross-validation K-Fold là một phương pháp vững chắc giúp tận dụng tối đa dữ liệu hiện có, đồng thời đảm bảo hiệu suất model đáng tin cậy và nhất quán trên các tập con dữ liệu khác nhau. Nhờ đó, model có khả năng khái quát hóa tốt hơn, đáng tin cậy hơn và ít có nguy cơ overfit với các mẫu dữ liệu cụ thể.
Hãy nhớ rằng dù hướng dẫn này sử dụng YOLO, các bước này 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 giúp bạn áp dụng cross-validation hiệu quả trong các dự án machine learning của riêng mình.
Câu hỏi thường gặp#
Cross-validation K-Fold là kỹ thuật chia tập dữ liệu thành 'k' tập con (fold) để đánh giá hiệu suất model đáng tin cậy hơn. Mỗi fold lần lượt được dùng làm dữ liệu huấn luyện và dữ liệu validation. Trong lĩnh vực phát hiện đối tượng, cross-validation K-Fold giúp đảm bảo hiệu suất của model Ultralytics YOLO vững chắc và có khả năng khái quát hóa trên các phần chia dữ liệu khác nhau, từ đó 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, hãy làm theo 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ừ tập dữ liệu của bạn.
- Chia tập dữ liệu bằng
KFoldtừsklearn.model_selection. - Huấn luyện model YOLO trên từng phần chia.
Để xem hướng dẫn toàn diện, hãy tham khảo mục Chia tập dữ liệu theo K-Fold trong tài liệu của chúng tôi.
Quy trình trong hướng dẫn này hướng đến định dạng phát hiện YOLO, nhưng cùng phương pháp có thể áp dụng cho mọi tác vụ YOLO — tác vụ chỉ thay đổi cách bạn tạo các fold, chứ không ảnh hưởng đến lợi ích của cross-validation:
Tác vụ Thiết kế fold detectChia ở cấp độ ảnh, cân bằng phân phối đối tượng 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. segmentDùng cùng chiến lược cấp độ ảnh như trong phát hiện đối tượng, đồng thời đảm bảo độ bao phủ của mask và class trong mọi fold. classifyƯu tiên các fold phân tầng để tần suất class được cân bằng giữa train và validation. poseChia theo đối tượng hoặc chuỗi để cùng một người hay động vật không bao giờ xuất hiện ở cả hai phần của một fold. obbChia ở cấp độ ảnh, giữ các tile hoặc crop từ cùng một cảnh trong cùng nhóm — điều này đặc biệt quan trọng với ảnh hàng không. Dù là tác vụ nào, hãy tránh để các mẫu gần như trùng lặp hoặc có liên quan nằm ở các fold đối lập: dạng rò rỉ này làm tăng các chỉ số validation vượt xa mức model có thể đạt được khi triển khai thực tế.
Ultralytics YOLO cung cấp khả năng phát hiện đối tượng theo thời gian thực hiện đại với độ chính xác cao và hiệu quả vượt trội. Model rất linh hoạt, hỗ trợ nhiều tác vụ thị giác máy tính như phát hiện, phân đoạn instance, phân đoạn ngữ nghĩa và phân loại. Ngoài ra, model tích hợp liền mạch với các công cụ như Ultralytics Platform để huấn luyện và triển khai model không cần viết mã. Để biết thêm chi tiết, hãy tìm hiểu 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 đối tượng cùng với tọa độ bounding box của đối tượng trong ảnh. Định dạng YOLO đảm bảo quy trình xử lý dữ liệu được tinh gọn và chuẩn hóa để huấn luyện model phát hiện đối tượng. Để biết thêm thông tin về cách định dạng annotation phù hợp, hãy xem hướng dẫn về định dạng phát hiện YOLO.
Có, bạn có thể dùng cross-validation K-Fold với mọi tập dữ liệu tùy chỉnh, miễn là annotation ở định dạng phát hiện YOLO. Thay thế các đường dẫn tập dữ liệu và nhãn class bằng những giá trị tương ứng với tập dữ liệu tùy chỉnh của bạn. Tính linh hoạt này giúp mọi dự án phát hiện đối tượng đều có thể đánh giá model vững chắc bằng cross-validation K-Fold. Để xem ví dụ thực tế, hãy tham khảo mục Tạo vector đặc trưng của chúng tôi.