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 는 박스 이름을 하나도 안 댔어. 엔진이 엮었어.
네가 이해하는 다단계 시스템을 골라 (빌드 파이프라인, 요청/응답 사이클, 게임 루프). 별개 박스로 쪼개. 두 박스 사이 각 seam 마다, 한 줄 계약을 적어: upstream 박스가 downstream 박스한테 뭘 약속해? 그 계약들의 명료함이 네 아키텍처의 건강이야.
Hint
seam 의 계약을 한 문장으로 못 말하면, 두 박스가 아직 융합돼 있을 거야. 깨끗한 seam 은 '경우에 따라' 안 하고 적을 수 있는 계약을 가져.
Progress
Progress is local-only — sign in to sync across devices.