C.W.K.
Stream
Lesson 02 of 04 · published

다섯 개의 박스

~14 min · five-modules, pipeline, vae, sampler, backbone

Level 0툴 임차인
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"다섯 박스를 한 번 보면, 다시는 안 볼 수 없어. 모든 diffusion 모델은 같은 다섯 박스를 조금씩 다르게 엮은 거야."

정직하게 그린 파이프라인

diffusion 이미지 생성기는 하나의 마법 행위처럼 보여 — 프롬프트 들어가고, 그림 나오고 — 근데 순서대로 넘겨지는 다섯 개의 별개 작업이야. 이름 붙이면 마법이 메커니즘이 돼:

  1. Text encoder — 네 프롬프트를 네트워크가 attend 할 수 있는 conditioning 벡터로 바꿔. family 에 따라 CLIP, 또는 CLIP + T5.
  2. Backbone — denoising 네트워크 자체. U-Net(구), DiT 나 MMDiT(transformer 시대). 생성의 뇌야.
  3. Sampler / scheduler — backbone 한테 "여기 노이즈가 뭐야?" 를 반복해 묻고 latent 를 깨끗한 이미지로 stepping 하는 루프. Euler, DPM++, flow-match.
  4. Conditioning attach — backbone 에 볼트로 조인 추가물: LoRA, ControlNet, IP-Adapter, embedding, inpaint mask.
  5. VAE — 압축된 latent 공간(모든 작업이 일어나는 곳)이랑 실제 픽셀(네가 보는 것) 사이를 번역해.

왜 하나가 아니라 다섯

각 박스가 모델 family 마다 독립적으로 바뀌어. SDXL 이랑 FLUX 는 VAE 개념은 공유하지만 다른 VAE weight 를 써. backbone 은 완전히 다른 걸 쓰고. 어떤 sampler 는 공유하고 어떤 건 안 하고. 이 다섯 작업이 한 함수에 살면, 모든 모델 family 가 그 함수 안에서 다른 모든 family 랑 싸워. 다섯 박스면, 각 family 가 필요한 박스만 공급하고 나머진 재사용해.

변화가 일어나는 선을 따라 분리해. 옳은 module 경계는 자의적이지 않아 — 정확히 다른 모델 family 가 다른 데 떨어져. text encoder 가 변하니까 text encoder 가 박스야. backbone 이 가장 많이 변하니까 backbone 이 가장 중요한 박스고. 경계는 변화의 단층선을 따라가.

인터페이스가 진짜 제품이야

박스는 그 사이 seam 보다 덜 중요해. sampler 는 backbone 이 U-Net 인지 DiT 인지 신경 안 써 — "노이즈 낀 latent 랑 timestep 주면, 노이즈를 예측해" 만 필요해. 그 계약이 인터페이스야. 모든 backbone 이 그걸 지키는 한, sampler 는 절대 안 바뀌어. 인터페이스가 박스를 스왑 가능하게 만들고; 박스는 그 뒤의 구현일 뿐이야.

구현 전에 seam 을 설계해. 어렵고 가치 있는 작업은 한 박스가 다른 박스한테 뭘 약속하는지 정의하는 거야 — 메서드 시그니처, tensor shape, 계약. seam 이 옳으면, 여러 구현이 그 뒤에 꽂혀. seam 이 틀리면 어떤 구현도 너를 못 구해.

recipe 가 박스를 통과하는 법

생성 요청이 recipe 로 들어와서 박스를 순서대로 통과해: text encoder 가 프롬프트를 conditioning 으로 바꾸고, conditioning-attach 레이어가 LoRA 나 ControlNet 을 접어 넣고, sampler 가 각 step 마다 backbone 을 호출하며 루프 돌고, 마지막으로 VAE 가 완성된 latent 를 픽셀로 디코드해. recipe 는 박스 이름을 절대 안 대 — 그냥 뭘 원하는지 말하고, 엔진이 옳은 다섯 개로 라우팅해.

아빠가 이 다섯 박스를 처음 그려줬을 때, 난 이미 diffusion 작동법을 오래 '알고' 있었어 — 근데 하나의 흐릿한 과정으로 알았어. 그걸 이름 붙은 계약을 가진 다섯 hand-off 로 보는 게, 그게 블랙박스이길 멈추고 내가 추론하고, 수정하고, 확장할 수 있는 시스템이 된 순간이었어. seam 에 이름 붙이는 게 지식을 이해로 바꾼 거야.

Code

다섯 protocol, 많은 구현·python
# 다섯 박스를 protocol(인터페이스)로. 구현은 모델 family 마다
# 다르고; 이 계약은 안 달라.
from typing import Protocol
import torch

class TextEncoder(Protocol):
    def encode(self, prompt: str) -> torch.Tensor: ...      # 박스 1

class Backbone(Protocol):
    def predict_noise(self, latents: torch.Tensor,
                      t: int, cond: torch.Tensor) -> torch.Tensor: ...  # 박스 2

class Sampler(Protocol):
    def sample(self, backbone: Backbone, cond: torch.Tensor,
               steps: int) -> torch.Tensor: ...             # 박스 3

class Conditioning(Protocol):
    def attach(self, backbone: Backbone) -> Backbone: ...   # 박스 4 (LoRA/ControlNet)

class VAE(Protocol):
    def decode(self, latents: torch.Tensor) -> torch.Tensor: ...  # 박스 5

# SDXL 이 한 세트 구현을 공급하고, FLUX 가 다른 세트를.
# 위 protocol 은 절대 안 바뀌어 — 그게 스왑 가능하게 만드는 거야.
recipe 는 뭘 말하고; 박스가 어떻게를 해·python
# recipe 가 다섯 박스를 순서대로 통과.
def run(recipe, te: TextEncoder, bb: Backbone,
        sampler: Sampler, cond: Conditioning, vae: VAE):
    conditioning = te.encode(recipe.prompt)        # 박스 1: 텍스트 -> 벡터
    bb = cond.attach(bb)                            # 박스 4: LoRA/ControlNet 접어 넣기
    latents = sampler.sample(bb, conditioning,      # 박스 3 이 루프로 박스 2 를 몰아
                             steps=recipe.steps)
    image = vae.decode(latents)                     # 박스 5: latent -> 픽셀
    return image
# recipe 는 박스 이름을 하나도 안 댔어. 엔진이 엮었어.

External links

Exercise

네가 이해하는 다단계 시스템을 골라 (빌드 파이프라인, 요청/응답 사이클, 게임 루프). 별개 박스로 쪼개. 두 박스 사이 각 seam 마다, 한 줄 계약을 적어: upstream 박스가 downstream 박스한테 뭘 약속해? 그 계약들의 명료함이 네 아키텍처의 건강이야.
Hint
seam 의 계약을 한 문장으로 못 말하면, 두 박스가 아직 융합돼 있을 거야. 깨끗한 seam 은 '경우에 따라' 안 하고 적을 수 있는 계약을 가져.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.