카멜레온과 얼리 퓨전 토큰 전용 멀티모달 모델(Chameleon and Early-Fusion Token-Only Multimodal Models)
지금까지 살펴본 모든 시각-언어 모델(Vision-Language Model; VLM)은 이미지와 텍스트를 분리해 다루었습니다. 시각 토큰(visual token)은 비전 인코더(vision encoder)에서 나와 프로젝터(projector)를 거친 뒤 거대 언어 모델(Large Language Model; LLM) 안에서 텍스트와 만납니다. 시각 어휘(vocabulary)와 텍스트 어휘는 절대 겹치지 않습니다. 카멜레온(Chameleon; Meta, 2024년 5월)은 이렇게 물었습니다. "만약 둘이 겹친다면 어떨까?" 이미지를 공유 어휘(shared vocabulary)의 이산 토큰(discrete token) 시퀀스로 변환하는 벡터 양자화 변분 오토인코더(Vector-Quantized Variational Autoencoder; VQ-VAE)를 학습합니다. 그러면 모든 멀티모달 문서가 하나의 시퀀스가 됩니다. 텍스트 토큰과 이미지 토큰이 교차로 섞이고, 손실 함수도 하나의 자기회귀(autoregressive) 손실로 통합됩니다. 부수 효과도 있습니다. 모델이 한 번의 추론(inference) 호출 안에서 텍스트와 이미지 토큰을 번갈아 출력하는 혼합 모달리티(mixed-modality) 결과를 생성할 수 있게 됩니다. 이번 레슨에서는 얼리 퓨전(early-fusion) 명제를 읽고 장난감 수준의 구현을 끝까지 만들어 봅니다.
유형: Build
언어: Python (표준 라이브러리, VQ-VAE 토크나이저 + 교차 디코더)
선수 지식: Phase 12 · 05, Phase 8 (Generative AI)
예상 시간: 약 180분
학습 목표
- 공유 어휘와 단일 손실(single loss)이 모델의 가능성을 어떻게 바꾸는지 설명합니다.
- VQ-VAE가 이미지를 트랜스포머(transformer)의 다음 토큰(next-token) 예측 목표와 호환되는 이산 시퀀스로 토크나이징(tokenizing)하는 방식을 설명합니다.
- 카멜레온의 학습 안정화(training-stability) 기법인 QK-Norm, 드롭아웃(dropout) 배치, 레이어 정규화(LayerNorm) 순서를 말할 수 있게 합니다.
- 카멜레온과 BLIP-2의 Q-Former 접근을 비교하고, 각각이 어떤 상황에서 적합한지 설명합니다.
문제
어댑터 기반(adapter-based) VLM(LLaVA, BLIP-2, Qwen-VL)은 텍스트와 이미지를 서로 다른 것으로 취급합니다. 텍스트 토큰은 embed(text_token)을 통과합니다. 이미지는 visual_encoder(image) → projector → ... pseudo_tokens를 통과합니다. 모델에는 두 개의 입력 경로가 있고, 중간 어딘가에서 합쳐집니다.
그 결과 세 가지 일이 일어납니다.
- LLM은 이미지를 받아들일 수만 있고 직접 생성할 수는 없습니다. 출력은 텍스트 전용(text-only)입니다.
- 기사처럼 단락과 이미지가 번갈아 나오는 혼합 모달리티 문서는 다루기가 어색합니다. 멀티모달 입력을 모델 바깥에서 구문 분석(parse)하거나, 생성(generation)을 여러 번 연쇄적으로 호출해야 합니다.
- 분포 불일치(distributional mismatch)가 발생합니다. 시각 토큰과 텍스트 토큰은 은닉 공간(hidden space)의 서로 다른 영역에 살며, 미묘한 정렬(alignment) 문제를 만듭니다.
카멜레온은 이 전제를 거부합니다. 이미지는 결국 공유 어휘에서 뽑은 이산 토큰의 시퀀스일 뿐입니다. 교차 배치된(interleaved) 문서로 모델을 학습하고, 손실 하나와 자기회귀 디코더 하나만으로 처리하면 혼합 모달리티 생성이 자연스럽게 열립니다.
개념
이미지 토크나이저로서의 VQ-VAE
토크나이저(tokenizer)는 벡터 양자화 변분 오토인코더(VQ-VAE)입니다. 구조는 다음과 같습니다.
- 인코더(encoder): 합성곱 신경망(CNN)과 비전 트랜스포머(Vision Transformer; ViT)가 이미지를 공간 특징 맵(spatial feature map)으로 변환합니다. 예를 들어 차원이 256인 32x32 특징 맵을 얻습니다.
- 코드북(codebook): K개의 벡터로 이루어진 학습된 어휘입니다. 카멜레온은 8192개를 사용하고, 각 벡터도 차원이 256입니다.
- 양자화(quantization): 각 공간 특징에 대해 L2 거리(L2 distance)가 가장 가까운 코드북 항목을 찾고, 연속 값(continuous feature)을 정수 인덱스로 대체합니다.
- 디코더(decoder): 양자화된 특징을 다시 픽셀로 복원하는 CNN입니다.
학습은 VAE 재구성 손실(reconstruction loss), 커밋먼트 손실(commitment loss), 코드북 손실(codebook loss)을 함께 사용합니다. 코드북 인덱스는 이미지를 위한 이산 알파벳(discrete alphabet) 역할을 합니다.
카멜레온에서는 이미지 한 장이 32*32 = 1024개 토큰이 되고, 이 토큰들은 8192개 어휘에서 뽑힙니다. 이를 텍스트 토큰과 이어 붙입니다(concatenate). 텍스트 토큰은 예를 들어 32000개 바이트 페어 인코딩(Byte Pair Encoding; BPE) 어휘에서 옵니다. 최종 어휘 크기는 40192개입니다. 트랜스포머는 하나의 시퀀스와 하나의 손실만 봅니다.
공유 어휘
카멜레온의 어휘는 텍스트 토큰, 이미지 토큰, 그리고 모달리티 구분자(modality separator)를 함께 묶습니다. 각 토큰은 하나의 ID를 가집니다. 입력 임베딩(input embedding) 계층은 모든 ID를 D차원 은닉 벡터(hidden vector)로 매핑합니다. 출력 투영(output projection)은 은닉 벡터를 다시 어휘 로짓(logit)으로 변환합니다. 소프트맥스(softmax)는 모달리티와 무관하게 다음 토큰 하나를 고릅니다.
구분자가 중요한 역할을 합니다. <image>와 </image> 태그는 이미지 토큰 시퀀스의 시작과 끝을 감쌉니다. 생성 중에 모델이 <image>를 출력하면, 후속 소프트웨어(downstream software)는 이어지는 1024개 토큰이 픽셀 렌더링(pixel rendering)을 위해 디코더로 보내야 할 VQ 인덱스라는 사실을 알게 됩니다.
혼합 모달리티 생성
추론은 공유 어휘에서 이뤄지는 다음 토큰 예측(next-token prediction)입니다. 예시 프롬프트(prompt)가 "Draw a cat and describe it."이라고 합시다. 카멜레온은 다음처럼 출력할 수 있습니다.
<image> 4821 1029 2891 ... (1024 image tokens) </image>
The cat is orange, sitting on a windowsill...
모델은 순서를 스스로 결정합니다. 이미지를 먼저 만들고 텍스트를 만들 수도, 텍스트를 먼저 만들고 이미지를 만들 수도, 둘을 교차로 섞을 수도 있습니다. 같은 디코더와 같은 손실로 처리합니다.
텍스트만 생성할 수 있는 어댑터 VLM과 비교해 보세요. 카멜레온은 모델 출력 모달리티(output modality)라는 질문을 다시 던집니다.
학습 안정성 — QK-Norm, 드롭아웃, LayerNorm 순서
얼리 퓨전 학습은 큰 규모(scale)에서 매우 불안정합니다. 카멜레온 논문은 세 가지 기법을 정리해 둡니다.
- QK-Norm. 어텐션(attention) 내부의 닷곱(dot product) 직전에 쿼리(query)와 키(key) 투영에 LayerNorm을 적용합니다. 깊은 모델에서 로짓 크기(logit magnitude)가 폭발하는 현상을 막아 줍니다. 2024년 이후 여러 대형 모델이 이 기법을 채택했습니다.
- 드롭아웃 배치(dropout placement). 어텐션과 다층 퍼셉트론(Multi-Layer Perceptron; MLP) 뒤에만 드롭아웃을 두는 것이 아니라, 잔차 합(residual-add) 뒤마다 드롭아웃을 둡니다. 이미지 토큰에서 들어오는 그래디언트(gradient)가 지배할 수 있으므로 더 강한 정규화(regularization)가 필요하기 때문입니다.
- LayerNorm 순서. 잔차 가지(residual branch)에는 표준적인 Pre-LN을 쓰고, 마지막 블록의 스킵 연결(skip connection)에는 추가 LN을 둡니다. 최종 계층의 그래디언트 흐름(gradient flow)을 안정화합니다.
이 기법들이 없으면 34B 파라미터 카멜레온 학습은 여러 체크포인트(checkpoint)에서 발산(diverge)합니다. 기법을 적용하면 수렴(converge)합니다. 학습 레시피(training recipe)는 구조(architecture)만큼이나 중요한 기여입니다.
토크나이저의 재구성 상한선(reconstruction ceiling)
VQ-VAE는 손실 압축(lossy)을 사용합니다. 코드북 항목이 8192개이고 512x512 이미지마다 1024개 토큰을 사용할 때, 재구성 PSNR은 대략 26~28 dB 부근에서 막힙니다. 알아볼 수 있는 이미지 생성에는 충분하지만, 연속 공간(continuous-space) 확산 모델(diffusion model)보다는 눈에 띄게 떨어집니다. 스테이블 디퓨전 3(Stable Diffusion 3)는 32 dB 이상을 달성합니다.
병목(bottleneck)은 토크나이저입니다. 더 나은 토크나이저, 예를 들면 MAGVIT-v2, IBQ, SBER-MoVQGAN 등은 상한을 끌어올립니다. Emu3(레슨 12.12)는 더 좋은 토크나이저만으로도 SDXL 수준의 생성 품질에 도달할 수 있음을 보여 줍니다.
카멜레온 vs BLIP-2 / LLaVA
카멜레온(얼리 퓨전, 공유 어휘):
- 손실 하나, 디코더 하나로 동작합니다.
- 혼합 모달리티 출력을 생성합니다.
- 토크나이저가 품질 상한을 결정합니다.
- 비용이 큽니다. 추론 경로에서 생성된 이미지마다 VQ-VAE 디코더가 필요합니다.
BLIP-2 / LLaVA(레이트 퓨전, 분리된 타워):
- 비전을 입력받고 텍스트만 출력합니다.
- 사전학습된(pretrained) LLM을 재사용합니다.
- 이해(understanding) 과제에서는 토크나이저 병목이 없습니다.
- 비용이 저렴합니다. 한 번의 순방향 패스(single forward pass)로 처리합니다.
과제에 따라 선택합니다. 이미지 생성이 필요하면 카멜레온 계열을 선택합니다. 이해만 필요하면 어댑터 기반 VLM이 더 단순하고 사전학습된 연산 자원(compute)을 더 많이 재사용할 수 있습니다.
Fuyu와 AnyGPT
Fuyu(Adept, 2023)는 관련된 접근입니다. 별도의 비전 인코더를 아예 건너뛰고, 원시 이미지 패치(raw image patch)를 토큰처럼 LLM의 입력 투영에 그대로 넣습니다. 토크나이저가 없습니다. 카멜레온보다 단순하지만, 공유 어휘 기반의 출력 생성은 잃습니다.
AnyGPT(Zhan et al., 2024)는 카멜레온을 네 가지 모달리티로 확장합니다. 텍스트, 이미지, 음성(speech), 음악(music)입니다. 각 모달리티에 같은 VQ-VAE 기법을 적용하고 공유 트랜스포머를 사용합니다. 임의의 모달리티에서 임의의 모달리티로 변환하는 any-to-any 생성입니다. 레슨 12.16에서 더 자세히 다룹니다.
사용해보기
code/main.py는 종단 간(end-to-end) 얼리 퓨전 토이 모델을 만듭니다.
- 8x8 패치(patch)를 코드북 인덱스로 매핑하는 작은 VQ-VAE 풍의 양자화기(quantizer)입니다.
K=16입니다.
(text id 0..31) + (image id 32..47) + (separator 48, 49)로 구성된 공유 어휘입니다.
- 합성된 캡션(synthetic caption)과 이미지 토큰 시퀀스로 학습한 토이 자기회귀 디코더로, 실제로는 바이그램(bigram) 테이블입니다.
- 프롬프트가 주어지면 텍스트 토큰과 이미지 토큰을 번갈아 출력하는 샘플링 루프(sampling loop)입니다.
코드는 트랜스포머를 의도적으로 매우 작게 유지합니다. 바이그램만 사용해서 신호 흐름(signal flow)을 끝까지 추적할 수 있게 하기 위함입니다.
산출물 만들기
이 레슨은 outputs/skill-tokenizer-vs-adapter-picker.md를 만듭니다. 제품 사양(product spec; 이해 전용인지 이해+생성인지, 요구되는 이미지 품질, 비용 예산)이 주어지면 카멜레온 계열(얼리 퓨전)과 LLaVA 계열(레이트 퓨전) 중 어느 쪽이 맞는지 고르고, 정량적인 경험 법칙(rule of thumb)으로 그 선택을 정당화합니다.
연습문제
-
쉬움: 카멜레온은 K=8192 코드북 항목과 512x512 이미지당 1024 토큰을 사용합니다. 24비트 RGB 이미지 대비 압축비(compression ratio)를 추정하세요. 손실 압축입니까? 얼마나 손실이 큽니까?
-
중간: 같은 VQ-VAE 밀도(density)로 처리할 때 4K 이미지(3840x2160)는 이미지 토큰을 몇 개 만들어 냅니까? 카멜레온 계열 모델이 4K 이미지를 한 번의 추론 호출로 생성할 수 있습니까? 먼저 무너지는 것은 컨텍스트(context)입니까, 토크나이저 품질입니까, KV 캐시(KV cache)입니까?
-
중간: 순수 Python으로 QK-Norm을 구현합니다. 64차원 쿼리와 키가 주어졌을 때 LayerNorm 적용 전후의 닷곱을 보여 주세요. 깊은 모델에서 크기 조절(magnitude control)이 왜 중요합니까?
-
어려움: 학습 안정성을 다룬 카멜레온 논문의 2.3절을 읽으세요. QK-Norm이 없는 34B 규모에서 논문이 관찰한 정확한 실패 양상(failure mode)은 무엇입니까? "노름 폭발(norm explosion)" 시그니처는 어떤 모습이었습니까?
-
어려움: 텍스트만 들어 있는 프롬프트가 주어졌을 때 혼합 모달리티 응답을 출력하도록 토이 디코더를 확장합니다. 학습 데이터 분포가 텍스트 먼저 60%, 이미지 먼저 40%일 때 모델이 이미지 먼저와 텍스트 먼저를 얼마나 자주 선택하는지 측정하세요.
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| 얼리 퓨전(Early fusion) | "통합된 토큰(Unified tokens)" | 이미지를 이산 토큰으로 변환해 1단계부터 트랜스포머 어휘를 텍스트와 공유하는 방식 |
| VQ-VAE | "이미지 토크나이저(Image tokenizer)" | CNN + ViT + 코드북으로 이미지를 트랜스포머가 예측할 수 있는 정수 인덱스로 매핑하는 모델 |
| 공유 어휘(Shared vocabulary) | "하나의 사전(One dictionary)" | 텍스트, 이미지, 모달리티 구분자를 모두 포함하는 단일 토큰 ID 공간 |
| QK-Norm | "어텐션 안정화 장치(Attention stabilizer)" | 닷곱 직전에 쿼리와 키에 LayerNorm을 적용해 노름 폭발을 막는 기법 |
| 혼합 모달리티 생성(Mixed-modality generation) | "텍스트 + 이미지 출력(Text + image output)" | 한 번의 추론에서 텍스트와 이미지 토큰을 교차로 자율 생성하는 방식 |
| 코드북 크기(Codebook size) | "K개 항목(K entries)" | VQ-VAE가 양자화할 수 있는 이산 벡터의 개수이며, 압축과 충실도(fidelity) 사이의 절충을 만듭니다 |
| 토크나이저 상한선(Tokenizer ceiling) | "재구성 한계(Reconstruction limit)" | VQ 토큰을 복원했을 때 도달 가능한 최대 PSNR이며, 모델의 이미지 품질 상한을 결정합니다 |
더 읽을거리