
대칭은 기본값입니다: 당신의 캐릭터 사양(Spec)이 살아남아야 하는 이유
요약
이미지 생성 AI에서 캐릭터 일관성을 유지하기 위해 캐릭터 사양(Spec)을 계약(Contract) 관점에서 접근하는 방법론을 제시합니다. 대칭성을 기본값으로 하는 모델의 특성을 고려하여, 비대칭적 속성을 통해 모델의 성능을 검증하는 테스트 방식을 설명합니다.
핵심 포인트
- 캐릭터 일관성을 미학적 문제가 아닌 계약(Contract) 문제로 정의
- 대칭성을 사전 확률로 활용하여 비대칭 속성으로 모델 성능 검증
- 프레임 내 속성 가시성(양손 포함 여부)의 중요성 강조
- 모델 아키텍처(SDXL vs DiT)에 따른 프롬프트 가중치 작동 차이 언급
이미지 생성에서 캐릭터 일관성(Character consistency)은 보통 미학적인 문제로 논의됩니다. 저는 이를 계약(Contract) 문제로 다루는 것이 더 유용하다고 생각합니다. 즉, 제가 모델에 사양(Specification)을 전달했을 때, 입력값이 변하더라도 그 사양이 유지되는지 알고 싶은 것입니다. 그래서 저는 의도적인 실패 모드(Failure mode)를 가진 사양을 구축하고, 같은 날 두 개의 애니메이션 이미지 모델을 통해 테스트를 진행했습니다.
그 실패 모드는 바로 대칭(Symmetry)입니다.
사양 (The spec)
한 번 작성되면 모든 실행 과정에서 일정하게 유지되는 7가지 속성입니다.
character: Shiori
hair: jet-black, low knot at the nape
hair_pin: single thin gold pin, through the knot
...
이 중 5개는 비용이 적게 듭니다. 머리카락 색상, 눈 색상, 그리고 팔레트(Palette)는 이미지의 전역적 속성(Global properties)이기 때문에 확산 모델(Diffusion model)이 거의 우연히 재현해내는 종류의 것들입니다.
나머지 2개는 비용이 많이 들며, 실제로 중요한 단언(Assertions)들입니다:
glove_hand == LEFT and ring_hand == RIGHT(장갑 낀 손 == 왼쪽 그리고 반지를 낀 손 == 오른쪽)face_mark_side == RIGHT(얼굴 점 위치 == 오른쪽)
두 가지 모두 비대칭(Asymmetric)입니다. 대칭이 사전 확률(Prior)이기 때문에, 비대칭은 흥미로운 테스트가 됩니다. 사용자의 설명을 추적하는 것을 멈춘 모델은 노이즈를 생성하는 것이 아니라 평균(Average)을 생성할 것입니다. 그리고 "장갑 한 개"의 평균은 장갑이 두 개가 되거나, 아예 없거나, 혹은 두 속성이 우연히 렌더링된 손 쪽으로 합쳐지는 것입니다.
처음에는 적어두지 않았지만, 예상보다 더 중요하게 작용한 세 번째 단언이 있었습니다:
both_hands_in_frame == true(양손이 프레임 안에 있음 == 참)
볼 수 없는 속성은 검증할 수 없는 속성입니다. 프레임을 크롭(Crop)해버리는 모델은 당신의 테스트를 소리 없이 삭제해 버린 셈입니다.
테스트 1: 베이스라인, 프롬프트만 사용
Model A는 Niji Journey 모델로, 현재 Niji 7 버전입니다. Model B는 PixAI의 Tsubaki.2로, 디퓨전 트랜스포머 (Diffusion Transformer, DiT) 모델입니다. 이 차이는 나중에 중요해지는데, (tag:1.3)과 같은 괄호 가중치 구문 (bracket weight syntax)은 SDXL 계열 모델에서는 작동하지만 DiT에서는 아무런 효과가 없기 때문입니다.
두 베이스라인 (Baseline) 모두 비용이 많이 드는 어설션 (Assertion)을 통과했습니다. 장갑 (Glove)과 반지 (Ring)가 각각 다른 손에 위치했습니다. Model A는 양측을 거울처럼 대칭 (Mirror)시켰는데, 이는 이미 알려진 지루한 유형의 실패 사례입니다. Model B는 사양 (Spec)에 명시된 대로 배치했습니다.
베이스라인 통과를 명확히 언급할 가치가 있는 이유는, 많은 비교가 여기서 멈추고 첫 번째 렌더링 (Render)의 결과만으로 승자를 선언하기 때문입니다. 첫 번째 렌더링은 쉬운 케이스입니다. 프롬프트 (Prompt)가 모든 역할을 수행하며, 무언가를 지속 (Persist)시키라고 요구하지 않은 상태이기 때문입니다.
테스트 2: 입력값은 변경하되, 사양은 유지한다
새로운 의상, 새로운 환경, 하지만 프롬프트에는 동일한 7가지 속성을 그대로 가져왔습니다: 두꺼운 오버코트 (Heavy overcoat), 니트 스카프 (Knit scarf), 해질녘 비에 젖은 거리 (Rain-slicked street at dusk), 전신 (Full body).
| 실행 (Run) | 모델 (Model) | 장갑/반지 분리 여부 | 양손이 프레임 내에 있음 | 요청되지 않은 추가 요소 |
|---|---|---|---|---|
| 2a | A | 아니오, 한 손에 합쳐짐 | 아니오, 허리 위 크롭 (Waist-up crop) | 금색 링 귀걸이 |
| 2b | A, 동일한 프롬프트 | 아니오, 한 손에 합쳐짐 | 아니오, 허리 위 크롭 (Waist-up crop) | 금색 링 귀걸이 |
실행 2b가 유용한 데이터입니다. 저는 실패가 확률적 (Stochastic)인지 결정론적 (Deterministic)인지를 확인하기 위해 2a를 바이트 단위로 똑같이 반복했으며, 결과는 재현되었습니다. 이 차이가 엔지니어링의 핵심입니다:
- 확률적 (Stochastic) 실패는 재시도 (Retry)의 문제입니다. 성공할 때까지 루프를 돌리면 됩니다.
- 재현 가능한 (Reproducible) 실패는 입력 (Input)의 문제입니다. 동일한 프롬프트는 무한히 동일한 오독 (Misreading)을 생성할 것입니다.
both_hands_in_frame 어설션이 실패한 것이 일차적인 어설션 실패의 원인이었습니다. 한쪽 손이 크롭(Crop)되면서, 모델은 상호 배타적인 두 속성을 하나의 표면에 배치해야 했고, 결국 이를 합쳐버렸습니다. 제 사양 (Spec)에 구멍이 있었고, 도구가 그 구멍을 찾아낸 것입니다.
테스트 3: 입력으로서의 참조 (Reference as input)
이 시점에서 올바른 조치는 캐릭터를 묘사하는 것을 멈추고 캐릭터를 직접 전달(passing)하기 시작하는 것입니다. Model A는 Character Reference (캐릭터 참조) 컨트롤을 노출합니다. Niji 7에서는 비활성화된 상태로 렌더링되며, 이를 클릭해도 아무런 반응이 없습니다. 에러도, 툴팁도, 설명도 나타나지 않습니다. 참조 패널은 이미지 프롬프트 (image prompt)와 스타일 참조 (style reference)를 제공합니다.
그래서 저는 이미지 프롬프트를 사용하여, 기본 가중치 (default weight)로 전달된 베이스라인 (baseline)을 다시 입력했습니다.
| 실행 (Run) | 입력 (Input) | 결과 (Result) |
|---|---|---|
| 3a | 이미지 프롬프트로서의 베이스라인 이미지 | 모든 실행 중 얼굴 충실도 (face fidelity)가 가장 높았으나, 색상 번짐 (palette bled) 발생 (재킷 안감이 터틀넥으로 다시 나타남), 장갑/반지는 여전히 합쳐짐, 여전히 잘림 |
이것이 제가 주목하는 발견입니다. 참조 (reference)는 이미지의 전역적 속성 (global property)인 모든 것을 개선했지만, 피사체에 관한 개별적 사실 (discrete fact)에 대해서는 아무것도 개선하지 못했습니다. "참조 이미지 (reference image)"를 단일한 기능으로 취급하는 것은 실수입니다. 그 라벨 아래에는 적어도 두 가지의 서로 다른 계약 (contracts)이 숨겨져 있으며, 그중 오직 하나만이 사양 (specification)을 담고 있습니다.
Model B는 이를 생성 모델 (generation model)의 플래그 (flag)가 아닌 별도의 모델을 통해 라우팅 (route)하는데, 이는 실제적인 결과로 이어지는 구현 세부 사항 (implementation detail)입니다. 즉, 캐릭터는 애니메이션 모델에서 생성된 후 참조 모델에 의해 운반되므로, 두 모델 사이의 스타일 변화 (style shift)는 버그라기보다 예상되는 현상입니다. 이 모델은 최대 10개의 참조 입력을 허용하는데, 이는 캐릭터 시트 (character sheets)가 작동하는 방식과 일치합니다. 캐릭터는 하나의 정전적 프레임 (canonical frame)이라기보다 여러 각도의 집합이기 때문입니다.
Model B를 통해 세 번의 장면 전환 (scene changes)을 거치는 동안, 얼굴, 매듭, 그리고 금색 핀은 유지되었습니다.
테스트 4: LoRA 추가 및 그 비용
LoRA는 저차원 어댑터 (low-rank adapter)로, 베이스 모델 (base model) 위에 학습된 작은 가중치 (weights) 세트입니다. 저는 눈 렌더링 (eye rendering)을 위해 제작된 커뮤니티 어댑터를 추가하고, 변경되지 않은 프롬프트 (prompt)에 해당 트리거 워드 (trigger words)를 입력한 뒤 0.7의 강도로 실행했습니다.
그 결과 눈 처리는 제대로 이루어졌습니다. 하지만 얼굴의 기하학적 구조 (geometry)가 부드러워졌고, 사양 (spec)에는 전혀 없는 앞머리가 추가되었습니다. 0.7의 강도에서 어댑터는 스타일 (style)을 넘어 정체성 (identity) 영역까지 침범했습니다.
일반화할 수 있는 규칙은 다음과 같습니다: 어댑터는 캐릭터가 점유하고 있는 동일한 잠재 공간 (latent space)에 가해지는 가중치가 부여된 개입 (intervention)입니다. 따라서 강도 (strength)는 당신이 원하는 효과와 당신이 보존하려는 대상 사이의 트레이드오프 (tradeoff)입니다. 만약 정체성이 우선순위라면, 가중치 (weight)가 가장 먼저 낮춰야 할 노브 (knob)입니다.
여기서 얻은 교훈
이미지 모델 (image models)을 기반으로 구축하는 모든 것에 적용할 수 있는 세 가지 사항이 있습니다.
사양 (spec)에 비대칭적 단언 (asymmetric assertion)을 넣으세요. 이는 단 한 토큰 (token)의 변화만으로 가능하며,
도구(tooling)에 관한 문제도 동일한 맥락에서 해결됩니다. 만약 결과물이 단 하나의 이미지라면, 첫 번째 렌더링(render) 결과가 더 나은 모델이 승리하며, 제 테스트 결과에서는 Model A가 승리했습니다. 만약 결과물이 여러 이미지에 걸쳐 동일한 피사체(subject)를 유지해야 한다면, 중요한 것은 해당 플랫폼이 정체성(identity)을 데이터로서 전달할 수 있는 경로를 제공하느냐 하는 것입니다. 이것이 제가 오늘 일과의 나머지 절반을 PixAI에서 보낸 이유입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기


