Midjourney로 이미지 뽑다가 새벽 3시에 갑자기 궁금해진 적 있음. "이 녀석은 내가 영어로 쓴 프롬프트를 어떻게 읽고 그림을 그리지?" 그날 프롬프트 수정만 3시간 했거든요. "cinematic lighting" 넣었다 빼고, "8k ultra detailed" 넣었다 빼고. 근데 근데 정작 이 뒤에서 뭐가 돌아가는지는 한 번도 안 찾아봤었음.

그러다 문득 찝찝해져서 논문을 뒤지기 시작했는데, 여기서 한 이틀을 날렸어요.


임베딩이라는 트릭

제가 원래 생각했던 건 이거예요. 이미지 처리하는 모듈, 텍스트 처리하는 모듈, 오디오 처리하는 모듈이 각각 따로 있고 마지막에 어디선가 합쳐지겠지. 근데 아니었음.

핵심은 뭐냐면, 어떤 형태의 입력이든 전부 임베딩 벡터라는 같은 종류의 숫자 뭉치로 변환된다는 거예요. 강아지 사진, "dog"이라는 텍스트, "개"라고 말한 음성 — 이 셋이 고차원 수학 공간에서 거의 같은 좌표에 찍힘. 우리 뇌도 빛이든 소리든 결국 전기 신호로 바꿔서 처리하잖아요. 그거랑 비슷한 원리.

연구자들은 이걸 cross-modal reasoning이라고 부릅니다.

텍스트 이미지 오디오 데이터가 고차원 임베딩 공간에서 하나로 수렴하는 추상적 시각화

구조는 간단히만

멀티모달 LLM 내부 구조는 세 파트예요. 각 입력을 벡터로 바꾸는 인코더, 서로 다른 벡터 공간을 하나로 맞춰주는 프로젝션 레이어, 그리고 최종 추론을 담당하는 언어 모델 백본(GPT, LLaMA 같은 것들).

프로젝션 레이어가 선형 변환 하나짜리 단순한 구조라는 게 좀 의외인데 이건 나중에 다시 이야기할게요.


ViT — 여기서 한참 헤맸다

이 글에서 가장 오래 붙잡고 있었던 부분임.

2020년에 구글 리서치 팀이 "An Image is Worth 16x16 Words"라는 논문을 쓰는데요. ICLR 2021에 발표되고 나서 인용 수가 수만 회를 넘겼어요. 근데 제가 이 논문에 꽂힌 건 인용 수 때문이 아니라 제목 때문이었음. 원래 "An image is worth a thousand words"라는 영어 속담이 있는데 그걸 비틀어서 16x16으로 바꾼 거거든요. 이 제목 하나로 사람을 끌어당기는 센스가 대단한 것 같아요 진짜. 연구자들 사이에서도 논문 제목이 곧 마케팅이라는 걸 보여주는 사례랄까. 나도 블로그 제목 저렇게 짓고 싶다...

어쨌든 본론으로 돌아오면, 이 논문이 뭘 한 거냐면요.

224x224 픽셀 이미지를 16x16 크기의 패치로 잘라요. 그러면 14x14 = 196개 조각이 나옴. 이 각 조각을 1차원 벡터로 쫙 펴고, "나는 왼쪽 위에서 세 번째 조각이야" 같은 위치 정보(positional embedding)를 붙여서 트랜스포머에 넣는 거예요. NLP에서 문장을 단어 토큰으로 쪼개서 모델에 넣는 것과 완전히 같은 로직인데 그걸 이미지에 적용한 거죠.

여기서 어텐션이 하는 일이 — 이게 제가 제일 좋아하는 부분인데 — 강아지 귀 패치가 자기 혼자 있으면 그냥 "갈색 픽셀 뭉치"잖아요. 근데 주변의 얼굴 패치, 몸통 패치를 참조하면서 "이건 골든 리트리버의 귀다"를 알게 되는 거거든요. 레이어를 통과할수록 맥락이 쌓여서, 마지막 레이어쯤 가면 "해변에 앉아 있는 골든 리트리버"까지 이해함. 패치 하나하나는 의미 없는 픽셀 조각인데 어텐션을 통과하면서 의미가 생기는 거예요. 이게 너무 멋있지 않나요? 저만 흥분한 건가.

골든 리트리버 사진이 16x16 패치로 분할되어 공중에 떠 있는 모자이크 분해 시각화 어텐션 메커니즘이 이미지 패치들을 연결해 골든 리트리버 형태를 인식하는 과정

근데 이거 읽으면서 바로 든 의문이 — "패치 크기를 바꾸면 어떻게 되지?" 16x16이 아니라 32x32로 하면? 8x8로 하면? 논문 Table 5인가 6인가에 비교가 나오는데 (정확한 번호는 까먹음) 패치가 작을수록 정보는 세밀해지는 대신 연산량이 제곱으로 늘어나요. 8x8로 하면 토큰이 784개가 되는데 셀프 어텐션이 O(n²)이니까 감당이 안 되는 거죠. 16x16이 성능과 비용 사이의 스윗 스팟이었다는 건데, 솔직히 이건 2020년 기준 하드웨어 한계에서 나온 타협이지 절대적인 정답은 아닌 것 같음. 요즘 나오는 모델들은 패치 크기를 가변적으로 쓰기도 하고요.

그리고 ViT는 데이터가 적으면 CNN한테 짐. 논문에서도 이걸 인정하고 있어요. ImageNet 수준의 "중간 크기" 데이터셋에서는 비슷한 사이즈의 ResNet보다 정확도가 낮았음. JFT-300M같은 3억 장짜리 괴물 데이터셋으로 사전학습을 해야 비로소 CNN을 압도하기 시작하거든요. 개인 프로젝트에서 ViT를 처음부터 학습시키겠다? 현실적으로 무리.

제가 ViT에 이렇게 길게 쓰는 이유가 있는데, Stable Diffusion 돌릴 때 "이 모델이 이미지를 어떻게 인식하지?" 궁금했던 적이 있었거든요. 그때는 대충 CNN 쓰겠지 하고 넘겼는데 최근 멀티모달 모델 대부분이 ViT 기반이었음. 그때 찾아볼 걸 그랬어요.


CLIP

CLIP은 짧게 갈게요.

기존 비전 모델은 사람이 라벨 붙인 데이터로 학습했는데 OpenAI의 CLIP은 인터넷에서 긁은 4억 개 이미지-캡션 쌍으로 학습함. contrastive learning이라는 방식인데, 배치에서 맞는 이미지-텍스트 쌍은 벡터를 가깝게, 틀린 쌍은 멀리 밀어내는 거예요. 라벨링 없이 의미 연결을 학습한다는 게 핵심.

CLIP의 contrastive learning에서 이미지와 텍스트 캡션 쌍이 정렬되는 과정

근데 직접 써보면 한계가 보여요. 한복 입은 여성이 경복궁 앞에 서 있는 이미지를 CLIP 임베딩으로 텍스트 매칭 시켰는데, "traditional Korean dress"보다 "woman in colorful robe near Asian temple" 쪽이 유사도가 더 높게 나온 적이 있음. 학습 데이터가 영어권 인터넷 위주라서 "한복"이 아니라 "화려한 로브"로 인식하는 거예요. 4억 쌍이래봤자 결국 데이터 분포의 한계.


소리를 이미지로 바꿔버린다

오디오는 텍스트나 이미지와 달리 연속적인 데이터예요. 30초짜리 오디오를 16,000Hz로 샘플링하면 48만 개 데이터 포인트가 나오는데, 이걸 그대로 트랜스포머에 넣으면 터집니다.

그래서 멜 스펙트로그램으로 변환해요. 오디오를 25밀리초 단위로 쪼개고, FFT 걸어서 주파수 성분 추출하고, 인간 청각 특성에 맞춘 멜 스케일로 매핑하면 시간×주파수의 2D 히트맵이 됨. 30초 클립이 대략 80x3,000 그리드가 돼요.

사람 음성을 멜 스펙트로그램으로 변환한 2D 히트맵 시각화

여기서부터는 이미지 처리할 때랑 똑같아요. 패치 쪼개고 트랜스포머에 넣으면 됨. OpenAI Whisper가 이 방식으로 68만 시간의 다국어 오디오를 학습했고요.

근데 잠깐 삼천포로 빠자면, 멜 스케일이라는 게 꽤 흥미로운 놈이에요. 사람 귀가 저주파에서는 주파수 차이를 잘 구분하는데 고주파로 갈수록 둔감해지거든요. 1000Hz와 1100Hz의 차이는 쉽게 느끼는데 8000Hz와 8100Hz의 차이는 거의 못 느낌. 멜 스케일이 이 비선형적인 인간 청각을 반영해서, 저주파 영역에 더 많은 해상도를 할당하는 건데 — 결국 AI 오디오 모델이 "사람처럼 듣는" 게 아니라 "사람이 잘 듣는 영역을 우선적으로 처리하는" 거예요. 이 차이가 은근 중요한 것 같은데 잘 언급 안 되더라고요.

아무튼 다시 본론으로.


학습: 얼리고 녹이고

학습은 2단계. 첫 번째로 비전 인코더랑 언어 모델은 얼려두고(frozen) 프로젝션 레이어만 학습시켜서 정렬을 맞추고, 두 번째로 프로젝션 레이어랑 언어 모델까지 같이 열어서 대화형 instruction 데이터로 학습시킵니다. 두 번째 단계에서 GPT-4한테 합성 학습 데이터를 만들게 시켰다는 게 좀 웃긴데, 이건 어디서 읽었는지 기억이 정확하지 않아요. LLaVA 논문이었나 InstructBLIP이었나... 아무튼 AI가 AI 교육 자료를 쓰는 셈이니까요.


아까 미룬 이야기 — 프로젝션 레이어

아까 프로젝션 레이어가 의외로 단순하다고 했는데 여기서 설명할게요.

비전 인코더가 뽑은 "고양이" 벡터랑 언어 모델이 이해하는 "고양이" 벡터는 완전 다른 수학 공간에 있어요. 차원 수도 다르고 벡터가 의미하는 체계 자체가 다름. 프로젝션 레이어가 이걸 하나의 공간으로 맞춰주는 건데 — 이게 선형 변환 하나예요. 행렬곱 한 번. 많아봐야 2층짜리 작은 MLP.

LLaVA 논문 Figure 1 보면 구조가 나오는데 진짜 이게 끝이에요. "에이 설마" 하고 코드까지 봤는데 진짜였음.

서로 다른 두 수학 공간을 하나의 선형 변환으로 연결하는 프로젝션 레이어 개념도

다만 이게 만능은 아니에요. "강아지"나 "자동차"같이 시각적으로 명확한 건 정렬이 잘 되는데, "그리움"이나 "향수" 같은 추상 개념으로 가면 모달리티 간 매핑이 꽤 흔들립니다.


비디오는요?

비디오 이야기를 안 할 수가 없는 게, 요즘 멀티모달 하면 비디오를 빼놓을 수 없잖아요. 근데 현실은 대부분 프레임 단위로 잘라서 이미지로 처리하는 수준이에요. "이 장면에서 저 장면으로 넘어가면서 분위기가 어떻게 바뀌었나?" 같은 시간 축 추론은 아직 제대로 못 함. 인코더 여러 개에 프로젝션에 LLM까지 태우는 구조이다 보니 추론 비용도 미쳤고요.


저는 이 글 쓰면서 프로젝션 레이어가 제일 계속 생각남. 행렬곱 하나가 서로 다른 세계를 연결한다는 거. 어제도 Midjourney에서 "a cat sitting on a quantum computer, photorealistic" 넣었는데 고양이 다리가 5개 나왔거든요. 아직 멀었다 싶으면서도, 이 구조를 알고 나니까 왜 이런 실수가 나오는지는 좀 이해가 됨. 패치 레벨에서 다리 수를 세는 건 어텐션으로 하기 어려운 종류의 작업이니까. 아마.

ViT 논문이랑 CLIP 논문은 읽어보면 좋아요. 특히 ViT는 의외로 짧음.