딥러닝 파이토치 강좌, GAN 동작 원리

Generative Adversarial Networks (GAN)은 Ian Goodfellow와 그의 동료들이 2014년에 소개한 혁신적인 딥러닝 기법입니다. GAN은 ‘생성자'(Generator)와 ‘판별자'(Discriminator)라는 두 개의 신경망으로 구성됩니다. 이 두 네트워크는 서로 경쟁하며 학습하여 고품질의 데이터를 생성하는 데 목적을 두고 있습니다. 본 강좌에서는 GAN의 동작 원리, 구성 요소, 훈련 과정 및 PyTorch를 사용한 구현 예제를 자세히 알아보겠습니다.

1. GAN의 기본 구조

GAN은 두 개의 신경망, 즉 생성자와 판별자 간의 경쟁 구조로 설정됩니다. 이 구조는 다음과 같이 작동합니다:

  1. 생성자(Generator): 랜덤 노이즈 벡터를 입력으로 받아 가짜 데이터를 생성합니다.
  2. 판별자(Discriminator): 주어진 데이터가 실제 데이터인지 생성자가 만든 가짜 데이터인지 판별합니다.

이 두 네트워크는 동시에 훈련되며, 생성자는 판별자를 속이는 가짜 데이터를 만들기 위해 개선되고, 판별자는 가짜와 실제 데이터를 잘 구분하기 위해 개선됩니다.

2. GAN의 수학적 동작 원리

GAN의 목표는 다음과 같은 비용 함수를 최소화하는 것입니다:


D\*(x) = log(D(x)) + log(1 - D(G(z)))
    

여기서,

  • D(x): 실제 데이터 x에 대한 판별자의 출력입니다. (1에 가까우면 실제 데이터, 0에 가까우면 가짜 데이터)
  • G(z): 생성자가 랜덤 노이즈 z를 통해 생성한 데이터입니다.
  • D(G(z)): 판별자가 생성된 데이터에 대해 반환한 확률입니다.

목표는 판별자가 실제 데이터에 대해 1, 생성된 데이터에 대해 0을 출력하도록 하는 것입니다. 이를 통해 생성자는 점점 더 진짜와 유사한 데이터를 생성하게 됩니다.

3. GAN의 구성 요소

3.1 생성자(Generator)

생성자는 일반적으로 완전 연결(fully connected) 레이어 또는 컨볼루션 레이어로 구성됩니다. 입력으로 랜덤 벡터 z를 받고, 이를 통해 실제 데이터와 유사한 정보를 생성합니다.

3.2 판별자(Discriminator)

판별자는 입력 데이터(실제 또는 생성된)를 받아서 이를 진짜인지 가짜인지 판단합니다. 이 또한 완전 연결 또는 컨볼루션 네트워크로 설계할 수 있습니다.

4. GAN의 훈련 과정

GAN의 훈련은 다음 단계로 이루어집니다:

  1. 실제 데이터를 선택하고, 랜덤 노이즈 벡터 z를 샘플링합니다.
  2. 생성자가 노이즈 z를 입력받아 가짜 데이터를 만듭니다.
  3. 판별자는 실제 데이터와 생성자가 만든 데이터를 평가합니다.
  4. 판별자의 손실을 계산하고, 역전파하여 판별자를 업데이트합니다.
  5. 생성자의 손실을 계산하고, 역전파하여 생성자를 업데이트합니다.

이 과정을 반복하며 두 네트워크 모두 개선합니다.

5. GAN의 PyTorch 구현 예제

다음은 PyTorch를 사용하여 GAN을 구현하는 간단한 예제입니다. 여기서는 MNIST 데이터셋을 사용하여 숫자 이미지를 생성하는 모델을 만들어 보겠습니다.

5.1 라이브러리 설치 및 데이터셋 로딩


import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
    

먼저, 필요한 라이브러리를 임포트하고 MNIST 데이터셋을 로드합니다.


# MNIST 데이터셋 다운로드 및 로드
transform = transforms.Compose([
    transforms.Resize(28),
    transforms.ToTensor(),
])

mnist = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
dataloader = DataLoader(mnist, batch_size=64, shuffle=True)
    

5.2 생성자(Generator) 모델 정의

생성자 모델은 랜덤 노이즈를 입력으로 받아 실제와 유사한 이미지를 생성합니다.


class Generator(nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(100, 128),
            nn.ReLU(),
            nn.Linear(128, 256),
            nn.ReLU(),
            nn.Linear(256, 512),
            nn.ReLU(),
            nn.Linear(512, 28*28),  # MNIST 이미지 크기
            nn.Tanh()  # 픽셀 값 범위를 [-1, 1]로 조정
        )

    def forward(self, z):
        return self.model(z).view(-1, 1, 28, 28)
    

5.3 판별자(Discriminator) 모델 정의

판별자 모델은 입력 이미지를 받아 그것이 실제인지 생성된 것인지 판별합니다.


class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.model = nn.Sequential(
            nn.Flatten(),  # 이미지 형태를 일차원으로 변환
            nn.Linear(28*28, 512),
            nn.LeakyReLU(0.2),
            nn.Linear(512, 256),
            nn.LeakyReLU(0.2),
            nn.Linear(256, 1),
            nn.Sigmoid()  # 출력 확률
        )

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

5.4 손실 함수와 옵티마이저 정의


# 생성자와 판별자 생성
generator = Generator()
discriminator = Discriminator()

# 손실 함수
criterion = nn.BCELoss()

# 옵티마이저
optimizer_g = optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))
optimizer_d = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))
    

5.5 GAN 훈련 단계

이제 GAN을 훈련하는 루프를 정의합니다. 각 에포크마다 판별자와 생성자를 업데이트합니다.


num_epochs = 50

for epoch in range(num_epochs):
    for real_images, _ in dataloader:
        batch_size = real_images.size(0)

        # 진짜 이미지에 대한 레이블
        real_labels = torch.ones(batch_size, 1)
        # 가짜 이미지에 대한 레이블
        fake_labels = torch.zeros(batch_size, 1)

        # 판별자 훈련
        discriminator.zero_grad()
        outputs = discriminator(real_images)
        d_loss_real = criterion(outputs, real_labels)
        d_loss_real.backward()

        # 가짜 데이터 생성
        noise = torch.randn(batch_size, 100)
        fake_images = generator(noise)

        outputs = discriminator(fake_images.detach())
        d_loss_fake = criterion(outputs, fake_labels)
        d_loss_fake.backward()

        optimizer_d.step()

        # 생성자 훈련
        generator.zero_grad()
        outputs = discriminator(fake_images)
        g_loss = criterion(outputs, real_labels)
        g_loss.backward()
        optimizer_g.step()

    print(f'Epoch [{epoch+1}/{num_epochs}], d_loss: {d_loss_real.item() + d_loss_fake.item()}, g_loss: {g_loss.item()}')
    

6. GAN의 활용 분야

GAN은 여러 분야에서 활용될 수 있습니다. 일부 예시는 다음과 같습니다:

  • 이미지 생성 및 변환
  • 비디오 생성
  • 음악 생성
  • 데이터 증강
  • 의료 이미지 분석
  • 스타일 전이

7. 결론

GAN은 딥러닝 분야에서 매우 혁신적인 개념으로, 데이터 생성 및 변환을 위해 널리 사용되고 있습니다. 본 강좌에서는 GAN의 기본 원리와 PyTorch를 사용한 간단한 구현 방법을 살펴보았습니다. GAN은 모델의 복잡성과 훈련 과정에서의 불안정성 때문에 매우 도전적인 기술이지만, 그 잠재력은 무궁무진합니다.

더 나아가 GAN의 다양한 변형 및 고급 기법에 대해 배우며, 실전 프로젝트에 적용해보길 권장합니다.