GAN 실습 및 생성모델 평가지표 강의 노트

JJang-404·2025년 11월 28일

GAN 실습 및 생성모델 평가지표 강의 노트

학습 목표

  • GAN의 Generator와 Discriminator 구현 방법 이해
  • 노이즈에서 이미지 생성 과정의 수학적 원리 파악
  • 배치 단위 학습의 중요성 이해
  • 생성모델의 성능을 평가하는 주요 지표 학습
  • IS, FID, Precision/Recall 등의 평가지표 이해

1. GAN의 핵심 개념 복습

1.1 GAN의 목표

우리가 맞춰야 하는 것은 라벨이 아니다

  • 일반 분류 문제: 클래스 넘버(0, 1, 2, ...)를 맞추는 것
  • GAN: 실제 이미지의 특징값(픽셀 분포)과 얼마나 비슷한지를 맞추는 것

이미지의 분포 값

  • 실제 이미지는 0~255 범위의 픽셀값을 가짐
  • 학습을 위해 정규화: [0, 1] 또는 [-1, 1] 범위로 변환
  • Generator의 마지막에 nn.Tanh()를 사용하는 이유: 출력값을 [-1, 1] 범위로 제한

1.2 Generator와 Discriminator의 역할

Generator (생성자)

  • 역할: 빈 노이즈에서 이미지 생성
  • 입력: 랜덤 노이즈 벡터 z (예: 100차원)
  • 출력: 이미지 (예: 28×28)
  • 목표: 판별자가 "진짜(1)"라고 판단하도록 속이기

Discriminator (판별자)

  • 역할: 이미지가 진짜인지 가짜인지 판별
  • 입력: 이미지 (실제 또는 생성된)
  • 출력: 확률값 [0, 1] (0=가짜, 1=진짜)
  • 목표: 진짜 이미지는 1로, 가짜 이미지는 0으로 구분

2. Generator 구현 상세

2.1 간단한 Generator 예시

class Generator(nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(3, 5),           # 3차원 노이즈 → 5차원
            nn.LeakyReLU(0.2),
            nn.Linear(5, 2*2),         # 5차원 → 4차원 (2×2 이미지)
            nn.Tanh()                  # 출력값을 [-1, 1] 범위로
        )

    def forward(self, z):
        return self.model(z).view(-1, 1, 2, 2)  # (배치, 채널, 높이, 너비)

2.2 노이즈에서 이미지 생성 과정

예시: 3차원 노이즈 → 2×2 이미지

입력 노이즈:

z = [0.5, -0.3, 0.8]

첫 번째 Linear 레이어 (3 → 5)

가중치와 편향:

W₁ = [[0.0762, -0.3221, -0.2734],
      [0.2199, -0.2722, -0.2088],
      [-0.3877, -0.3328, -0.3437],
      [0.2889, -0.5252,  0.5153],
      [0.2175,  0.1663, -0.0094]]

b₁ = [-0.3234, 0.2513, 0.3487, -0.5297, 0.2759]

계산:

출력₁ = W₁ · z + b₁

각 뉴런의 계산 예시:

뉴런1 = 0.0762×0.5 + (-0.3221)×(-0.3) + (-0.2734)×0.8 + (-0.3234)

이렇게 5개의 값이 생성됩니다.

두 번째 Linear 레이어 (5 → 4)

W₂ = [[-0.4093,  0.2127, -0.1650, -0.0907, -0.2445],
      [-0.3008,  0.2487, -0.3585,  0.3977,  0.3180],
      [ 0.2415, -0.4205, -0.3090,  0.2092,  0.2356],
      [-0.4201,  0.3128,  0.1191, -0.3206, -0.0462]]

b₂ = [0.2013, -0.0937, 0.1788, -0.0041]

5개의 값에 W₂를 곱하고 b₂를 더하면 4개의 값이 생성됩니다.

Reshape

4개의 값을 2×2 행렬로 변환:

[a, b, c, d] → [[a, b],
                [c, d]]

이것이 최종 생성된 이미지입니다!

2.3 MNIST용 실전 Generator

class Generator(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(100, 128),       # 100차원 노이즈 → 128
            nn.ReLU(),
            nn.Linear(128, 784),       # 128 → 784 (28×28)
            nn.Tanh()                  # [-1, 1] 범위로
        )
    
    def forward(self, z):
        out = self.net(z)
        return out.view(-1, 1, 28, 28)  # 이미지 형태로 변환

핵심 포인트

  • 100차원 노이즈를 입력받아 784차원(28×28)으로 확장
  • 가중치(W)와 편향(b)의 학습을 통해 진짜 같은 이미지 생성
  • 초기에는 무의미한 점들만 생성되지만, 경사하강법을 통해 점차 개선

3. Discriminator 구현 상세

3.1 MNIST용 Discriminator

class Discriminator(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Flatten(),              # 1×28×28 → 784
            nn.Linear(784, 128),
            nn.LeakyReLU(0.2),        # 음수 영역에서도 0.2만큼 활성화
            nn.Linear(128, 1),
            nn.Sigmoid()               # [0, 1] 확률값 출력
        )
    
    def forward(self, x):
        return self.net(x)

3.2 LeakyReLU의 의미

일반 ReLU의 문제점

ReLU(x) = max(0, x)
  • 음수 값이 들어오면 0으로 만듦
  • 뉴런이 "죽을" 수 있음 (gradient = 0)

LeakyReLU의 해결

LeakyReLU(x) = max(0.2x, x)
  • 음수 영역에서도 0.2를 곱한 값을 출력
  • 0.2는 하이퍼파라미터 (0.1, 0.3 등도 사용)
  • 음수 영역에서 20%만큼 활성화 유지

왜 LeakyReLU를 사용하나?

  • 판별자가 가짜 이미지에 대해 음수 값을 출력할 때도 학습이 가능
  • 뉴런이 완전히 죽지 않아 더 안정적인 학습

4. GAN 학습 과정

4.1 전체 학습 구조

# 장치 설정
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 모델 초기화
G = Generator().to(device)
D = Discriminator().to(device)

# 손실 함수와 옵티마이저
criterion = nn.BCELoss()  # Binary Cross Entropy
opt_G = torch.optim.Adam(G.parameters(), lr=0.0002)
opt_D = torch.optim.Adam(D.parameters(), lr=0.0002)

# 고정된 노이즈 (평가용)
fixed_noise = torch.randn(64, 100, device=device)

4.2 학습 루프의 두 단계

핵심: 두 번의 학습 단계만 존재

  1. Discriminator 학습: 진짜는 1로, 가짜는 0으로 판별하도록
  2. Generator 학습: 가짜 이미지를 판별자가 1(진짜)로 판별하도록

4.3 Discriminator 학습 단계

# ----- 1) Discriminator 학습 -----
z = torch.randn(batch, 100, device=device)
fake = G(z)

pred_real = D(real)                    # 진짜 이미지 판별
pred_fake = D(fake.detach())           # 가짜 이미지 판별 (detach!)

# 진짜 이미지를 1로 만들기
loss_D_real = criterion(
    pred_real,
    torch.ones(batch, 1, device=device)
)

# 가짜 이미지를 0으로 만들기
loss_D_fake = criterion(
    pred_fake,
    torch.zeros(batch, 1, device=device)
)

loss_D = loss_D_real + loss_D_fake

opt_D.zero_grad()
loss_D.backward()
opt_D.step()

detach()를 사용하는 이유

  • fake = G(z)로 생성된 이미지는 Generator의 그래프에 연결되어 있음
  • Discriminator만 학습하고 싶은데, 역전파가 Generator까지 전달될 수 있음
  • detach()로 그래프를 끊어서 Discriminator만 업데이트
  • 오토그래드(autograd) 연결을 차단하는 역할

4.4 Generator 학습 단계

# ----- 2) Generator 학습 -----
z = torch.randn(batch, 100, device=device)
fake = G(z)

pred_fake = D(fake)

# Generator는 판별자가 1(진짜)로 판단하길 원함
loss_G = criterion(
    pred_fake,
    torch.ones(batch, 1, device=device)
)

opt_G.zero_grad()
loss_G.backward()
opt_G.step()

핵심 포인트

  • Generator는 판별자를 속이려고 함
  • 가짜 이미지를 생성했지만, 라벨은 1(진짜)로 설정
  • 판별자가 높은 확률을 출력할수록 Generator의 손실이 작아짐

4.5 학습 과정 직관적 이해

예시: 간단한 판별자 학습

real_img = torch.tensor([[1.0, 0.0, 1.0]])     # 진짜
fake_img = torch.tensor([[0.2, 0.7, -0.3]])    # 가짜

D = nn.Linear(3, 1, bias=True)
criterion = nn.BCELoss()
opt = optim.SGD(D.parameters(), lr=0.1)

for step in range(5):
    pred_real = torch.sigmoid(D(real_img))
    pred_fake = torch.sigmoid(D(fake_img))

    real_label = torch.ones((1,1))   # 1
    fake_label = torch.zeros((1,1))  # 0

    loss = criterion(pred_real, real_label) + \
           criterion(pred_fake, fake_label)

    opt.zero_grad()
    loss.backward()
    opt.step()

학습 결과 분석

=== STEP 0 ===
pred_real = 0.5154
pred_fake = 0.4748
loss = 1.3068

=== STEP 4 ===
pred_real = 0.6066
pred_fake = 0.4405
loss = 1.0806
  • pred_real은 점점 1에 가까워짐 (0.5154 → 0.6066)
  • pred_fake는 점점 0에 가까워짐 (0.4748 → 0.4405)
  • loss는 감소 (1.3068 → 1.0806)

결론: 가중치와 편향이 업데이트되면서 판별 능력이 향상됨!


5. 배치 크기의 중요성

5.1 왜 배치 크기를 맞춰야 하나?

잘못된 방법

fixed_noise = torch.randn(1, 100, device=device)  # 1개만 생성

for real, _ in loader:
    real = real.to(device)  # 배치 크기: 64
    batch = real.shape[0]   # 64
    
    # 1개의 노이즈로 64개의 실제 이미지를 비교? → 비효율적

올바른 방법

for real, _ in loader:
    real = real.to(device)
    batch = real.shape[0]  # 64
    
    z = torch.randn(batch, 100, device=device)  # 배치 크기만큼 생성
    fake = G(z)  # 64개의 가짜 이미지 생성

이유

  • 배치의 각 이미지는 독립적으로 비교되어야 함
  • 첫 번째 실제 이미지 ↔ 첫 번째 생성 이미지
  • 두 번째 실제 이미지 ↔ 두 번째 생성 이미지
  • ...
  • 64번째 실제 이미지 ↔ 64번째 생성 이미지

5.2 고정된 노이즈의 용도

fixed_noise = torch.randn(64, 100, device=device)
  • 학습용이 아님!
  • 평가/시각화용: 학습 진행 상황을 확인하기 위해 사용
  • 같은 노이즈로 에포크마다 이미지를 생성하면 변화를 관찰할 수 있음

6. 전체 학습 코드 분석

6.1 완전한 학습 루프

for epoch in range(100):
    generator.train()
    discriminator.train()

    total_d_loss = 0.0
    total_g_loss = 0.0
    total_real_score = 0.0
    total_fake_score = 0.0
    num_batches = 0

    for real_images, _ in dataloader:
        num_batches += 1
        batch_size = real_images.size(0)
        
        # 라벨 준비
        real_labels = torch.ones(batch_size, 1).to(device)
        fake_labels = torch.zeros(batch_size, 1).to(device)

        # ========== Discriminator 학습 ==========
        discriminator.zero_grad()
        
        # 진짜 이미지 판별
        outputs_real = discriminator(real_images.to(device))
        d_loss_real = criterion(outputs_real, real_labels)
        real_score = outputs_real.mean().item()

        # 가짜 이미지 판별
        noise = torch.randn(batch_size, 100, device=device)
        fake_images = generator(noise)
        outputs_fake = discriminator(fake_images.detach())
        d_loss_fake = criterion(outputs_fake, fake_labels)
        fake_score = outputs_fake.mean().item()

        # Discriminator 전체 손실
        d_loss = d_loss_real + d_loss_fake
        d_loss.backward()
        optimizer_D.step()

        # ========== Generator 학습 ==========
        generator.zero_grad()
        
        # 새로운 노이즈로 가짜 이미지 생성
        noise2 = torch.randn(batch_size, 100, device=device)
        fake_images2 = generator(noise2)
        outputs = discriminator(fake_images2)
        
        # Generator는 판별자를 속이려고 함 (라벨을 1로)
        g_loss = criterion(outputs, real_labels)
        g_loss.backward()
        optimizer_G.step()

        total_d_loss += d_loss.item()
        total_g_loss += g_loss.item()
        total_real_score += real_score
        total_fake_score += fake_score

    # 에포크 결과 출력
    avg_d_loss = total_d_loss / num_batches
    avg_g_loss = total_g_loss / num_batches
    avg_real_score = total_real_score / num_batches
    avg_fake_score = total_fake_score / num_batches

    print(f"Epoch [{epoch+1}/100]: "
          f"d_loss={avg_d_loss:.4f}, "
          f"g_loss={avg_g_loss:.4f}, "
          f"D(x)={avg_real_score:.2f}, "
          f"D(G(z))={avg_fake_score:.2f}")

6.2 출력 지표 이해

d_loss (Discriminator Loss)

  • 판별자의 손실값
  • 낮을수록 판별을 잘하고 있다는 의미

g_loss (Generator Loss)

  • 생성자의 손실값
  • 낮을수록 판별자를 잘 속이고 있다는 의미

D(x) (진짜 이미지에 대한 판별자 출력)

  • 실제 이미지에 대해 판별자가 출력한 평균 "진짜일 확률"
  • 1에 가까울수록 좋음

D(G(z)) (가짜 이미지에 대한 판별자 출력)

  • 가짜 이미지에 대해 판별자가 출력한 평균 "진짜일 확률"
  • 판별자 입장: 0에 가까울수록 좋음
  • 생성자 입장: 1에 가까울수록 좋음

7. 생성모델 평가지표

7.1 평가의 필요성

생성 모델의 성능을 평가하는 것은 매우 중요합니다:

  • 생성된 데이터가 얼마나 진짜와 유사한가?
  • 생성된 데이터가 얼마나 다양한가?
  • 실제 데이터 분포와 얼마나 일치하는가?

7.2 주요 평가 요소

1. 생성 품질 (Quality)

  • 생성된 데이터가 얼마나 사실적인가?
  • 원본 데이터와 얼마나 유사한가?

2. 다양성 (Diversity)

  • 모델이 얼마나 다양한 데이터를 생성하는가?
  • 단일 패턴만 반복하지 않는가?

3. 분포 적합성 (Distribution Matching)

  • 생성된 데이터의 분포가 실제 데이터 분포와 일치하는가?

8. Inception Score (IS)

8.1 개념

생성된 이미지를 분류하고, 분류된 클래스의 다양성과 확신도를 측정합니다.

8.2 수식

IS = exp(𝔼ₓ[KL(p(y|x) || p(y))])

여기서:

  • p(y|x): 이미지 x에 대한 예측 확률 분포
  • p(y): 전체 생성 이미지의 클래스 확률 분포
  • KL: Kullback-Leibler Divergence (두 분포 간의 차이)

8.3 해석

높은 IS 값의 의미

  1. 높은 확신도: p(y|x)가 특정 클래스에 집중되어 있음
    • 예: [0.9, 0.05, 0.05] → 첫 번째 클래스일 확률 90%
  2. 높은 다양성: p(y)가 골고루 분포되어 있음
    • 예: [0.33, 0.33, 0.34] → 모든 클래스가 비슷한 비율로 생성

예시

나쁜 경우:

이미지1: [0.5, 0.3, 0.2]  # 확신도 낮음
이미지2: [0.5, 0.3, 0.2]  # 확신도 낮음
이미지3: [0.5, 0.3, 0.2]  # 확신도 낮음
→ IS 낮음

좋은 경우:

이미지1: [0.9, 0.05, 0.05]  # 클래스 0, 확신도 높음
이미지2: [0.05, 0.9, 0.05]  # 클래스 1, 확신도 높음
이미지3: [0.05, 0.05, 0.9]  # 클래스 2, 확신도 높음
→ IS 높음 (확신도 높고 다양함)

8.4 장단점

장점

  • 생성된 이미지의 품질과 다양성을 동시에 측정
  • 계산이 비교적 간단

단점

  • Inception v3 모델에 의존적
  • 실제 데이터와의 유사성은 직접 측정하지 못함

9. Fréchet Inception Distance (FID)

9.1 개념

생성된 데이터 분포와 실제 데이터 분포 간의 유사성을 측정합니다.

두 분포의 평균과 공분산을 비교합니다.

9.2 수식

FID = ||μᵣ - μ_g||² + Tr(Σᵣ + Σ_g - 2(ΣᵣΣ_g)^(1/2))

여기서:

  • μᵣ, Σᵣ: 실제 데이터의 평균과 공분산
  • μ_g, Σ_g: 생성된 데이터의 평균과 공분산
  • Tr: 행렬의 대각합 (Trace)
  • ||||²: 유클리드 거리의 제곱

9.3 상세 설명

첫 번째 항: ||μᵣ - μ_g||²

  • 두 분포의 평균 벡터 간 거리
  • 생성된 이미지의 평균적 특성이 실제와 얼마나 다른지

두 번째 항: Tr(Σᵣ + Σ_g - 2(ΣᵣΣ_g)^(1/2))

  • 두 분포의 공분산 행렬 간 차이
  • 생성된 이미지의 변동성이 실제와 얼마나 다른지

9.4 해석

낮은 FID 값 = 좋은 성능

  • 생성된 데이터가 실제 데이터와 유사함
  • 평균과 분산이 비슷함

예시

실제 데이터: 평균 = [10, 20], 분산 = [5, 5]
생성 데이터: 평균 = [10, 20], 분산 = [5, 5]
→ FID ≈ 0 (완벽하게 일치)

실제 데이터: 평균 = [10, 20], 분산 = [5, 5]
생성 데이터: 평균 = [15, 25], 분산 = [10, 10]
→ FID > 0 (차이 발생)

9.5 장단점

장점

  • 실제 데이터와 생성 데이터 간의 차이를 잘 반영
  • IS보다 더 신뢰할 수 있는 지표

단점

  • 분포가 정규분포를 따르지 않으면 왜곡 가능
  • 계산 비용이 비교적 높음

10. Precision and Recall

10.1 개념

생성된 데이터의 품질(Precision)과 다양성(Recall)을 분리하여 측정합니다.

10.2 정의

Precision (정밀도)

  • 생성된 데이터가 실제 데이터 분포 안에 얼마나 포함되는가?
  • 높을수록: 생성된 이미지가 진짜 같음
  • 낮을수록: 이상한 이미지가 많이 생성됨

Recall (재현율)

  • 실제 데이터 분포가 생성된 데이터로 얼마나 잘 커버되는가?
  • 높을수록: 다양한 종류의 이미지를 생성
  • 낮을수록: 특정 종류만 반복 생성 (Mode Collapse)

10.3 시각적 이해

[실제 데이터 분포]
    ┌─────────────┐
    │   ·  ·  ·   │
    │  ·    ·  ·  │
    │ ·   ·    ·  │
    └─────────────┘

[경우 1: High Precision, Low Recall]
    ┌─────────────┐
    │   ○  ○      │  ← 생성된 데이터가 실제 분포 안에만 있음 (Precision 높음)
    │             │     하지만 분포의 일부만 커버 (Recall 낮음)
    │             │
    └─────────────┘

[경우 2: Low Precision, High Recall]
    ┌─────────────┐
    │  ○  ○   ○   │  ← 실제 분포를 넓게 커버 (Recall 높음)
 ○  │ ○    ○   ○  │ ○    하지만 분포 밖에도 생성 (Precision 낮음)
    │   ○     ○   │
    └─────────────┘

[경우 3: High Precision, High Recall]
    ┌─────────────┐
    │ ○ ○  ○  ○   │  ← 실제 분포 안에 있으면서 (Precision 높음)
    │ ○  ○  ○  ○  │     분포를 넓게 커버 (Recall 높음)
    │  ○  ○  ○ ○  │
    └─────────────┘

10.4 장단점

장점

  • 품질과 다양성을 별도로 측정 가능
  • Mode Collapse를 명확히 감지

단점

  • 계산 비용이 높음
  • 복잡한 데이터에서 해석이 어려울 수 있음

11. 기타 평가지표

11.1 Perceptual Path Length (PPL)

개념

  • 잠재 공간의 선형성을 측정
  • 모델이 얼마나 자연스럽게 변형 이미지를 생성하는지 평가

예시

  • 잠재 공간에서 z₁에서 z₂로 선형 보간할 때
  • 생성된 이미지들이 부드럽게 변화하는가?

주요 사용 사례

  • StyleGAN과 같은 고급 생성 모델 평가

11.2 Kernel Inception Distance (KID)

개념

  • FID와 유사하지만, 커널 방법 사용
  • 분포가 정규분포를 따르지 않아도 정확히 측정 가능

장점

  • FID보다 작은 데이터셋에서도 안정적
  • 정규분포 가정이 필요 없음

단점

  • 계산 복잡도가 높을 수 있음

12. 평가지표 비교

지표측정 내용장점단점
IS품질 + 다양성간단, 빠름Inception 모델 의존적, 실제 데이터와 비교 안 함
FID분포 유사성실제 데이터와 비교, 신뢰성 높음정규분포 가정, 계산 비용
Precision품질 (진짜 같은 정도)품질만 집중 측정Recall과 함께 봐야 함
Recall다양성 (커버리지)다양성만 집중 측정Precision과 함께 봐야 함
PPL잠재 공간 매끄러움잠재 공간 품질 평가특정 모델에만 적합
KID분포 유사성 (커널 기반)작은 데이터셋에서도 안정적계산 복잡도 높음

13. 실제 평가 전략

13.1 다양한 지표 조합

단일 지표의 한계

  • IS와 FID는 각각의 모델 특성을 충분히 반영하지 못할 수 있음
  • 여러 지표를 조합하여 종합적인 성능 평가 필요

추천 조합

기본: IS + FID
상세: IS + FID + Precision/Recall
고급: IS + FID + Precision/Recall + PPL

13.2 주관적 평가와의 조화

User Study의 중요성

  • 자동화된 지표만으로는 부족
  • 실제 사람이 보기에 좋은지도 중요

평가 방법
1. 100명에게 진짜/가짜 이미지 섞어서 보여주기
2. 진짜라고 판단한 비율 측정
3. 자동 지표와 비교

13.3 응용 분야별 고려사항

의료 영상

  • 정확성이 최우선
  • FID와 Precision 중시

예술/디자인

  • 창의성과 다양성 중요
  • IS와 Recall 중시

데이터 증강

  • 실제 데이터와의 유사성
  • FID와 Precision/Recall 균형

14. 생성모델 학습 최적화

14.1 GAN의 학습 안정화

Batch Normalization

  • 각 레이어의 출력 분포를 정규화
  • 학습 안정성 향상

Spectral Normalization

  • 판별자의 가중치 행렬의 스펙트럼 크기 제한
  • 그라디언트 폭주 방지

Feature Matching

  • 판별자의 중간 특징을 기반으로 생성자 학습
  • 안정성 향상

Gradient Penalty (WGAN-GP)

  • 그라디언트의 크기를 제어 (1에 가깝게 유지)
  • 학습 안정성 강화

14.2 학습률 조정

일반적인 설정

lr_G = 0.0002  # Generator 학습률
lr_D = 0.0002  # Discriminator 학습률

불균형 해결

# Discriminator가 너무 강할 때
lr_G = 0.0002
lr_D = 0.0001  # Discriminator 학습률 낮춤

# Generator가 너무 강할 때
lr_G = 0.0001  # Generator 학습률 낮춤
lr_D = 0.0002

14.3 데이터 증강

transform = transforms.Compose([
    transforms.Resize(28),
    transforms.RandomRotation(5),      # 회전
    transforms.RandomHorizontalFlip(), # 좌우 반전
    transforms.ToTensor(),
    transforms.Normalize([0.5], [0.5])
])

Q&A 정리

Q. "왜 Tanh를 마지막에 사용하나요?"

실제 이미지 데이터를 [-1, 1] 범위로 정규화하기 때문입니다.

transforms.Normalize([0.5], [0.5])

이 변환은 [0, 1] 범위의 데이터를 [-1, 1]로 변환합니다:

x_normalized = (x - 0.5) / 0.5

따라서 Generator의 출력도 같은 범위여야 비교 가능합니다.

Q. "detach()는 정확히 무엇을 하나요?"

Autograd의 연결을 끊습니다.

# detach() 없이
fake = G(z)           # G의 그래프에 연결됨
output = D(fake)      # D의 그래프에도 연결됨
loss.backward()       # G와 D 모두 업데이트됨 (원하지 않음!)

# detach() 사용
fake = G(z)
output = D(fake.detach())  # D의 그래프에만 연결됨
loss.backward()            # D만 업데이트됨 (올바름!)

Q. "배치 크기를 맞추지 않으면 어떻게 되나요?"

기술적으로는 동작하지만 성능이 떨어집니다:

  • 1개의 노이즈로 64개의 실제 이미지 비교 → 비효율적
  • 각 실제 이미지마다 다른 가짜 이미지와 비교해야 학습이 효과적

Q. "GPU 20번 에포크로 돌렸는데 이미지가 잘 안 나오는 이유는?"

GAN은 수렴이 느립니다:

  • 20 에포크: 아직 초기 단계, 노이즈 같은 이미지
  • 100 에포크: 어느 정도 형태 인식 가능
  • 500+ 에포크: 실제 같은 이미지

인내심을 가지고 충분히 학습시켜야 합니다!

Q. "IS가 높으면 무조건 좋은 모델인가요?"

아닙니다. IS는 한계가 있습니다:

  • Inception 모델에 의존적
  • 실제 데이터와의 유사성은 측정 안 함
  • FID와 함께 사용하는 것이 좋음

핵심 정리

  1. GAN은 Generator와 Discriminator가 서로 경쟁하며 학습한다.

  2. Generator는 노이즈에서 시작해 신경망을 통해 이미지를 생성한다.

  3. Discriminator는 진짜 이미지는 1로, 가짜 이미지는 0으로 판별한다.

  4. 배치 크기를 맞춰서 각 이미지를 독립적으로 비교해야 한다.

  5. detach()는 Discriminator 학습 시 Generator의 그래프를 끊기 위해 사용한다.

  6. Inception Score는 품질과 다양성을 동시에 측정한다.

  7. FID는 실제 데이터와 생성 데이터의 분포 차이를 측정한다.

  8. Precision/Recall은 품질과 다양성을 분리하여 측정한다.

  9. 여러 평가지표를 조합하여 사용하는 것이 좋다.

  10. GAN 학습은 불안정하므로 Spectral Normalization, WGAN 등의 기법을 사용한다.


추가 학습 권장 사항

심화 주제

1. 고급 GAN 아키텍처

  • StyleGAN: 스타일 제어 가능
  • ProGAN: 점진적 해상도 증가
  • CycleGAN: 이미지 변환 (말 → 얼룩말)

2. 평가지표 심화

  • FID 계산 실습
  • Precision/Recall 계산 실습
  • 각 지표의 수학적 배경

3. 최적화 기법

  • Wasserstein Loss의 수학적 이해
  • Spectral Normalization의 원리
  • Progressive Growing 구현

4. 실무 응용

  • 고해상도 이미지 생성
  • 조건부 생성 (cGAN)
  • 이미지 편집 및 복원

실습 프로젝트

프로젝트 1: MNIST GAN 완성하기

  • 100 에포크 이상 학습
  • FID 계산해보기
  • 생성 이미지 품질 분석

프로젝트 2: Fashion-MNIST GAN

  • 의류 이미지 생성
  • 다양한 학습률 실험
  • 평가지표 비교

프로젝트 3: 조건부 GAN

  • 특정 숫자만 생성하기
  • 클래스 정보를 입력으로
  • 제어 가능한 생성

프로젝트 4: 고해상도 얼굴 생성

  • CelebA 데이터셋 사용
  • StyleGAN 구현 시도
  • 스타일 믹싱 실험

참고 자료

논문

  • Goodfellow et al. (2014): GAN 원본 논문
  • Salimans et al. (2016): Improved Techniques for Training GANs
  • Heusel et al. (2017): GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium (FID)
  • Karras et al. (2019): A Style-Based Generator Architecture for GANs

온라인 자료

  • PyTorch GAN Tutorial
  • TensorFlow GAN Guide
  • Distill.pub: GAN 시각화

도구 및 라이브러리

  • PyTorch-GAN: 다양한 GAN 구현
  • TensorFlow GAN (TF-GAN)
  • FID 계산 라이브러리: pytorch-fid

학습 팁

  1. 이론과 실습을 병행하세요. 수식만 보면 어렵지만 코드로 보면 이해가 쉽습니다.

  2. 작은 데이터셋부터 시작하세요. MNIST → Fashion-MNIST → CelebA 순서로.

  3. 학습 과정을 시각화하세요. TensorBoard를 사용하면 손실과 이미지를 실시간으로 확인할 수 있습니다.

  4. 여러 평가지표를 계산해보세요. 수치로 보면 모델의 성능을 객관적으로 이해할 수 있습니다.

  5. 인내심을 가지세요. GAN은 학습이 느리고 불안정합니다. 충분한 에포크를 돌려야 합니다.

profile
V I S I O N _ E N G I N E E R

0개의 댓글