본문 바로가기
Artificial Intelligence/21. PyTorch

[PYTORCH] Subset을 이용해 학습/검증 데이터를 나누는 3가지 방법과 데이터 누수 해결 가이드

by Papa Martino V 2026. 3. 25.
728x90

Subset 클래스
Subset 클래스

 

모델의 성능을 객관적으로 평가하기 위해 전체 데이터를 학습(Train)과 검증(Validation) 세트로 나누는 과정은 필수적입니다. PyTorch에서는 torch.utils.data.Subset 클래스를 통해 원본 데이터를 물리적으로 복사하지 않고도 인덱스 참조만으로 데이터를 효율적으로 분할할 수 있습니다. 본 가이드에서는 2026년 실무 표준에 따른 데이터 분할 전략과 발생 가능한 데이터 누수(Data Leakage) 해결 방안을 상세히 다룹니다.


1. Subset 클래스의 동작 원리와 메모리 효율성

PyTorch의 Subset은 원본 데이터셋 객체와 선택하고자 하는 인덱스 리스트를 인자로 받습니다. 이는 얕은 복사(Shallow Copy) 방식을 취하므로, 수십 GB에 달하는 이미지나 비디오 데이터를 다룰 때 메모리 점유율을 비약적으로 낮출 수 있다는 독보적인 장점이 있습니다. 단순히 리스트를 슬라이싱하는 방식과 비교했을 때, Subset은 PyTorch의 DataLoader와 완벽하게 호환되며 데이터셋의 추상화 인터페이스를 그대로 유지합니다.

2. 데이터 분할 방식에 따른 장점 및 기술적 차이 해결

데이터를 나누는 방법은 크게 랜덤 분할과 순차 분할로 나뉩니다. 각 상황에 맞는 최적의 선택을 돕기 위해 비교 분석표를 제시합니다.

분할 방식 사용 도구 핵심 특징 해결 가능한 문제
무작위 분할 (Random) random_split 전체 분포를 고르게 반영 데이터 순서에 따른 편향(Bias) 해결
인덱스 기반 분할 (Index) Subset 직접 활용 특정 조건에 따른 세밀한 제어 시계열 데이터의 순서 보존 해결
계층적 분할 (Stratified) Scikit-learn + Subset 클래스 비율 유지 불균형 데이터셋의 학습 안정성 확보
교차 검증 분할 (K-Fold) KFold + Subset 모든 데이터의 검증 활용 소규모 데이터셋의 일반화 성능 확보

3. 실무 즉시 적용 가능한 데이터 분할 Example 7가지

실제 프로젝트에서 발생할 수 있는 7가지 시나리오별 Subset 활용 코드 예제입니다.

Example 1: random_split을 이용한 표준 8:2 분할 방법

가장 범용적으로 사용되는 방식으로, 시드가 고정되어 재현성을 보장합니다.

import torch
from torch.utils.data import DataLoader, random_split

# 전체 데이터셋 로드 후 크기 계산
total_size = len(full_dataset)
train_size = int(0.8 * total_size)
val_size = total_size - train_size

# 시드 고정을 통한 결과 재현 해결
generator = torch.Generator().manual_seed(42)
train_dataset, val_dataset = random_split(full_dataset, [train_size, val_size], generator=generator)
        

Example 2: Subset과 인덱스를 이용한 수동 분할

전체 데이터의 뒷부분 20%를 검증 데이터로 고정할 때 유용합니다.

from torch.utils.data import Subset

indices = list(range(len(full_dataset)))
split = int(0.8 * len(full_dataset))

train_indices = indices[:split]
val_indices = indices[split:]

train_dataset = Subset(full_dataset, train_indices)
val_dataset = Subset(full_dataset, val_indices)
        

Example 3: 클래스 비율을 유지하는 계층적(Stratified) 분할 방법

클래스 불균형이 심한 데이터셋에서 학습 안정성을 확보하는 해결 방법입니다.

from sklearn.model_selection import train_test_split

# 레이블 정보만 추출 (예: full_dataset.labels)
targets = [label for _, label in full_dataset]
train_idx, val_idx = train_test_split(
    list(range(len(full_dataset))),
    test_size=0.2,
    stratify=targets,
    random_state=42
)

train_dataset = Subset(full_dataset, train_idx)
val_dataset = Subset(full_dataset, val_idx)
        

Example 4: 시계열 데이터(Time-series)를 위한 순차적 분할

미래 데이터를 보고 과거를 맞추는 실수를 방지하기 위해 셔플링 없이 분할합니다.

# 시계열은 절대 섞으면 안 됨 (No Shuffle)
split_point = int(len(full_dataset) * 0.9)
train_dataset = Subset(full_dataset, range(split_point))
val_dataset = Subset(full_dataset, range(split_point, len(full_dataset)))
        

Example 5: K-Fold 교차 검증 구현 예제

from sklearn.model_selection import KFold

kf = KFold(n_splits=5, shuffle=True, random_state=42)
for fold, (train_idx, val_idx) in enumerate(kf.split(range(len(full_dataset)))):
    train_sub = Subset(full_dataset, train_idx)
    val_sub = Subset(full_dataset, val_idx)
    # 각 fold 별 학습 루프 실행
        

Example 6: 분할된 Subset에 서로 다른 Transforms 적용 방법

Subset 사용 시 가장 많이 겪는 'Transform 공유 문제' 해결 방법입니다.

import copy

class ApplyTransform(torch.utils.data.Dataset):
    def __init__(self, subset, transform=None):
        self.subset = subset
        self.transform = transform
        
    def __getitem__(self, index):
        x, y = self.subset[index]
        if self.transform: x = self.transform(x)
        return x, y
        
    def __len__(self):
        return len(self.subset)

# 학습용은 Augmentation 적용, 검증용은 Resize만 적용
train_dataset = ApplyTransform(train_dataset, transform=train_aug)
val_dataset = ApplyTransform(val_dataset, transform=val_resize)
        

Example 7: Subset을 활용한 대규모 데이터의 소규모 샘플링 테스트

전체 데이터를 돌리기 전 코드 오류를 확인하기 위해 1%만 샘플링합니다.

sample_idx = torch.randperm(len(full_dataset))[:int(0.01 * len(full_dataset))]
mini_dataset = Subset(full_dataset, sample_idx)
        

4. 데이터 누수(Data Leakage) 방지를 위한 3가지 체크리스트

  1. 중복 샘플 제거: 원본 데이터에 중복이 있다면 Train과 Val에 같은 데이터가 들어갈 수 있습니다. Subset 적용 전 Set 자료형으로 고유성을 확인하십시오.
  2. Transform 시점: 검증 데이터셋에 RandomHorizontalFlip 같은 학습용 Augmentation이 포함되어 있는지 확인하십시오. Example 6의 래퍼 클래스 방식이 가장 안전합니다.
  3. 시드 관리: random_split 사용 시 반드시 고정된 Generator를 전달하여 실행할 때마다 분할 영역이 바뀌는 것을 방지하십시오.

5. 결론: 효율적인 실험 설계가 모델의 가치를 만든다

PyTorch의 Subset은 단순히 데이터를 나누는 도구를 넘어, 하드웨어 자원을 보존하면서도 실험의 무결성을 지켜주는 핵심 클래스입니다. 특히 2026년의 복잡한 멀티모달 데이터 환경에서는 물리적 분할보다 인덱스 기반의 Subset 관리가 데이터 파이프라인의 유연성을 결정짓는 승부처가 될 것입니다.

참고 문헌 및 기술 출처

  • PyTorch Documentation: `torch.utils.data.Subset` & `random_split` API
  • "Deep Learning with PyTorch" (Eli Stevens, 2024 Revised Edition)
  • PyTorch Community Forum: "Correct way to split train and test datasets"
728x90