K-Fold Cross Validation với Ultralytics
Giới thiệu
Hướng dẫn toàn diện này minh họa việc triển khai K-Fold Cross Validation 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ẽ tận 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 các thiết lập cần thiết, quy trình tạo vectơ đặc trưng và thực hiện phân chia tập dữ liệu K-Fold.
Cho dù dự án của bạn liên quan đến tập dữ liệu Phát hiện trái cây hay nguồn dữ liệu tùy chỉnh, hướng dẫn này nhằm mục đích giúp bạn hiểu và áp dụng K-Fold Cross Validation để củng cố độ tin cậy và tính mạnh mẽ của bạn học máy các mô hình. Trong khi chúng tôi đang áp dụng k=5
folds cho hướng dẫn này, hãy nhớ rằng số lượng folds tối ưu có thể khác nhau tùy thuộc vào tập dữ liệu và đặc điểm cụ thể của dự án của bạn.
Không cần chần chừ thêm nữa, hãy bắt đầu!
Thiết lập
-
Chú thích 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 tệp chú thích có sẵn cục bộ.
-
Trong phần trình bày này, chúng tôi sử dụng bộ dữ liệu Phát hiện trái cây.
- Tập dữ liệu này chứa tổng cộng 8479 hình ảnh.
- Nó bao gồm 6 nhãn lớp, mỗi nhãn có tổng số lượng thể hiện được liệt kê bên dưới.
Nhãn lớp | Số lượng Instance |
---|---|
Apple | 7049 |
Nho | 7202 |
Trái dứa | 1613 |
Màu cam | 15549 |
Chuối | 3536 |
Dưa hấu | 1976 |
-
Các gói Python cần thiết bao gồm:
ultralytics
sklearn
pandas
pyyaml
-
Hướng dẫn này hoạt động với
k=5
folds. Tuy nhiên, bạn nên xác định số lượng folds tốt nhất cho tập dữ liệu cụ thể của mình. -
Khởi tạo một môi trường ảo Python mới (
venv
) cho dự án của bạn và kích hoạt nó. Sử dụngpip
(hoặc trình quản lý gói ưa thích của bạn) để cài đặt:- Thư viện Ultralytics:
pip install -U ultralytics
. Ngoài ra, bạn có thể sao chép chính thức kho lưu trữ. - Scikit-learn, pandas và PyYAML:
pip install -U scikit-learn pandas pyyaml
.
- Thư viện Ultralytics:
-
Xác minh rằng các chú thích của bạn ở định dạng phát hiện YOLO.
- Trong hướng dẫn này, tất cả các tệp chú thích đều nằm trong
Fruit-Detection/labels
directory.
- Trong hướng dẫn này, tất cả các tệp chú thích đều nằm trong
Tạo các Vector Đặc trưng cho Bộ dữ liệu Phát hiện Đối tượng
-
Bắt đầu bằng cách tạo một cái mới
example.py
Tệp Python cho các bước dưới đây. -
Tiến hành truy xuất tất cả các tệp nhãn cho bộ dữ liệu của bạn.
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'
-
Bây giờ, hãy đọc nội dung của tệp YAML bộ dữ liệu và trích xuất các chỉ số của nhãn lớp.
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())
-
Khởi tạo một đối tượng trống
pandas
DataFrame.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)
-
Đếm số lượng của từng nhãn lớp có trong các tập tin chú thích.
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`
-
Sau đây là một khung nhìn mẫu của DataFrame đã được điền:
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 lập chỉ mục các tệp nhãn, mỗi tệp tương ứng với một hình ảnh trong bộ dữ liệu của bạn và các cột tương ứng với các chỉ số nhãn lớp của bạn. Mỗi hàng đại diện cho một pseudo feature-vector, với số lượng của mỗi nhãn lớp có trong bộ dữ liệu của bạn. Cấu trúc dữ liệu này cho phép áp dụng K-Fold Cross Validation cho một bộ dữ liệu phát hiện đối tượng.
Phân chia tập dữ liệu K-Fold
-
Bây giờ chúng ta sẽ sử dụng
KFold
lớp từsklearn.model_selection
để tạok
các phần chia của tập dữ liệu.- Quan trọng:
- Thiết lập
shuffle=True
đảm bảo phân phối ngẫu nhiên các class (lớp) trong các split (phân tách) của bạn. - Bằng cách thiết lập
random_state=M
trong đóM
là một số nguyên được chọn, bạn có thể thu được kết quả lặp lại.
- Thiết lập
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))
- Quan trọng:
-
Bộ dữ liệu hiện đã được chia thành
k
folds, mỗi fold có một danh sách cáctrain
vàval
indices. Chúng tôi 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=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"
-
Bây giờ chúng ta sẽ tính toán sự phân bố của các nhãn lớp cho mỗi fold dưới dạng tỷ lệ của các lớp có trong
val
cho những người có mặt 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}"] = ratio
Kịch bản lý tưởng là tất cả các tỷ lệ lớp phải tương đối giống nhau cho mỗi lần phân tách và giữa các lớp. Tuy nhiên, điều này sẽ tùy thuộc vào đặc điểm cụ thể của bộ dữ liệu của bạn.
-
Tiếp theo, chúng ta tạo các thư mục và tệp YAML bộ dữ liệu cho mỗi phần tách.
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, )
-
Cuối cùng, sao chép hình ảnh và nhãn vào thư mục tương ứng ('train' hoặc 'val') cho mỗi phần tách.
- LƯU Ý: Thời gian cần thiết cho phần mã này sẽ khác nhau tùy thuộc vào kích thước tập dữ liệu và phần cứng hệ thống của bạn.
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)
Lưu trữ bản ghi (Tùy chọn)
Tùy chọn, bạn có thể lưu các bản ghi của K-Fold split và DataFrame phân phối nhãn dưới dạng tệp CSV để tham khảo trong tương lai.
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ách sử dụng phân chia dữ liệu K-Fold
-
Đầu tiên, tải mô hình YOLO.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # use yolo11n.pt for a small model model = YOLO(weights_path, task="detect")
-
Tiếp theo, lặp lại các tệp YAML của bộ dữ liệu để chạy huấn luyện. Kết quả sẽ được lưu vào một thư mục được chỉ định bởi
project
vàname
các tham số. Theo mặc định, thư mục này là 'runs\detect\train#' trong đó # là một chỉ mục 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 hàm Ultralytics data.utils.autosplit để tự động chia tách dataset:
from ultralytics.data.utils 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 đã khám phá quy trình sử dụng K-Fold cross-validation để huấn luyện mô hình phát hiện đối tượng YOLO. Chúng ta đã học cách chia tập dữ liệu của mình thành K phân vùng, đảm bảo phân phối lớp cân bằng trên các fold khác nhau.
Chúng tôi cũng đã khám phá quy trình tạo DataFrames báo cáo để trực quan hóa các phân tách dữ liệu và phân phối nhãn trên các phân tách này, cung cấp cho chúng tôi cái nhìn rõ ràng về cấu trúc của bộ đào tạo và xác thực.
Tùy chọn, chúng tôi đã lưu lại các bản ghi để tham khảo trong tương lai, điều 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ố hiệu suất mô hình.
Cuối cùng, chúng tôi đã triển khai việc huấn luyện mô hình thực tế bằng cách sử dụng từng phần chia nhỏ trong một vòng lặp, lưu kết quả huấn luyện của chúng tôi để phân tích và so sánh thêm.
Kỹ thuật cross-validation K-Fold này là một cách mạnh mẽ để tận dụng tối đa dữ liệu hiện có của bạn và nó giúp đảm bảo rằng hiệu suất mô hình của bạn là đáng tin cậy và nhất quán trên các tập hợp con dữ liệu khác nhau. Điều này dẫn đến một mô hình tổng quát hơn và đáng tin cậy hơn, ít có khả năng quá khớp với các mẫu dữ liệu cụ thể.
Hãy nhớ rằng mặc dù chúng tôi đã sử dụng YOLO trong hướng dẫn này, nhưng các bước này hầu hết có thể chuyển sang các mô hình học máy khác. Hiểu các bước này cho phép bạn áp dụng cross-validation một cách hiệu quả trong các dự án học máy của riêng bạn. Chúc bạn viết code vui vẻ!
Câu hỏi thường gặp
K-Fold Cross Validation là gì và tại sao nó hữu ích trong phát hiện đối tượng?
K-Fold Cross Validation là một kỹ thuật trong đó tập dữ liệu được chia thành 'k' tập hợp con (folds) để đánh giá hiệu suất mô hình một cách đáng tin cậy hơn. Mỗi fold đóng vai trò là dữ liệu huấn luyện và xác thực. Trong bối cảnh phát hiện đối tượng, việc sử dụng K-Fold Cross Validation giúp đảm bảo hiệu suất của mô hình Ultralytics YOLO của bạn mạnh mẽ và có khả năng khái quát hóa trên các phần chia dữ liệu khác nhau, nâng cao độ tin cậy của nó. Để biết hướng dẫn chi tiết về cách thiết lập K-Fold Cross Validation với Ultralytics YOLO, hãy tham khảo K-Fold Cross Validation với Ultralytics.
Làm cách nào để triển khai K-Fold Cross Validation bằng Ultralytics YOLO?
Để triển khai K-Fold Cross Validation với Ultralytics YOLO, bạn cần làm theo các bước sau:
- Xác minh chú thích ở định dạng phát hiện YOLO.
- Sử dụng các thư viện Python như
sklearn
,pandas
, vàpyyaml
. - Tạo các vector đặc trưng từ bộ dữ liệu của bạn.
- Chia tập dữ liệu của bạn bằng cách sử dụng
KFold
từsklearn.model_selection
. - Huấn luyện mô hình YOLO trên mỗi phần tách.
Để có hướng dẫn toàn diện, hãy xem phần Chia bộ dữ liệu K-Fold trong tài liệu của chúng tôi.
Tại sao tôi nên sử dụng Ultralytics YOLO để phát hiện đối tượng?
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 và hiệu quả cao. Nó 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 và phân loại. Ngoài ra, nó tích hợp liền mạch với các công cụ như Ultralytics HUB để huấn luyện và triển khai mô hình 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.
Làm cách nào để đảm bảo các chú thích của tôi ở đúng định dạng cho Ultralytics YOLO?
Chú thích của bạn phải tuân theo định dạng phát hiện YOLO. Mỗi tệp chú thích phải liệt kê lớp đối tượng, cùng với tọa độ hộp giới hạn của nó trong hình ảnh. Định dạng YOLO đảm bảo xử lý dữ liệu hợp lý và tiêu chuẩn hóa để đào tạo các mô hình phát hiện đối tượng. Để biết thêm thông tin về định dạng chú thích thích hợp, hãy truy cập hướng dẫn định dạng phát hiện YOLO.
Tôi có thể sử dụng K-Fold Cross Validation với các bộ dữ liệu tùy chỉnh khác ngoài Fruit Detection không?
Có, bạn có thể sử dụng K-Fold Cross Validation với bất kỳ bộ dữ liệu tùy chỉnh nào miễn là các chú thích ở định dạng phát hiện YOLO. Thay thế đường dẫn bộ dữ liệu và nhãn lớp bằng những đường dẫn và nhãn dành riêng cho bộ dữ liệu tùy chỉnh của bạn. Sự linh hoạt này đảm bảo rằng mọi dự án phát hiện đối tượng đều có thể hưởng lợi từ việc đánh giá mô hình mạnh mẽ bằng K-Fold Cross Validation. Để có một ví dụ thực tế, hãy xem lại phần Tạo vectơ đặc trưng của chúng tôi.