Các Phương Pháp Phân Chia Dataset Trong PyTorch Cho Deep Learning

Giới thiệu

Khi làm việc với deep learning, việc chuẩn bị dữ liệu là một bước quan trọng. Trong bài viết này, chúng ta sẽ tìm hiểu các phương pháp để phân chia dataset phục vụ việc huấn luyện mô hình.

Phương pháp 1: Phân chia tập huấn luyện và tập kiểm tra

Đầu tiên, chúng ta cần chia dữ liệu thành hai phần: tập huấn luyện (training set) và tập kiểm tra (validation set). Dưới đây là code Python để thực hiện việc này:

import os
from shutil import copy, rmtree
import random


def tao_thu_muc(duong_dan: str):
    if os.path.exists(duong_dan):
        rmtree(duong_dan)
    os.makedirs(duong_dan)


def main():
    random.seed(42)
    ti_le_chia = 0.15
    
    thu_muc_goc = os.getcwd()
    duong_dan_du_lieu = os.path.join(thu_muc_goc, "dulieu")
    thu_muc_nguon = os.path.join(duong_dan_du_lieu, "hinh_anh")
    
    if not os.path.exists(thu_muc_nguon):
        raise FileNotFoundError(f"Không tìm thấy thư mục: {thu_muc_nguon}")
    
    cac_lop = [cl for cl in os.listdir(thu_muc_nguon)
               if os.path.isdir(os.path.join(thu_muc_nguon, cl))]
    
    thu_muc_train = os.path.join(duong_dan_du_lieu, "train")
    tao_thu_muc(thu_muc_train)
    for lop in cac_lop:
        tao_thu_muc(os.path.join(thu_muc_train, lop))
    
    thu_muc_val = os.path.join(duong_dan_du_lieu, "validation")
    tao_thu_muc(thu_muc_val)
    for lop in cac_lop:
        tao_thu_muc(os.path.join(thu_muc_val, lop))
    
    for lop in cac_lop:
        duong_dan_lop = os.path.join(thu_muc_nguon, lop)
        danh_sach_anh = os.listdir(duong_dan_lop)
        so_luong = len(danh_sach_anh)
        danh_sach_val = random.sample(danh_sach_anh, k=int(so_luong * ti_le_chia))
        
        for chi_so, ten_anh in enumerate(danh_sach_anh):
            if ten_anh in danh_sach_val:
                duong_dan_nguon = os.path.join(duong_dan_lop, ten_anh)
                duong_dan_moi = os.path.join(thu_muc_val, lop)
                copy(duong_dan_nguon, duong_dan_moi)
            else:
                duong_dan_nguon = os.path.join(duong_dan_lop, ten_anh)
                duong_dan_moi = os.path.join(thu_muc_train, lop)
                copy(duong_dan_nguon, duong_dan_moi)
            print(f"\r[{lop}] Đang xử lý [{chi_so + 1}/{so_luong}]", end="")
        print()

    print("Hoàn tất xử lý!")


if __name__ == '__main__':
    main()

Phương pháp 2: Giảm kích thước dataset cho phần cứng hạn chế

Khi máy tính có cấu hình yếu hoặc tham số mô hình quá lớn, chúng ta có thể giảm bớt số lượng ảnh để việc huấn luyện diễn ra trơn tru hơn.

Cách 2.1: Xóa ngẫu nhiên ảnh khỏi thư mục

Phương pháp này phù hợp với các dataset chuẩn có cấu trúc thư mục theo từng lớp:

import os
import random

def xoa_ngau_nhien(duong_dan_thu_muc, so_luong_xoa):
    cac_tep = os.listdir(duong_dan_thu_muc)
    cac_anh = [f for f in cac_tep if f.lower().endswith(('.jpg', '.png', '.jpeg'))]
    
    so_luong_xoa = min(so_luong_xoa, len(cac_anh))
    if so_luong_xoa == 0:
        print("Không có ảnh để xóa")
        return
    
    anh_can_xoa = random.sample(cac_anh, so_luong_xoa)
    
    for anh in anh_can_xoa:
        duong_dan_anh = os.path.join(duong_dan_thu_muc, anh)
        os.remove(duong_dan_anh)
        print(f"Đã xóa: {anh}")

# Ví dụ sử dụng
xoa_ngau_nhien(r'D:\Project\HuanLuyen\DuLieu\class_bird', 15)

Cách 2.2: Sử dụng Subset từ PyTorch

Đối với các dataset có sẵn trong torchvision như CIFAR10, MNIST, chúng ta có thể sử dụng lớp torch.utils.data.Subset để lấy một phần của dataset:

from torchvision import datasets
from torch.utils.data import DataLoader, Subset

# Khởi tạo dataset gốc
train_data = datasets.CIFAR10(
    root=duong_dan_hinh,
    train=True,
    download=False,
    transform=data_transform['train']
)

# Chọn 8000 ảnh đầu tiên cho tập huấn luyện
train_indices = list(range(8000))
train_subset = Subset(train_data, train_indices)

train_loader = DataLoader(
    train_subset,
    batch_size=batch_size,
    shuffle=True,
    num_workers=2
)

# Gán thuộc tính class_to_idx
train_subset.class_to_idx = train_data.class_to_idx

# Tương tự với tập kiểm tra
test_data = datasets.CIFAR10(
    root=duong_dan_hinh,
    train=False,
    download=False,
    transform=data_transform['val']
)

test_indices = list(range(1500))
test_subset = Subset(test_data, test_indices)

test_loader = DataLoader(
    test_subset,
    batch_size=batch_size,
    shuffle=False,
    num_workers=2
)

# Lấy danh sách các lớp
danh_sach_lop = train_subset.class_to_idx
print(f"Số lượng batch huấn luyện: {len(train_loader)}")

Lưu ý quan trọng

Khi sử dụng Subset, cần sao chép thuộc tính class_to_idx từ dataset gốc sang subset để tránh lỗi khi truy cập nhãn lớp:

subset.dataset.class_to_idx = original_dataset.class_to_idx

Thẻ: PyTorch deep-learning Dataset data-preprocessing computer-vision

Đăng vào ngày 18 tháng 6 lúc 07:56