kimyongtae.com
홈 / 강의 / AI 이미지·애니메이션 생성, 원리부터 / 2단계. 이미지 생성 해부

2-1. 워크플로 해부: 노드와 수식을 맞춰 보기

ComfyUI의 기본 워크플로에는 노드가 일곱 개 있다. 그 일곱 개가 1단계에서 배운 부품과 하나씩 대응한다. 이번 수업은 그 대응을 확인한다. 이것만 되면 어떤 복잡한 워크플로도 읽을 수 있다.

왜 ComfyUI인가

이미지 생성 도구는 여럿이다. 이 강의는 ComfyUI를 쓴다. 이유는 하나다. 구조가 눈에 보인다.

다른 도구는 설정 칸만 보여 주고 안에서 무슨 일이 일어나는지 숨긴다. ComfyUI는 부품을 상자(노드)로 늘어놓고 선으로 잇게 한다. 1-8의 전체 그림을 직접 조립하는 셈이다. 새 모델과 기법도 가장 먼저 지원된다.

기본 워크플로

[Load Checkpoint] ─ MODEL ──────────────────────→ [KSampler] ─ LATENT → [VAE Decode] → [Save Image]
        │─ CLIP → [CLIP Text Encode] (긍정) ─ CONDITIONING ─→   ↑              ↑
        │─ CLIP → [CLIP Text Encode] (부정) ─ CONDITIONING ─→   │              │
        │─ VAE ─────────────────────────────────────────────────│──────────────┘
[Empty Latent Image] ─ LATENT ──────────────────────────────────┘

노드 하나씩

Load Checkpoint

모델 파일을 읽어 세 덩어리로 내놓는다. 1-8의 세 상자다.

출력실체배운 곳
MODEL디노이저 (U-Net 또는 DiT)1-2, 1-4, 1-8
CLIP텍스트 인코더1-5
VAE압축기와 복원기1-1

출력 이름이 CLIP이라고 되어 있지만 T5나 LLM 계열 인코더도 이 선으로 흐른다. 처음 만들 때 CLIP뿐이어서 붙은 이름이다.

CLIP Text Encode

글을 받아 토큰 벡터 묶음으로 바꾼다. 1-5의 텍스트 인코더를 실제로 돌리는 노드다. 출력 이름 CONDITIONING이 "조건"이다.

두 개를 쓴다. 하나는 긍정, 하나는 부정이다. 노드 자체는 똑같다. KSampler의 어느 구멍에 꽂느냐가 역할을 정한다.

Empty Latent Image

빈 잠재를 만든다. 가로, 세로, 장수를 정한다.

이름은 "빈"이지만 여기에 KSampler가 노이즈를 채운다.

KSampler

핵심 노드다. 1-3의 걷기를 실행한다.

입력, 설정하는 일배운 곳
model방향을 알려 줄 디노이저1-8
positiveCFG의 "조건 있음"1-6
negativeCFG의 "조건 없음" 자리1-6
latent_image출발할 잠재1-1
seed출발 노이즈를 정한다0-1
steps걸음 수1-3
cfg프롬프트 방향을 몇 배로 과장할지1-6
sampler_name걷는 방법1-3
scheduler걸음을 어디에 놓을지1-3
denoise얼마나 노이즈를 섞고 시작할지. 1이면 순수 노이즈3-1에서

안에서 벌어지는 일을 말로 쓰면 이렇다.

시드로 노이즈를 만든다
스케줄러가 정한 걸음마다:
    디노이저를 긍정 조건으로 한 번, 부정 조건으로 한 번 부른다
    cfg 로 두 결과를 합친다
    샘플러의 방법대로 한 걸음 옮긴다
완성된 잠재를 내놓는다

VAE Decode

잠재를 그림으로 푼다. 1-1의 디코더다. 한 번만 돈다.

Save Image

그림을 파일로 저장한다. ComfyUI는 PNG 안에 워크플로 전체를 함께 적어 둔다. 그 그림을 ComfyUI 창에 끌어다 놓으면 만들 때 쓴 워크플로가 그대로 열린다. 남이 만든 그림의 설정을 배울 때 쓸모 있다.

최신 모델의 워크플로는 조금 다르다

Flux 이후의 모델은 세 덩어리를 따로 받는다. 텍스트 인코더가 수 GB에서 십수 GB로 커져서 한 파일에 묶지 않는다.

기본 노드나눠 받을 때의 노드
Load CheckpointLoad Diffusion Model (디노이저)
Load CLIP 또는 DualCLIPLoader (텍스트 인코더)
Load VAE

노드가 몇 개 더 붙기도 한다.

상자가 늘어나도 뼈대는 같다. 세 덩어리를 읽고, 프롬프트를 조건으로 바꾸고, 잠재를 만들고, 걷고, 푼다.

선의 색과 타입

선은 타입이 맞아야 이어진다. MODEL 출력은 model 입력에만 꽂힌다. 타입이 곧 "무엇이 흐르는가"다.

타입흐르는 것
MODEL디노이저
CLIP텍스트 인코더
VAEVAE
CONDITIONING프롬프트의 토큰 벡터
LATENT잠재
IMAGE픽셀 그림

LATENT와 IMAGE를 구분하는 것이 중요하다. 둘 사이를 오가려면 VAE를 거쳐야 한다. VAE Decode는 LATENT를 IMAGE로, VAE Encode는 IMAGE를 LATENT로 바꾼다.

워크플로는 파일이다

워크플로는 JSON 파일로 저장된다. 그리고 ComfyUI는 그 JSON을 받아 실행하는 서버이기도 하다. 화면에서 손으로 누르지 않고 프로그램이 워크플로를 보내 그림을 받아 올 수 있다. 캐릭터 수백 명의 그림을 한꺼번에 뽑는 일이 이렇게 된다. 7단계에서 다룬다.

해 볼 것

시드를 고정하고 하나씩만 바꿔 본다. 한 번에 하나만 바꿔야 그 설정의 효과만 보인다.

  1. steps를 5, 10, 20, 40으로 바꿔 본다. 몇에서부터 그림이 더 나아지지 않나?
  2. cfg를 1, 3, 7, 12로 바꿔 본다. 어디서부터 색이 타기 시작하나?
  3. sampler를 euler와 euler_ancestral로 바꾸고, 각각 steps를 20과 40으로 돌려 본다. 어느 쪽이 구도가 유지되나?
  4. Empty Latent Image의 크기를 모델의 기본 해상도의 절반과 두 배로 바꿔 본다. 무슨 일이 생기나?

예상 결과

  1. 모델마다 다르지만 대개 20~30에서 멈춘다. 그 뒤로는 경로를 이미 충분히 정확하게 따라가고 있다(1-3).
  2. 1에서는 흐리고 프롬프트를 덜 따른다. 값이 커질수록 또렷해지다가, 어느 선을 넘으면 색이 진해지고 윤곽이 딱딱해진다(1-6).
  3. euler는 스텝을 바꿔도 구도가 유지된다. euler_ancestral은 걸음마다 노이즈를 넣어서 그림이 달라진다(1-3).
  4. 절반이면 그림이 무너진다. 두 배면 같은 대상이 여러 번 반복되거나 몸이 늘어난다. 모델은 학습한 해상도 근처에서만 제대로 그린다.
← 1-8 아키텍처: U-Net에서 DiT로 2-2 모델 계보: 이름의 홍수에서 길 찾기 →