노이즈에서 그림이 태어나다 — 그림을 노이즈로 망가뜨리는 법을 정해두고, 그 '되돌리기'로 새 그림을 만들어요. Stable Diffusion·DALL·E의 원리!
점 200개가 하나의 "그림"이에요 (실제 모델에서는 픽셀 수십만 개). 파랑일수록 또렷한 원본, 회색일수록 노이즈에 가까운 상태예요.
👀 읽는 법: t 슬라이더를 문지르면 모양이 "녹았다 얼었다" 해요. 🎬 생성을 누르면 새 노이즈 구름에서 모양이 태어나는 과정이 재생돼요. 실제 확산 모델은 이 되돌리기를 신경망이 학습해서 해내요 — 이 화면은 목표를 알려준 개념 시연이에요.
이 데모는 목표 배치를 매번 새로 뽑아 결과가 조금씩 달라요. 진짜 확산 모델은 시작 노이즈가 매번 달라서 같은 그림이 두 번 나오지 않아요.
앞 방향은 정해진 규칙(노이즈 섞기)이라 배울 게 없어요. 어려운 건 거꾸로 — 실제 모델은 "이 안에 섞인 노이즈가 얼마나 되는지"를 맞히는 신경망을 훈련해서 한 겹씩 벗겨냅니다.
# 실전: diffusers 라이브러리 — 4줄이면 그림이 나와요
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
image = pipe("a watercolor heart", num_inference_steps=40).images[0]
image.save("heart.png")
# 개념 의사코드: DDPM의 두 방향
# (1) 앞 방향 — 노이즈 섞기 (훈련 데이터 만들기)
# x_t = sqrt(abar_t) * x0 + sqrt(1 - abar_t) * eps
# 신경망(U-Net)은 x_t를 보고 "섞인 eps"를 맞히도록 학습해요.
# (2) 거꾸로 — 생성 (오늘 🎬 버튼이 한 일)
x = torch.randn(3, 512, 512) # 완전한 노이즈에서 출발
for t in reversed(range(num_steps)): # t = 999 → 0
eps_hat = unet(x, t, prompt_emb) # "이 안에 섞인 노이즈는 이만큼!"
x = remove_noise(x, eps_hat, t) # 예측한 노이즈를 한 겹 벗겨냄
# 루프가 끝나면 x가 그림이 되어 있어요 (스텝이 적으면 거칠어요)