위조범(생성자)은 진짜 같은 가짜를 만들고, 감별사(판별자)는 가려내요. 반대 목표를 가진 둘의 대결만으로 AI가 '진짜 데이터 만드는 법'을 배웁니다.
가로축은 데이터 값 x(0~10). 파란 막대는 진짜 데이터의 분포, 주황 막대는 위조범이 만든 가짜의 분포예요. 초록 선은 감별사의 판단(오른쪽 0~1 축, 1=진짜다!, 0=가짜다!)입니다. 주황이 파랑 위에 겹치고 초록 선이 그 근처에서 0.5로 평평해지면 — 위조범의 완승이에요.
μ_g와 σ_g는 진짜의 6.5와 0.6에 가까워지고, 가짜가 받는 점수는 0.5(감별사도 반반으로 헷갈림)에 가까워지면 성공이에요.
import torch
import torch.nn as nn
G = nn.Sequential(nn.Linear(64, 128), nn.ReLU(),
nn.Linear(128, 784), nn.Tanh()) # 위조범: 노이즈 → 이미지
D = nn.Sequential(nn.Linear(784, 128), nn.LeakyReLU(0.2),
nn.Linear(128, 1), nn.Sigmoid()) # 감별사: 이미지 → 진짜일 확률
loss_fn = nn.BCELoss()
opt_D = torch.optim.Adam(D.parameters(), lr=2e-4)
opt_G = torch.optim.Adam(G.parameters(), lr=2e-4)
for step in range(10000):
real = next(loader) # 진짜 이미지 배치
z = torch.randn(real.size(0), 64) # 노이즈
fake = G(z) # 위조범이 가짜 생성
ones, zeros = torch.ones(real.size(0), 1), torch.zeros(real.size(0), 1)
# 1) 감별사 학습: 진짜엔 1, 가짜엔 0을 주도록
loss_D = loss_fn(D(real), ones) + loss_fn(D(fake.detach()), zeros)
opt_D.zero_grad(); loss_D.backward(); opt_D.step()
# 2) 위조범 학습: 감별사가 가짜를 "진짜(1)"로 믿게 만들도록
loss_G = loss_fn(D(fake), ones)
opt_G.zero_grad(); loss_G.backward(); opt_G.step()