🖼️ 온디바이스에서 "글자가 안 깨지는" 이미지 생성 — POCKET-Image
VIDRAFT · POCKET 시리즈 신규 모델 · 한국어 요약 (기술)
대부분의 텍스트-투-이미지 모델은 한글(과 비라틴 문자)을 정확히 못 씁니다. 프롬프트에 "안녕하세요"를 넣으면 "안ㅐ기 하웲소" 같은 결과가 나오죠. POCKET-Image는 이 문제를 GPU/NPU 없이 온디바이스에서 실용 수준으로 해결한 모델입니다. 이 글은 왜 어려운지, 어떤 축으로 접근했는지(구현 세부는 제외), 그리고 온디바이스 경량화·평가를 정리합니다.
1. 왜 디퓨전 모델은 글자를 못 쓰나
이건 데이터만의 문제가 아니라 구조적 난제입니다.
- 한글의 조합성: 한글은 초성·중성·종성 자모를 쌓아 11,172개 음절 블록을 만듭니다. 같은 자모라도 받침 유무·위치에 따라 모양이 바뀝니다. 디퓨전 디노이저는 글자를 하나의 형태(shape)로 "그리는" 방식이라, 자모 조합 규칙을 배우지 못해 낯선 음절에서 오탈자가 납니다.
- 비라틴 전반 동일: 중국어·일본어(한자 수천 자), 아랍어(글자 연결 + RTL), 태국어(성조·모음 기호 겹침), 인도계(결합 자소). 라틴·숫자는 그럭저럭 되지만 그 외 스크립트는 광범위하게 뭉갭니다.
- 평가의 함정: OCR로 채점할 때, 여러 줄 포스터에서 OCR이 일부만 읽어 정답을 오답으로 처리하는 경우가 흔합니다(특히 easyocr). 텍스트 렌더링 평가는 OCR 단독보다 VLM/육안 병행이 안전합니다.
2. 관련 연구 — "글리프 조건부" 계열
텍스트 렌더링을 개선하는 공개 연구 대부분은 정답 글자 형태를 조건으로 주입하는 방향입니다. 이 계열을 알아두면 문제의 성격이 분명해집니다.
- AnyText / GlyphControl — 글리프 이미지를 컨디션으로 사용
- Glyph-ByT5 — 바이트/서브음절 텍스트 인코더로 문자 인지 강화
- TextFlux(2505.17778) — 글자 캔버스를 공간적으로 결합
- EasyText(2505.24417) — 위치 인코딩 기반 글리프 조건, 한국어 문자 정밀도 보고
공통점: 모델이 글자를 "발명"하게 두지 않고, 정확한 글자형을 참조/보존하도록 만든다는 것입니다.
3. POCKET-Image의 접근 (관점)
핵심 관점: 텍스트 렌더링을 "생성 문제"가 아니라 "보존 문제"로 재정의한다.
POCKET-Image는 위 계열의 정신을 따르되, 글자형 충실도(glyph fidelity)를 보장하는 파이프라인으로 구성했습니다. 즉 사용자가 넣은 문구는 정확히 유지하고, 모델은 그 주변 장면만 만들도록 역할을 나눴습니다. (구체 구현·레시피는 비공개입니다.) 다국어 지원은 스크립트별 폰트 선택 + 복합문자 셰이핑(HarfBuzz/RAQM)으로 처리해, 아랍어 RTL 연결과 태국어·인도계 결합 기호까지 올바르게 배치합니다.
결과적으로 한국어 · 中文 · 日本語 · العربية · ไทย · Latin 등에서 헤드라인 텍스트 정확도가 사실상 100%에 수렴합니다(전역 모델이 전부 깨뜨리는 구간).
4. 온디바이스 경량화 — VRAM을 어떻게 줄였나
베이스는 Z-Image(약 6B single-stream DiT + 텍스트 인코더 + VAE, Apache-2.0)입니다. 문제는 bf16 원본이 무겁다는 것 — 그래서 표준 4-bit 양자화로 온디바이스에 맞췄습니다. 여기엔 특별한 비법이 없습니다. 공개 도구를 그대로 씁니다.
- CUDA: bitsandbytes NF4 (double-quant, bf16 compute)
- Apple Silicon / CPU: optimum-quanto int8 — bitsandbytes는 CUDA 전용이라, 크로스플랫폼엔 quanto가 열쇠
from diffusers import DiffusionPipeline, PipelineQuantizationConfig
import torch
# 표준 NF4 4-bit (CUDA). 큰 컴포넌트(transformer, text_encoder)만 양자화, VAE는 유지
qc = PipelineQuantizationConfig(
quant_backend="bitsandbytes_4bit",
quant_kwargs={"load_in_4bit": True, "bnb_4bit_quant_type": "nf4",
"bnb_4bit_compute_dtype": torch.bfloat16,
"bnb_4bit_use_double_quant": True},
components_to_quantize=["transformer", "text_encoder"],
)
pipe = DiffusionPipeline.from_pretrained(
model_id, quantization_config=qc, torch_dtype=torch.bfloat16
).to("cuda")
측정 결과 (1024×1024 추론 피크 VRAM):
| 구성 | 피크 VRAM | 비고 |
|---|---|---|
| bf16 (원본) | 23.3 GB | 기준 |
| NF4 (CUDA) | 8.6 GB | RTX 3050/4060급 |
| NF4 + CPU offload | 4.5 GB | 6GB GPU(RTX 2060)도 가능 |
| quanto int8 (Mac) | 13.4 GB | MacBook 16GB+ 통합메모리 |
흥미로운 부수효과: 글자형은 파이프라인 차원에서 보존되므로, 양자화가 텍스트 정확도를 건드리지 않습니다. 양자화 손실은 배경 품질에만 미세하게 반영됩니다. 그래서 4-bit로 밀어도 "글자는 그대로 정확"합니다 — 온디바이스에 특히 유리한 특성입니다.
5. 평가
정량 지표는 PaddleOCR(Korean) 기반 Sentence Accuracy / NED(AnyText 계열 표준)를 권장합니다. 앞서 언급한 OCR 오채점 함정(여러 줄 부분 인식) 때문에, 육안/VLM 검수를 병행했습니다. 실측에서 한·중·일·아랍·태국 5개 언어 헤드라인이 모두 정확히 렌더됨을 확인했습니다.
6. 정직한 한계
- 텍스트는 보장되지만, 배경은 일반 생성입니다. 사진실사 + 전경 물체가 많은 장면에서는 물체가 글자를 시각적으로 가릴 수 있습니다. 깔끔한 그라디언트/스튜디오 배경에서는 글자가 매우 선명합니다.
- 일부 스크립트(예: 특정 결합 자소)는 폰트·셰이핑 커버리지에 의존합니다.
데모 · 모델
- 🎨 Studio (그 자리에서 생성): huggingface.co/spaces/FINAL-Bench/POCKET-Image-Studio
- 🧩 모델 카드: huggingface.co/FINAL-Bench/POCKET-Image-Zimage
- 🧠 베이스: Tongyi-MAI/Z-Image (Apache-2.0)
POCKET 시리즈는 "큰 모델을 작은 하드웨어에서" 지향합니다 — GPU/NPU 없이 CPU·RAM만으로 도는 온디바이스 AI. POCKET-Image는 그 이미지 편입니다. 피드백·질문 환영합니다. 🙌