이미지 데이터와 GPU 메모리

1. 이미지 데이터 소개

1.1 그레이스케일 이미지

여기서부터 이미지 데이터 관련 내용으로 들어갑니다. 컴퓨터 비전 관련 기본 지식이 있다고 가정하지만, 몇 가지 핵심 개념은 다시 짚고 넘어가겠습니다.

이전에 MNIST라는 고전적인 손글씨 데이터셋을 소개했습니다. 이미지 데이터는 정형 데이터(표 형식)와 달리 각 샘플의 형상이 (특성 수,)가 아니라 (너비, 높이, 채널 수)라는 점이 특징입니다.

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
from torchvision import datasets, transforms
import matplotlib.pyplot as plt

# 랜덤 시드 설정으로 결과 재현 가능하게 함
torch.manual_seed(42)

# 데이터 전처리 파이프라인 구성
def make_mnist_transform():
    return transforms.Compose([
        transforms.ToTensor(),  # 텐서로 변환하고 [0, 1]로 정규화
        transforms.Normalize((0.1307,), (0.3081,))  # MNIST 평균과 표준편차
    ])

mnist_transform = make_mnist_transform()

# MNIST 데이터셋 로드 (없으면 자동 다운로드)
train_dataset = datasets.MNIST(
    root='./data',
    train=True,
    download=True,
    transform=mnist_transform
)

test_dataset = datasets.MNIST(
    root='./data',
    train=False,
    download=True,
    transform=mnist_transform
)
# 무작위로 이미지 하나 선택 (반복 실행 시 매번 달라짐)
sample_index = torch.randint(0, len(train_dataset), size=(1,)).item()
image, label = train_dataset[sample_index]

# 역정규화 함수
def denormalize(tensor, mean=0.1307, std=0.3081):
    return tensor * std + mean

# 그레이스케일 이미지 시각화
def show_gray_image(tensor):
    restored = denormalize(tensor)
    np_img = restored.numpy()
    plt.imshow(np_img[0], cmap='gray')
    plt.show()

print(f"Label: {label}")
show_gray_image(image)
Label: 7

위 코드는 이미지 데이터 전처리를 보여줍니다. 이번이 이미지 데이터를 처음 다루는 것이므로, 기존 정형 데이터와 어떤 차이가 있는지 살펴보겠습니다.

정형 데이터(예: 테이블)의 형상은 일반적으로 (샘플 수, 특성 수)입니다. 예를 들어 (1000, 5)는 샘플 1000개, 각 샘플의 특성 5개를 의미합니다. 이미지 데이터는 공간 정보(높이, 너비, 채널)를 유지해야 하므로 단순한 1차원 벡터로 표현할 수 없습니다. 색상 정보는 보통 입력 데이터의 채널이 담당하며, 각 색은 RGB 삼원색으로 표현할 수 있으므로 일반적인 입력 데이터의 채널 수는 3입니다.

차원 인덱스 의미 값 설명
0 채널 수(Channels) 1은 그레이스케일 이미지(단일 색상 채널, 흑백 사진 등)임을 나타냅니다.
RGB 같은 컬러 이미지라면 채널 수는 3입니다.
1 높이(Height) 28은 이미지의 세로 픽셀 수가 28픽셀임을 나타냅니다.
2 너비(Width) 28은 이미지의 가로 픽셀 수가 28픽셀임을 나타냅니다.

MNIST 데이터셋은 손글씨 숫자 그레이스케일 이미지이고, 각 픽셀 값은 0~255(흑백 정도) 범위를 가지므로 채널 수가 1입니다. 이미지 크기는 28×28 픽셀로 통일되어 있습니다.

# 이미지 형상 출력
image.shape
torch.Size([1, 28, 28])

1.2 컬러 이미지

PyTorch에서 이미지 데이터의 형상은 일반적으로 (채널 수, 높이, 너비) 형식(Channel First)을 따릅니다. 이는 (높이, 너비, 채널 수)(Channel Last, NumPy 배열 등)와 다릅니다. — 순서 관계에 주의하세요.

주의점:

  1. matplotlib으로 그릴 때는 순서를 변환해야 합니다. 이는 이후에 소개합니다.
  2. 모델 입력에는 보통 배치 차원(Batch Size)이 필요하므로 형상이 (배치 크기, 채널 수, 높이, 너비)가 됩니다. 예를 들어 MNIST 이미지 10장을 배치로 입력하면 형상은 (10, 1, 28, 28)입니다.

다음은 CIFAR-10 데이터셋으로 컬러 이미지를 로드하고 채널 순서를 확인하는 예입니다.

import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np

# 랜덤 시드 설정
torch.manual_seed(42)

# CIFAR-10 전처리 정의
cifar_transform = transforms.Compose([
    transforms.ToTensor(),  # 텐서 변환 및 [0, 1] 정규화
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 채널별 표준화
])

# CIFAR-10 학습 데이터 로드
cifar_train = torchvision.datasets.CIFAR10(
    root='./data',
    train=True,
    download=True,
    transform=cifar_transform
)

# CIFAR-10 테스트 데이터 로드
cifar_test = torchvision.datasets.CIFAR10(
    root='./data',
    train=False,
    download=True,
    transform=cifar_transform
)

# 배치 차원 확인
batch_loader = torch.utils.data.DataLoader(cifar_train, batch_size=10, shuffle=True)
images, labels = next(iter(batch_loader))
print(images.shape)  # torch.Size([10, 3, 32, 32])

# 컬러 이미지 시각화 함수
def show_rgb_image(tensor):
    # (C, H, W) -> (H, W, C)
    image = tensor.permute(1, 2, 0).numpy()
    image = (image * 0.5 + 0.5).clip(0, 1)
    plt.imshow(image)
    plt.show()

show_rgb_image(cifar_train[0][0])

태그: PyTorch torchvision mnist CIFAR-10 이미지 데이터

9월 21일 09:32에 게시됨