Section 0177 토큰 제한
Stable Diffusion v1.5의 텍스트 인코더는 OpenAI의 CLIP 인코더를 쓴다. CLIP 텍스트 인코더에는 77 토큰 제한이 있고, 이 제한이 다운스트림 Stable Diffusion으로 그대로 전파된다.
긴 프롬프트를 인코딩하려 하면 단호한 오류가 떨어진다 — RuntimeError: tensor a (181) must match tensor b (77). CLIP 텍스트 인코더는 한 번에 단 77개의 토큰만 받는다.
prompt = "a photo of a cat and a dog driving an aircraft " * 20 tokenizer = pipe.tokenizer text_encoder = pipe.text_encoder tokens = tokenizer(prompt, truncation=False, return_tensors='pt')["input_ids"] print(len(tokens[0])) # 181 embeddings = pipe.text_encoder(tokens.to("cuda"))[0] # RuntimeError — 181 != 77
49406(<|startoftext|>)과 마지막 ID 49407(<|endoftext|>)은 토크나이저가 자동으로 붙인다. 토큰을 청크로 잘라 다시 이을 때 이 두 토큰을 반드시 제거해야 한다. 그렇지 않으면 시작·끝 토큰이 중간에 끼어든다.
Section 02제한 극복하기
다행히 Stable Diffusion UNet은 77 토큰 제한을 강제하지 않는다. 제한은 CLIP 인코더에만 있다. 임베딩을 배치로 가져와 청크된 임베딩을 하나의 tensor로 연결해 UNet에 넘기면 제한을 우회할 수 있다.
1. 파이프라인에서 텍스트 토크나이저와 텍스트 인코더를 추출한다.
2. truncation=False로 어떤 크기의 프롬프트든 토큰화한다.
3. 자동으로 붙은 시작·끝 토큰을 제거한다.
4. 77개씩 청크로 꺼내 각각 임베딩으로 인코딩한다.
5. 임베딩들을 [1, x, 768] 크기의 tensor로 스택해 UNet에 공급한다.
Section 03Compel 블렌딩
Compel은 Damian Stewart가 만든 오픈 소스 프롬프트 가중치·블렌딩 라이브러리다. "반은 고양이, 반은 개인 사진"을 원할 때, "A photo with half cat and half dog"이라 쓰면 "half"가 동물이 아니라 사진 자체에 적용되어 버린다.
Compel은 두 개념의 텍스트 임베딩을 직접 블렌딩해 이 문제를 푼다.
from compel import Compel compel = Compel( tokenizer = pipeline.tokenizer, text_encoder = pipeline.text_encoder) # 고양이 70% + 개 30% 블렌딩 prompt = '("A photo of cat", "A photo of dog").blend(0.7, 0.3)' prompt_embeds = compel(prompt) image = pipeline( prompt_embeds = prompt_embeds, generator = torch.Generator("cuda:0").manual_seed(1) ).images[0]
Compel이 Diffusers와 매끄럽게 맞물리는 이유는, 모델 파일의 동일한 CLIPTokenizer와 CLIPTextModel로 텍스트 임베딩을 만들기 때문이다. .blend()의 비율을 바꾸면 더 고양이 같은, 혹은 더 개 같은 사진을 얻는다.
Section 04스케줄된 프롬프트
Diffusers 기본 코드에는 한계가 있다. "처음 5단계는 고양이를, 다음 5단계는 개를 생성하라"는 프롬프트는 쓸 수 없다. 두 개념을 번갈아 노이즈 제거해 혼합하는 것도 불가능하다. 스케줄된 프롬프트(scheduled prompt)는 이 빈틈을 메운다.
[cat:dog:0.5] 같은 구문을 해석하는 커스텀 파서가 필요하다. 책에서는 lark 패키지로 파서를 만들고, 누락된 단계를 채운 뒤, 각 노이즈 제거 단계에서 해당 단계의 텍스트 임베딩을 UNet에 공급하는 커스텀 파이프라인을 구축한다. 단계가 진행될수록 프롬프트가 바뀐다.
Section 05좋은 프롬프트의 원칙
SD v1.5의 CLIP 인코더는 인터넷의 캡션 이미지로 학습됐는데, 그중 다수가 구조화된 문장이 아닌 태그다. 그래서 v1.5는 "마법 같은" 키워드를 외워 조합해야 한다. SDXL의 듀얼 인코더는 훨씬 지능적이지만, 그래도 원칙은 있다.
| 원칙 | 나쁜 예 | 좋은 예 |
|---|---|---|
| 명확하고 구체적으로 | "A painting of cool sci-fi" | "...futuristic cityscape with towering skyscrapers, neon lights, flying vehicles" |
| 설명적으로 | "A beautiful woman" | "...long flowing brown hair, piercing emerald eyes, gentle smile" |
| 일관된 용어 | "blue suit, he wears colorful cloth" (모순) | "tailored blue suit adorned with a colorful scarf" |
이 밖에도 아트워크와 스타일을 참조하고, 네거티브 프롬프트를 통합하며, 반복과 개선을 거듭하라. 그리고 가장 강력한 도구 — LLM을 프롬프트 생성기로 활용하면, 간단한 아이디어를 풍부하고 구조화된 Stable Diffusion 프롬프트로 자동 확장할 수 있다.