PyTorch

5. Dataset & DataLoader

MoonLight314 2025. 3. 3. 20:46
728x90
반응형

안녕하세요, MoonLigt입니다.

이번 Post에서는 Train Data를 효율적으로 가공하고 Model에 공급(?)해 주는 역할을 하는 Dataset & DataLoader Module에 대해서 알아보도록 하겠습니다.

 

 

1. Dataset & DataLoader 개념과 필요성

딥러닝 모델을 학습할 때 가장 중요한 요소 중 하나는 바로 "데이터"입니다.

보통 딥러닝 모델을 학습할 때는 대용량의 데이터를 Model에 입력해야 하는데, 잘못된 방식이나 비효율적으로 입력된다면 성능 좋은 모델이 나올 수도 없고 Train에 시간도 많이 걸리게 될 것입니다.

그렇다면, 딥러닝 모델을 학습할 때 최적의 성능을 내도록 데이터를 올바르게 준비하고, 효율적으로 전달하는 방법은 무엇일까요?

가장 단순하게 생각해보면 데이터를 리스트나 NumPy 배열과 같은 기본적인 자료구조에 저장한 후에 이를 하나씩 모델에 전달하는 방식입니다.

예를 들어, 숫자를 입력받아 그에 대응하는 결과를 예측하는 간단한 선형 회귀 모델을 만든다고 가정해봅시다.

입력 데이터와 정답 데이터를 각각 리스트에 저장한 후, 반복문을 이용하여 하나씩 모델에 입력해서 학습을 진행하면 됩니다.

하지만, 이렇게 되면 문제가 데이터가 수천, 수만 개 이상으로 커지면, 하나씩 모델에 전달하는 방식은 매우 비효율적이며 학습 속도가 크게 저하됩니다.

물론, 입력이 숫자밖에 없으니 데이터의 양이 아무리 많아져 봐야 큰 문제가 되지 않을 수도 있습니다만, 입력 데이터가 이미지, 자연어, 소리 등이 되어 버리고 데이터의 양의 커지면 문제가 커집니다.

또한, 보통 딥러닝 모델에서는 GPU 사용의 효율성을 위해서 데이터를 배치(batch) 단위로 학습하는 것이 일반적입니다.

한 번의 학습(Iteration)에서 여러 개의 데이터을 동시에 입력하여 연산 속도를 높이고, 그래디언트 업데이트가 더욱 안정적으로 이루어지도록 하기 위한 것입니다.

이 기능을 직접 구현하면 데이터 배치, 셔플링, 멀티프로세싱 등을 모두 수동으로 처리해야 하므로 코드가 복잡해질 수 있습니다

학습할 때마다 데이터를 정해진 크기대로 나누어야 하고, 게다가 학습할 때마다 동일한 데이터가 입력되지 않도록 데이터를 섞어(shuffle)줘야 하는 기능까지 추가해야 한다면 보통일이 아니죠.

이런 문제들을 해결하기 위해 PyTorch에서는 `Dataset`과 `DataLoader`라는 두 가지 핵심 모듈를 제공합니다.

`Dataset` 모듈은 데이터를 읽어와서 저장하고 개별 샘플을 반환하는 역할을 하며, `DataLoader` 모듈은 이러한 데이터를 배치 단위로 불러오고, 셔플링 및 병렬 처리를 지원하여 학습 속도와 GPU 효율을 극대화하는 역할을 합니다.

이제, `Dataset`과 `DataLoader`가 구체적으로 어떤 역할을 하는지 하나씩 살펴보도록 하겠습니다.

2. Dataset & DataLoader 기본적인 사용법

아래의 Code는 Dataset & DataLoader의 가장 기본적인 형태를 보여주는 Code입니다.

이 Code는 y = 2x + 1의 Linear Regression을 학습하기 위한 Dataset & DataLoader의 예제입니다.

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

# 간단한 Custom Dataset
class CustomDataset(Dataset):
    def __init__(self):
        self.data = [i for i in range(10)] # 샘플 데이터

    def __getitem__(self, index):
        return self.data[index],self.data[index]*2+1

    def __len__(self):
        return len(self.data)

dataset = CustomDataset()

dataloader = DataLoader(dataset, batch_size=3, shuffle=True)

for batch in dataloader:
    print(batch)
출력
[tensor([2, 1, 4]), tensor([5, 3, 9])]
[tensor([9, 5, 3]), tensor([19, 11, 7])]
[tensor([7, 6, 0]), tensor([15, 13, 1])]
[tensor([8]), tensor([17])]

 

 

2.1. 'Dataset' Module

Custom Dataset을 만들기 위해서는 Dataset Class를 상속받아서 3개의 핵심 함수를 구현해 주면 됩니다.

하나씩 살펴보겠습니다.

1) __init__()

· Dataset Class의 초기화 메서드입니다.

· 여기서는 기본적으로 Train Data를 불러오거나 혹은 한 번에 불러올 수 없을 경우에는 Data를 불러올 수 있는 다양한 환경설정을 합니다.

· 예를 들어, 숫자로 된 CSV 파일 형태의 Train Data라면 읽어서 내부 변수에 저장할 수도 있겠죠. 혹은 대용량의 이미지나 텍스트 파일이 Train Data라면 해당 파일의 목록을 내부 변수에 초기화 시킨 후에, 실제로 Data를 읽을 때는 파일 목록을 참고해서 읽어오는 방법도 가능합니다.

· 요약하면 Train Data를 읽어오거나 읽어올 준비를 할 때 필요한 다양한 변수들을 초기화하는 기능을 합니다.

· 한 번만 실행되며, 데이터 로딩 시 반복 실행되지 않습니다.

def __init__(self): 
	self.data = [i for i in range(10)] # 샘플 데이터

위 예제에서 __init__() 메서드는 Train Data로 사용할 내부 변수, .data를 0~9까지의 수로 초기화합니다.

2) __getitem__(index)

· Train Data를 실제로 읽어서 Dataloader로 Return해주는 역할을 하는 메서드입니다.

· Parameter로 Index를 받아서, Index에 해당하는 Train Data와 함께 Train Data의 Target 값도 함께 return 해야 합니다.

· 이 메서드는 Dataloader가 Dataset에게 Data를 요청할 때 마다 Call됩니다.

· 이 메서드내부에서는 Dataloader에 Train Data를 전달하기 전에 다양한 작업을 수행할 수 있습니다.

· 예를 들어, Image같은 경우에는 Index에 해당하는 파일을 읽어서 크기 변형을 포함한 다양한 Data Augmentation을 진행할 수 있습니다.

· 이런 전처리는 텍스트 , 소리 에도 동일하게 적용될 수 있습니다.

    def __getitem__(self, index):
        return self.data[index],self.data[index]*2+1

 

위 예제에서 __getitem__() 메서드는 학습에 필요한 x값과 그에 해당하는 y값을 Return해 주는 역할을 합니다.

이 예제에서는 특별히 전처리가 필요가 없지만, 추후에 살펴볼 Image 처리에서는 다양한 전처리가 필요한데, 그런 작업을 여기서 해주면 됩니다.

3) __len__()

· Dataset Class가 가지고 있는 전체 데이터 수를 반환하는 메서드입니다.

· DataLoader가 몇 번 반복할지를 결정할 때 사용됩니다.

    def __len__(self):
        return len(self.data)

위 예제에서 __len__()는 단순히 Dataset이 가지고 있는 전체 Train Data의 수를 Return해 주면 됩니다.

여기서는 내부 변수 .data의 길이를 Return해 주면 되겠죠.

 

 

2.2. 'DataLoader' Module

DataLoader는 Dataset을 배치 단위로 불러오고, 학습을 최적화하기 위한 다양한 기능을 제공합니다.

DataLoader의 주요 파라미터는 다음과 같습니다.

· dataset : 사용할 데이터셋 객체. 이전에 선언한 것을 사용하면 됩니다.

· batch_size: 한 번에 불러올 데이터 샘플의 개수 (기본값: 1). 이 값을 상황에 맞게(GPU Memory etc.) 적절히 조절해 주시면 됩니다.

· shuffle: 데이터를 무작위로 섞을지 여부(기본값: False)를 결정합니다.

· num_workers : 데이터를 불러올 때 사용할 병렬 프로세스 개수 (기본값: 0, 멀티 프로세싱 활성화 시 성능 향상 가능)

· drop_last : 마지막 배치가 batch_size보다 작을 경우 이를 버릴지 여부 (기본값: False)

dataset = CustomDataset()

dataloader = DataLoader(dataset, batch_size=3, shuffle=True)

for batch in dataloader:
    print(batch)

 

위 예제에서는 앞서 선언한 0~9까지의 Data를 가진 Dataset 객체에서 Data를 읽어오고, 한 번에 읽어오는 갯수(Batch Size)는 3개, 순서대로 읽지말고 무작위로 선택해서 읽어오도록(Shuffle) 합니다.

아래 for를 돌면서 dataloader를 읽으면 아래와 같이 나오는 것을 알 수 있습니다.

출력
[tensor([2, 1, 4]), tensor([5, 3, 9])]
[tensor([9, 5, 3]), tensor([19, 11, 7])]
[tensor([7, 6, 0]), tensor([15, 13, 1])]
[tensor([8]), tensor([17])]

이 값들은 Shuffle되도록 한 값들이기 때문에 여러분들이 실행하면 아마 다른 값들의 조합으로 출력될 것 입니다.

[tensor([2, 1, 4]), tensor([5, 3, 9])]

Batch Size(3)만큼 Train Data(0~9)에서 무작위로(Shuffle) 뽑고(tensor([2, 1, 4])), 각각에 해당하는 Target값(tensor([5, 3, 9]))도 같이 Return해 줍니다.

 

 

3. Examples of Dataset & DataLoader

Dataset & DataLoader의 사용법을 알아보았으니, 몇 가지 예제를 살펴보면서 실제 사용법을 알아보도록 하겠습니다.

2가지 예제를 살펴볼 예정인데요, Linear Regression Model과 Image Classification을 다루어 보겠습니다.

3.1. Linear Regression

먼저 간단한 Linear Regression 문제를 다루면서 Dataset & DataLoader의 사용법을 알아보도록 하겠습니다.

예제를 위해서 임의로 생성한 Data입니다. 첫번째 Column이 x, 두번째 Column이 y값이며 y = 3x + 5를 만족하는 값들에서 약간의 Noise를 추가하였습니다.

49.1899
147.8112
13.97437
42.65056
39.89298
118.7158
72.92857
232.4149
18.37243
65.65343
94.98697
290.3499
.
.

이와 같은 x,y 값이 총 2만개가 있습니다. 예제에서 사용한 csv 파일은 첨부해 두었으니 필요하시면 받아서 사용하시면 됩니다.

3.1.1. Train Code

기본적인 Linear Regression에서 사용할 수 있는 Code를 아래와 같이 준비하였습니다.

기본적인 구성은 이전 Post인 'Basic Train Loop'에서 다루었던 구조와 비슷합니다.

우리가 눈여겨 봐야할 것은 Dataset과 DataLoader의 사용법입니다.

import torch
import torch.nn as nn
import torch.optim as optim
import pandas as pd
from torch.utils.data import Dataset, DataLoader

# 󾠮 Dataset 정의
class LinearRegressionDataset(Dataset):
    def __init__(self, csv_file):
        self.data = pd.read_csv(csv_file)

    def __getitem__(self, index):
        x = torch.tensor(self.data.iloc[index, 0], dtype=torch.float32).unsqueeze(0)    # x 값
        y = torch.tensor(self.data.iloc[index, 1], dtype=torch.float32).unsqueeze(0)    # y 값
        return x, y
    
    def __len__(self):
        return len(self.data)

# 󾠯 DataLoader 설정
csv_path = "./linear_regression_data.csv"

dataset = LinearRegressionDataset(csv_path)

dataloader = DataLoader(dataset, batch_size=256, shuffle=True)


# 󾠰 모델 정의
class LinearRegressionModel(nn.Module):
    def __init__(self):
        super(LinearRegressionModel, self).__init__()
        self.linear = nn.Linear(1, 1) # 입력 1개, 출력 1개
    
    def forward(self, x):
        return self.linear(x)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = LinearRegressionModel().to(device)

# 󾠱 손실 함수 및 옵티마이저 설정
criterion = nn.MSELoss()

optimizer = optim.Adam(model.parameters(), lr=0.001)  # SGD 대신 Adam 사용


# 󾠲 학습 루프
num_epochs = 200

for epoch in range(num_epochs):
    total_loss = 0.0

    for x_batch, y_batch in dataloader:
        x_batch, y_batch = x_batch.to(device), y_batch.to(device)
        optimizer.zero_grad()
        predictions = model(x_batch)
        loss = criterion(predictions, y_batch)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss / len(dataloader):.4f}")

print("Training Completed!")

# 󾠳 학습된 가중치 확인
w, b = model.linear.weight.item(), model.linear.bias.item()
print(f"학습된 모델: y = {w:.3f}x + {b:.3f}")
 

 

3.1.2. Dataset 정의

Dataset Class의 정의부분만 따로 떼서 보면 아래와 같습니다.

Dataset은 말씀드린 3개의 함수(__init__() , __getitem__() , __len__())를 정의하는 부분이 가장 중요합니다.

1) __init__()

    def __init__(self, csv_file):
        self.data = pd.read_csv(csv_file)

Dataset Instance를 생성할 때, 우리가 사용할 CSV File의 Path를 전달합니다.

이것을 받아서 __init__()에서는 내부 변수에 해당 CSV File을 읽어서 저장하는 기능을 구현했습니다.

추후에 이 CSV File에서 x,y Data를 읽어서 Train Loop에 전달하기 위해서입니다.

2) __getitem__()

    def __getitem__(self, index):
        x = torch.tensor(self.data.iloc[index, 0], dtype=torch.float32).unsqueeze(0)    # x 값
        y = torch.tensor(self.data.iloc[index, 1], dtype=torch.float32).unsqueeze(0)    # y 값
        return x, y

__getitem__()은 Parameter로 전달되는 index 값에 해당하는 Data를 읽어서 적절한 전처리를 거친 후에, Train Data와 Target값을 Return하는 기능을 수행하면 됩니다.

3) __len__()

    def __len__(self):
        return len(self.data)

__len__()은 전체 Data의 수를 Return하는 기능만 수행하면 되기 때문에 위와 같이 간단하게 구현할 수 있습니다.

3.1.3. Dataloader 정의

Dataloader는 아래와 같이 간단하게 정의하면 됩니다.

dataloader = DataLoader(dataset, batch_size=256, shuffle=True)

앞서 정의한 dataset과 Batch Size, Data를 섞는 Option인 shuffle 정도 사용하도록 하겠습니다.

3.1.4. Train 결과

이제 Train할 모든 준비를 마쳤으니, Train을 시작합니다.

단순한 수치 Data이니 시간이 오래 걸리지는 않고 금방 끝이 날 것입니다.

저의 실행 결과는 아래와 같았습니다.(Loss 수치는 실행할 때 마다 달라질 것입니다. )

결과
Epoch [10/200], Loss: 31025.5282
Epoch [20/200], Loss: 18407.1935
Epoch [30/200], Loss: 9938.8032
Epoch [40/200], Loss: 4661.6758
Epoch [50/200], Loss: 1752.0332
Epoch [60/200], Loss: 479.0370
Epoch [70/200], Loss: 93.4282
Epoch [80/200], Loss: 29.6183
Epoch [90/200], Loss: 25.5707
Epoch [100/200], Loss: 25.4686
Epoch [110/200], Loss: 25.5857
Epoch [120/200], Loss: 25.4268
Epoch [130/200], Loss: 25.3823
Epoch [140/200], Loss: 25.3971
Epoch [150/200], Loss: 25.5207
Epoch [160/200], Loss: 25.3790
Epoch [170/200], Loss: 25.3884
Epoch [180/200], Loss: 25.4159
Epoch [190/200], Loss: 25.3473
Epoch [200/200], Loss: 25.4567
Training Completed!
학습된 모델: y = 3.003x + 4.944

Train을 마친 Model이 y = 3.003x + 4.944으로 나왔습니다.

학습된 가중치가 실제 값(y = 3x + 5)과 거의 동일하게 수렴한 것을 확인할 수 있습니다.

 

3.2. Image Classification

두번째 예제로써 Image를 분류하는 간단한 Model을 학습시키는데 Dataset & DataLoader를 사용해 보도록 하겠습니다.

Train에 사용할 Image Dataset은 Kaggle에 있는 것을 사용했습니다. 아래 Link를 참고해 주세요.

https://www.kaggle.com/datasets/tongpython/cat-and-dog?resource=download

 

Cat and Dog

Cats and Dogs dataset to train a DL model

www.kaggle.com

 

 

압축을 풀어보면, 아래와 같은 Folder 구조로 되어 있습니다.

 

 

우리는 training_set Folder에 있는 8000여 장의 Image로 Train을 하도록 하겠습니다.

아래는 Train에 사용할 전체 Code입니다.

3.2.1. Train Code

Transfer Learning 기법을 이용한 Image Classification 기본 Code입니다.

Transfer Learning에 관한 자세한 내용을 알고 싶으시면 아래 Post를 참고해 주시기 바랍니다.

https://moonlight314.tistory.com/entry/Transfer-Learning%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80

 

 

우리가 눈여겨 봐야할 것은 Dataset과 DataLoader의 사용법입니다.

그 부분을 집중적으로 살펴보겠습니다.

import os
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.transforms as transforms
from torchvision.models import efficientnet_b0
from torch.utils.data import Dataset, DataLoader, Subset
from PIL import Image
import glob
from sklearn.model_selection import train_test_split

BATCH_SIZE = 512

# 1. Dataset 정의
class DogCatDataset(Dataset):
    def __init__(self, image_dir, transform=None):
        self.image_dir = image_dir+"\\**\\*.jpg"
        self.image_filenames = glob.glob(self.image_dir, recursive=True)
        self.transform = transform

        # 클래스 라벨 할당 (Dog: 0, Cat: 1)
        self.labels = [0 if "dog" in filename else 1 for filename in self.image_filenames]

    def __getitem__(self, index):
        img_path = self.image_filenames[index]
        image = Image.open(img_path).convert("RGB")        
        label = self.labels[index]  # Dog(0), Cat(1)
        
        if self.transform:
            image = self.transform(image)
        
        return image, label

    def __len__(self):
        return len(self.image_filenames)

# 2. 데이터 전처리 및 Train / Validation 분리
transform = transforms.Compose([
    transforms.Resize((128, 128)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5], std=[0.5])
])

dataset = DogCatDataset(".\\Cat_Dog\\training_set\\training_set", transform=transform)

# 이미지 경로와 라벨 리스트 추출
indices = list(range(len(dataset)))
labels = dataset.labels  # 각 이미지의 라벨 리스트 (0: Dog, 1: Cat)

# Stratified Train/Validation Split (80% Train, 20% Validation)
train_indices, val_indices = train_test_split(indices, test_size=0.2, stratify=labels, random_state=42)

# Subset을 이용해 Train / Validation Dataset 생성
train_dataset = Subset(dataset, train_indices)
val_dataset = Subset(dataset, val_indices)

train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False)

# 3. 모델 정의 (Pretrained ResNet18 사용)
class DogCatClassifier(nn.Module):
    def __init__(self):
        super(DogCatClassifier, self).__init__()
        self.model = efficientnet_b0(pretrained=True)
        self.model.fc = nn.Linear(512, 2)  # Output layer 수정 (2 classes)

    def forward(self, x):
        return self.model(x)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = DogCatClassifier().to(device)

# 4. 손실 함수 및 옵티마이저 설정
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 5. 학습 및 검증 루프
num_epochs = 10
for epoch in range(num_epochs):
    model.train()
    total_train_loss = 0.0
    correct_train, total_train = 0, 0

    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)

        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        total_train_loss += loss.item()
        _, predicted = torch.max(outputs, 1)
        total_train += labels.size(0)
        correct_train += (predicted == labels).sum().item()

    # 검증 단계 (Validation)
    model.eval()
    total_val_loss = 0.0
    correct_val, total_val = 0, 0
    with torch.no_grad():
        for val_images, val_labels in val_loader:
            val_images, val_labels = val_images.to(device), val_labels.to(device)
            val_outputs = model(val_images)
            val_loss = criterion(val_outputs, val_labels)
            total_val_loss += val_loss.item()

            _, val_predicted = torch.max(val_outputs, 1)
            total_val += val_labels.size(0)
            correct_val += (val_predicted == val_labels).sum().item()

    train_loss = total_train_loss / len(train_loader)
    train_acc = 100 * correct_train / total_train
    val_loss = total_val_loss / len(val_loader)
    val_acc = 100 * correct_val / total_val

    print(f"Epoch [{epoch+1}/{num_epochs}], "
          f"Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%, "
          f"Validation Loss: {val_loss:.4f}, Validation Acc: {val_acc:.2f}%")

print("Training Completed!")

 

 

 

3.2.2. Dataset 정의

앞서 몇 번 강조하였듯이, Dataset은 말씀드린 3개의 함수(__init__() , __getitem__() , __len__())를 정의하는 부분이 가장 중요합니다.

하나씩 살펴보겠습니다.

1) __init__()

    def __init__(self, image_dir, transform=None):
        self.image_dir = image_dir+"\\**\\*.jpg"
        self.image_filenames = glob.glob(self.image_dir, recursive=True)
        self.transform = transform

        # 클래스 라벨 할당 (Dog: 0, Cat: 1)
        self.labels = [0 if "dog" in filename else 1 for filename in self.image_filenames]

Dataset의 Instance를 만들때, Train Data의 Path(image_dir)를 전달합니다.

self.image_filenames = glob.glob(self.image_dir, recursive=True)

해당 Path의 전체 Folder를 Scan하면서 Image Filename을 취득합니다.

self.labels = [0 if "dog" in filename else 1 for filename in self.image_filenames]

Target값을 생성하기 위해서 Image Folder의 이름을 이용합니다.

Folder Name에 'Dog'가 들어가면 0, 'Cat'이 들어가면 1로 Target을 저장합니다.

그 값은 Dataset 내부 변수인 self.labels에 List로 저장됩니다.

나중에 Filename과 labels값으로 Train Data를 생성하는 Code를 __getitem__()에 구현합니다.

2) __getitem__()

    def __getitem__(self, index):
        img_path = self.image_filenames[index]
        image = Image.open(img_path).convert("RGB")        
        label = self.labels[index]  # Dog(0), Cat(1)
        
        if self.transform:
            image = self.transform(image)
        
        return image, label

 

__getitem__()에서는 Parameter로 들어오는 index값에 해당하는 Image를 Train할 수 있는 Tensor형태로 변환하고, 해당 Image가 Dog인지

Cat인지를 Target값으로 Return해 주어야 합니다.

여기에 보통 transform이라는 과정을 넣는 것이 일반적인데, 이 transform의 역할은 Tensor로 변환하는 기본적인 역할 이외에도 Data Augmentation 기능도 여기에 추가합니다.

이번 예제에 적용한 transform은 아래와 같이 간단하게 적용했습니다.

transform = transforms.Compose([
    transforms.Resize((128, 128)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5], std=[0.5])
])

3) __len__()

    def __len__(self):
        return len(self.image_filenames)

__len__()에는 전체 Data 수를 Return하므로, Image Filename의 전체 수를 Return하도록 합니다.

Dataset 객체는 아래와 같이 생성하도록 하겠습니다.

Train Data가 있는 Path와 적용시킬 transform객체를 전달합니다.

dataset = DogCatDataset(".\\Cat_Dog\\training_set\\training_set", transform=transform)

4) Train / Validation Dataset 분리

일반적으로 Model 훈련시에 Train Data 이외에 Model의 성능을 검증할 때 사용하는 Validation Data를 별도로 만듭니다.

전체 Data의 20%를 Validation Data로 할당하고, 분리시에 Label의 비율이 일정하도록 하기 위해서 Sci-Kit Learn의 train_test_split()를 사용했습니다

.

랜덤 분할(random_split())을 사용하면 클래스 불균형 문제가 발생할 수 있기 때문에, 각 클래스의 비율을 유지하면서 Train과 Validation을 나누기 위해 Stratified Split을 사용했습니다. 분리된 Index로 Subset()으로 각각에 맞게 별도의 Train / Validation Dataset으로 생성합니다.

# 이미지 경로와 라벨 리스트 추출
indices = list(range(len(dataset)))
labels = dataset.labels  # 각 이미지의 라벨 리스트 (0: Dog, 1: Cat)

# Stratified Train/Validation Split (80% Train, 20% Validation)
train_indices, val_indices = train_test_split(indices, test_size=0.2, stratify=labels, random_state=42)

# Subset을 이용해 Train / Validation Dataset 생성
train_dataset = Subset(dataset, train_indices)
val_dataset = Subset(dataset, val_indices)

3.2.3. DataLoader 정의

DataLoader는 Simple하게 아래와 같이 생성하면 됩니다.

train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False)

3.2.4. Train 결과

이번 Post는 Dataset & DataLoader의 사용법을 주로 다루고 있기 때문에, Train Code의 나머지 부분은 별도의 Post에서 다룰 수 있도록 하겠습니다.

보시다시피, Transfer Learning을 사용하면 아래와 같이 성능이 매우 훌륭하다는 것을 알 수 있습니다.

몇 Epoch지나지 않아서 Model의 성능이 굉장히 좋아진다는 것을 알 수 있습니다.

결과
Epoch [1/10], Train Loss: 2.5207, Train Acc: 63.35%, Validation Loss: 0.3941, Validation Acc: 93.63%
Epoch [2/10], Train Loss: 0.1215, Train Acc: 96.00%, Validation Loss: 0.1931, Validation Acc: 94.57%
Epoch [3/10], Train Loss: 0.0433, Train Acc: 98.24%, Validation Loss: 0.1357, Validation Acc: 97.00%
Epoch [4/10], Train Loss: 0.0183, Train Acc: 99.31%, Validation Loss: 0.0979, Validation Acc: 97.50%
Epoch [5/10], Train Loss: 0.0063, Train Acc: 99.77%, Validation Loss: 0.0886, Validation Acc: 97.88%
Epoch [6/10], Train Loss: 0.0090, Train Acc: 99.73%, Validation Loss: 0.1337, Validation Acc: 97.31%
Epoch [7/10], Train Loss: 0.0128, Train Acc: 99.73%, Validation Loss: 0.1385, Validation Acc: 97.31%
Epoch [8/10], Train Loss: 0.0040, Train Acc: 99.89%, Validation Loss: 0.1305, Validation Acc: 97.31%
Epoch [9/10], Train Loss: 0.0048, Train Acc: 99.78%, Validation Loss: 0.1243, Validation Acc: 97.56%
Epoch [10/10], Train Loss: 0.0065, Train Acc: 99.86%, Validation Loss: 0.1079, Validation Acc: 97.63%
Training Completed!

이번 Post에서는 Dataset & DataLoader에 대해서 알아보았습니다.

도움이 되셨기를 바랍니다.

 

 




 

더욱 다양한 PyTorch 강의를 보시려면 아래 강의 목록을 읽어보시면 도움이 됩니다.

 

1. PyTorch 소개

https://moonlight314.tistory.com/entry/1-PyTorch-%EC%86%8C%EA%B0%9C

 

1. PyTorch 소개

안녕하세요, MoonLight입니다.​Deep Learning Framework의 양대산맥이라고 하면 Tensorflow와 PyTorch일 것입니다.​예전에는 다양한 Framework이 많이 있었지만, 이제는 거의 이 2개가 대부분을 차지한다고 할

moonlight314.tistory.com


2. PyTorch의 주요 Module 소개

https://moonlight314.tistory.com/entry/2-PyTorch%EC%9D%98-%EC%A3%BC%EC%9A%94-Module-%EC%86%8C%EA%B0%9C

 

2. PyTorch의 주요 Module 소개

안녕하세요, MoonLight입니다.​이번 Post에서는 PyTorch를 구성하는 다양한 Module에 대해서 소개해 드리고자 합니다.​​Model을 설계하고 Train 시키는데 매우 다양한 기능이 필요한 것은 어찌보면 당

moonlight314.tistory.com


3. Tensor

https://moonlight314.tistory.com/entry/3-Tensor

 

3. Tensor

안녕하세요, MoonLight입니다.​이번 Post에서는 Deep Learning에서 Data를 표현하기 위한 자료구조인 Tensor에 대해서 알아보도록 하겠습니다.​​1. Tensor​1.1 Tensor의 개념Tensor는 겉으로 보기에 숫자로

moonlight314.tistory.com


4. Basic Train Loop

https://moonlight314.tistory.com/entry/4-Basic-Train-Loop

 

4. Basic Train Loop

안녕하세요, MoonLight입니다.​이번 글에서는 PyTorch를 이용한 기본적인 Train Loop를 분석하고, 각 구성 요소가 하는 역할을 상세히 설명합니다. ​이를 통해 신경망 모델을 학습하는 과정에서 필요

moonlight314.tistory.com


5. Dataset & DataLoader

https://moonlight314.tistory.com/entry/5-Dataset-DataLoader

 

5. Dataset & DataLoader

안녕하세요, MoonLigt입니다.​이번 Post에서는 Train Data를 효율적으로 가공하고 Model에 공급(?)해 주는 역할을 하는 Dataset & DataLoader Module에 대해서 알아보도록 하겠습니다.​​​​1. Dataset & DataLoader

moonlight314.tistory.com


6. 신경망 구성 - Container Class

https://moonlight314.tistory.com/entry/6-%EC%8B%A0%EA%B2%BD%EB%A7%9D-%EA%B5%AC%EC%84%B1-Container-Class

 

6. 신경망 구성 - Container Class

안녕하세요, MoonLight입니다.​이번 장에서는 신경망을 구성하는 기본 개념과, PyTorch에서 제공하는 다양한 Container Class를 활용하여 신경망을 구축하는 방법에 대해 알아보겠습니다.​​​1. Model

moonlight314.tistory.com


7. Loss Function( 손실 함수 )

https://moonlight314.tistory.com/entry/7-Loss-Function-%EC%86%90%EC%8B%A4-%ED%95%A8%EC%88%98

 

7. Loss Function( 손실 함수 )

안녕하세요, MoonLight입니다.​이번 Post에서는 모델이 학습을 잘하고 있는지 정량적으로 표현할 수 있게 해주는 손실함수(Loss Function)에 대해서 알아보도록 하겠습니다.​​1. Loss Function​1.1. Loss F

moonlight314.tistory.com


8. Optimizers

https://moonlight314.tistory.com/entry/8-Optimizers

 

8. Optimizers

안녕하세요, MoonLight입니다.​이번 장에서는 딥러닝 모델의 Train을 하는데 있어서 중요한 요소중의 하나인, Optimizer에 대해서 알아보도록 하겠습니다.​​​​1. Optimization in Deep Learning1.1. Optimizati

moonlight314.tistory.com


9. Learning Rate Schedulers

https://moonlight314.tistory.com/entry/9-Learning-Rate-Schedulers

 

9. Learning Rate Schedulers

안녕하세요, MoonLight입니다.​이번 Post에서는 Learning Rate를 효율적으로 변경하여 학습이 잘 이루어지도록 도와주는 Learning Rate Scheduler에 대해서 알아보도록 하겠습니다.​​​​​​1. Learning Rate1

moonlight314.tistory.com


10. Early Stopping

https://moonlight314.tistory.com/entry/10-Early-Stopping

 

10. Early Stopping

안녕하세요, MoonLight입니다.​이번 Post에서는 모델의 학습을 적절한 시점에 마무리 할 수 있도록 해주는 Early Stopping이라는 개념과 구현에 대해서 알아보도록 하겠습니다.​​​1. Early Stopping1.1. E

moonlight314.tistory.com

 

 

728x90
반응형

'PyTorch' 카테고리의 다른 글

7. Loss Function( 손실 함수 )  (0) 2025.03.03
6. 신경망 구성 - Container Class  (0) 2025.03.03
4. Basic Train Loop  (0) 2025.03.03
3. Tensor  (0) 2025.03.03
1. PyTorch 소개  (0) 2025.03.03