GAN — 생성자와 판별자 (GANs — Generator vs Discriminator)
Goodfellow가 2014년에 보여준 묘수는 밀도(density)를 아예 건너뛰는 것이었습니다. 두 개의 신경망(network)을 둡니다. 한쪽은 가짜(fake)를 만들고, 다른 한쪽은 그것을 잡아냅니다. 가짜가 진짜(real)와 구분되지 않을 때까지 둘은 끊임없이 싸웁니다. 잘 작동할 것 같지 않은 방식이고, 실제로도 자주 실패합니다. 그러나 잘 작동할 때의 결과물은 좁은 도메인(narrow domain)에서 지금까지 문헌에 보고된 어떤 표본보다도 선명합니다.
유형: Build
언어: Python
선수 지식: Phase 3 · 02 (Backprop), Phase 3 · 08 (Optimizers), Phase 8 · 02 (Autoencoder와 VAE)
예상 시간: 약 75분
문제
변분 오토인코더(VAE)는 흐릿한(blurry) 표본을 만들기 쉽습니다. MSE 디코더(decoder) 손실이 여러 그럴듯한 숫자(plausible digit)의 평균(mean) 이미지에 대해 베이즈 최적(Bayes-optimal)이기 때문이며, 여러 그럴듯한 숫자들의 평균은 결국 흐릿한 숫자일 수밖에 없습니다. 우리가 원하는 것은 특정 정답 이미지와의 픽셀 단위 근접도(pixel-wise proximity)가 아니라 그럴듯함(plausibility) 자체에 보상을 주는 손실 함수입니다. 그런데 그럴듯함에는 닫힌 형태(closed form)의 수식이 존재하지 않으므로, 직접 학습으로 얻어내야 합니다.
Goodfellow의 아이디어는 다음과 같습니다. 진짜 이미지와 가짜 이미지를 구분하는 분류기(classifier) D(x)를 학습하고, 생성자(generator) G(z)는 그 D를 속이도록 학습합니다. G가 받는 손실 신호(loss signal)는 "현재 D가 무엇을 진짜처럼 본다고 판단하는가"라는 기준 그 자체입니다. 이 신호는 G가 개선될수록 함께 바뀌므로 G는 움직이는 표적을 쫓는 셈입니다. 두 신경망이 모두 수렴하면 G는 log p(x)를 한 번도 직접 적지 않고도 데이터 분포(data distribution)를 학습한 것이 됩니다.
이것이 적대적 학습(Adversarial Training)입니다. 수식으로는 미니맥스 게임(Minimax Game)으로 표현됩니다.
2026년 기준으로 GAN은 더 이상 최첨단(SOTA) 범용 생성기는 아닙니다. 그 자리는 확산 모델(Diffusion)과 흐름 매칭(Flow Matching)이 가져갔습니다. 그러나 StyleGAN 2/3은 배포된 얼굴 생성 모델 가운데 여전히 가장 선명한 축에 속하고, GAN의 판별자(discriminator)는 확산 학습에서 지각 손실(Perceptual Loss)로 사용되며, SDXL-Turbo, SD3-Turbo, LCM 같은 빠른 1-스텝 증류(distillation)에도 적대적 학습이 핵심으로 쓰입니다.
사전 테스트
2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요
1.원래 GAN 공식에서 생성자(generator)가 미니맥스 손실 log(1 - D(G(z))) 대신 비포화 손실(non-saturating loss) -log D(G(z))를 사용하는 이유는 무엇인가요?
2.완벽하게 학습된 GAN의 균형점(equilibrium) 조건은 무엇인가요?
0/2 답변 완료
개념
생성자(Generator) G(z). 노이즈 벡터(noise vector) z ~ N(0, I)를 표본 x̂로 변환합니다. 완전 연결층(dense layer)이나 전치 합성곱(transposed convolution)으로 구성한 디코더 형태의 신경망입니다.
판별자(Discriminator) D(x). 표본을 스칼라 확률 또는 점수로 사상합니다. 진짜는 1에 가깝게, 가짜는 0에 가깝게 출력합니다.
손실(Loss). 두 가지 갱신을 번갈아 수행합니다.
D 학습:loss_D = -[ log D(x) + log(1 - D(G(z))) ]. 진짜=1, 가짜=0으로 두는 이진 교차 엔트로피(Binary Cross-Entropy; BCE)입니다.
G 학습:loss_G = -log D(G(z)). Goodfellow가 채택한 비포화 형태(non-saturating form)입니다. 원래의 log(1 - D(G(z)))는 D가 확신할 때 포화되어 기울기(gradient)를 사실상 0으로 만듭니다.
학습 루프(Training loop).D 한 스텝, G 한 스텝씩 번갈아 학습하고, 이를 반복합니다.
왜 작동하는가.G가 실제 데이터 분포 p_data와 완전히 같아지면 D는 무작위 추측보다 잘할 수 없게 되어 모든 곳에서 0.5를 출력합니다. 이 시점에서 G는 더 이상 기울기를 받지 않습니다. 이것이 균형점(equilibrium)입니다.
왜 깨지는가. 모드 붕괴(mode collapse), 기울기 소실(vanishing gradient), 학습 불안정(training instability) 때문입니다. G가 D가 잘 잡아내지 못하는 모드(mode) 하나만 발견하고 그것만 계속 찍어내거나, D가 너무 빨리 학습되어 log D가 포화되거나, 학습률(learning rate)과 배치 크기(batch size) 같은 세부 설정이 학습을 흔들기 시작합니다.
GAN을 작동시키게 만든 변형들
연도
혁신
해결한 문제
2015
DCGAN
합성곱/전치 합성곱(Conv/deconv), 배치 정규화(Batch Norm), LeakyReLU를 사용한 최초의 안정적 구조.
매핑 신경망(Mapping Network)과 적응적 인스턴스 정규화(Adaptive Instance Norm; AdaIN). 고정 도메인 사실주의(photorealism)의 대표.
2021
StyleGAN3
에일리어스 없음(alias-free), 변환 등변성(translation-equivariant). 2026년에도 얼굴 생성의 표준.
2022
StyleGAN-XL
조건부(conditional), 클래스 인식, 더 큰 규모.
2024
R3GAN
더 강한 정규화로 1024² 해상도에서 트릭 없이 동작.
직접 만들기
code/main.py는 두 가우시안(Gaussian)이 섞인 1차원 데이터에서 작은 규모의 GAN을 학습합니다. 생성자와 판별자는 각각 은닉층이 한 개인 다층 퍼셉트론(MLP)입니다. 순전파(forward), 역전파(backward), 미니맥스 학습 루프를 직접 손으로 구현합니다. 목표는 모드 붕괴와 기울기 소실이라는 두 가지 대표적 실패 모드(failure mode)를 실제로 눈으로 확인하는 것입니다.
Step 1: 비포화 손실
원래의 Goodfellow 손실인 log(1 - D(G(z)))는 D가 G의 가짜를 가짜라고 높은 확신으로 분류하는 순간 0에 가까워집니다. 그 지점에서 G의 기울기는 사실상 0이고, G는 더 이상 개선되지 못합니다. 비포화 형태(non-saturating form)인 -log D(G(z))는 정반대 점근선을 가집니다. D가 확신할수록 값이 커지므로 G에게 강한 신호를 전달합니다.
defg_loss(d_fake):
# log D(G(z))를 최대화하는 것은 -log D(G(z))를 최소화하는 것과 같다.return -sum(math.log(max(p, 1e-8)) for p in d_fake) / len(d_fake)
Step 2: 생성자 한 스텝마다 판별자 한 스텝
for step inrange(steps):
# D를 학습한다.
real_batch = sample_real(batch_size)
fake_batch = [G(z) for z in sample_noise(batch_size)]
update_D(real_batch, fake_batch)
# G를 학습한다.
fake_batch = [G(z) for z in sample_noise(batch_size)] # 새로 만든 가짜
update_G(fake_batch)
G를 학습할 때는 새로 뽑은 가짜를 사용해야 합니다. 그렇지 않으면 기울기가 낡은(stale) 값이 됩니다.
Step 3: 모드 붕괴 관찰
if step % 200 == 0:
samples = [G(z) for z in sample_noise(500)]
mode_a = sum(1for s in samples if s < 0)
mode_b = 500 - mode_a
ifmin(mode_a, mode_b) < 50:
print(" [!] 모드 붕괴: 한쪽 모드가 거의 생성되지 않음")
대표적인 증상은 실제 데이터의 두 모드 중 한쪽이 더 이상 생성되지 않는 현상입니다. 판별자가 그 모드를 가짜로 본 적이 없기 때문에 더 이상 교정 신호를 보내지 못합니다.
함정과 주의점 (Pitfalls)
판별자가 너무 강함.D의 학습률을 2~5배 낮추거나 입력에 인스턴스/층 단위 잡음(instance/layer noise)을 추가합니다. D의 정확도가 95%를 넘으면 G는 사실상 죽은 상태입니다.
GAN은 선명하지만 좁습니다. 도메인이 일반 사진, 자유 텍스트 프롬프트, 동영상처럼 넓어지는 순간 확산으로 전환하는 것이 합리적입니다. 적대적 학습이라는 트릭은 단독 생성기로서가 아니라 지각 손실과 증류 같은 구성 요소로 살아남았습니다.
산출물 만들기
outputs/skill-gan-debugger.md를 저장합니다. 이 skill은 실패한 GAN 학습(손실 곡선, 표본 격자, 데이터셋 크기)을 입력으로 받아 가능성 높은 원인을 순위로 정리하고, 한 줄 수정안과 재실행 절차(rerun protocol)를 출력합니다.
연습문제
쉬움. 기본 설정 그대로 code/main.py를 실행합니다. 그런 다음 D_LR = 5 * G_LR로 바꾸어 다시 실행합니다. G의 손실이 상수 값으로 무너지는 데까지 걸리는 속도를 관찰합니다.
중간. Goodfellow의 BCE 손실을 WGAN 손실로 교체합니다. 즉 loss_D = E[D(fake)] - E[D(real)], loss_G = -E[D(fake)]로 바꾸고, D의 가중치를 [-0.01, 0.01] 구간으로 클리핑(clip)합니다. 학습이 더 안정적인지 확인하고 실제 시간(wall-clock) 기준 수렴 속도를 비교합니다.
어려움. 1차원 예제를 2차원 데이터로 확장합니다. 원 둘레에 배치된 8개의 가우시안 혼합으로 구성하고, 1k·5k·10k 스텝에서 생성자가 8개 모드 가운데 몇 개를 잡아내는지 추적합니다. 미니배치 판별(minibatch discrimination)을 구현하고 다시 측정해 비교합니다.
프로덕션 노트: 단일 추론(one-shot inference)이 GAN의 오래 남은 강점이다
GAN은 개방 도메인 생성에서 표본 품질로는 더 이상 이기지 못하지만, 추론 비용(inference cost) 측면에서는 여전히 강력합니다. 프로덕션 추론(production inference) 문헌의 용어로 표현하면 GAN의 특징은 다음과 같습니다.
사전 채움(prefill)과 디코드(decode) 단계가 없음. 단 한 번의 G(z) 순전파만 수행합니다. 첫 토큰 지연(TTFT)은 사실상 전체 지연(total latency)과 같습니다.
KV 캐시(KV-cache) 부담이 없음. 유일한 상태는 가중치뿐입니다. 배치 크기는 캐시가 아니라 활성값 메모리(activation memory)로만 제한됩니다.
연속 배치(continuous batching)가 매우 단순. 모든 요청이 동일한 고정 FLOPs를 소비하므로, 서버의 목표 점유율(target occupancy)에 맞춘 정적 배치(static batch)면 보통 충분합니다. 비행 중 스케줄러(in-flight scheduler)가 필요 없습니다.
이것이 GAN 증류(SDXL-Turbo, SD3-Turbo, ADD, LCM)가 2026년 빠른 텍스트-이미지 변환의 지배적 기법인 이유입니다. 2050 스텝짜리 확산 파이프라인을 14회의 GAN 양식 순전파로 압축하면서도 확산 베이스의 분포는 유지합니다. 적대적 손실은 느린 생성기를 빠른 생성기로 바꾸는 학습 단계의 손잡이(training-time knob)로 살아남았습니다.