14장 — 글을 읽는 인코더: CLIP의 마지막 층에서 언어모델의 여러 층으로

자주 하는 실수와 요약

자주 하는 실수

실수 나온 문제 바로잡는 법
그림 N장과 글 N개의 짝을 N(N − 1)/2로 셈 1 (그림, 글)을 하나씩 고르므로 N²가지, 틀린 짝은 N² − N
코사인에 곱하는 배율은 클수록 좋다고 봄 2 배율은 코사인의 작은 차이를 확률 차이로 키운다. 너무 크면 엉터리 차이까지 확신해 학습이 흔들려, CLIP은 100을 넘지 않게 묶었다
뜻이 정반대인 문장은 색 하나 바꾼 문장보다 멀다고 봄 3 순서만 바뀐 문장은 낱말 주머니가 같다. CLIP 문장 벡터에서는 위아래를 뒤집은 문장이 0.972, 색을 맞바꾼 문장이 60쌍 모두 하나 바꾼 문장보다 가까웠다
코사인이 거의 같으면 가르는 정보가 없다고 봄 3 선형 분류기로는 문장 벡터에서 고양이 색을 99.9% 읽었다. 정보가 있는 것과 벡터를 크게 움직이는 것은 다르다
문장 벡터에 직접 들어가지 않는 자리는 기울기가 0이라고 봄 5 길이 하나라도 있으면 0이 아니다. 끝에서 둘째 층의 자리는 마지막 층 끝 토큰의 어텐션을 거쳐 신호를 받는다
마지막 층 토큰 자리의 성질이 다른 것을 「끝에서 둘째 층이 더 좋다」의 증명으로 읽음 5 숫자가 말하는 것은 마지막 층의 토큰 자리가 학습으로 다듬어지지 않았다는 데까지다
clip skip 2가 어느 모델에서나 좋다고 봄 6 모델이 학습 때 받은 층에 맞춘다. SDXL 은 이미 끝에서 둘째 층이 기본이고, −1로 바꾸면 처음 보는 입력이 된다
로짓 렌즈로 읽히지 않는 층에는 정보가 없다고 봄 7 낱말 하나로 읽히지 않을 뿐이다. 중간 층의 뜻은 다른 방법(뜻 짝 찾기)으로 잰다
언어모델 은닉 상태를 그대로 평균해 문장 벡터로 씀 8 첫 자리 토큰이 다른 토큰의 백 배 넘게 커서 평균을 혼자 차지한다. 틀로 감싸고 머리를 잘라 낸다
층 하나를 고르는 것과 여러 층을 넘기는 것을 같은 일로 봄 9 하나를 고르면 비중을 사람이 미리 정한 것이다. 여럿을 넘기면 비중을 디퓨전 쪽이 배운다
큰 선형층 하나가 작은 섞기보다 늘 낫다고 봄 10 Krea 2 는 층끼리 어텐션으로 엮은 뒤 층 비중 12개만 배운다. 매개변수 7,800만 개 대신 12개다
여러 층을 그대로 이어 붙이면 좋아진다고 봄 11 길이가 큰 뒤쪽 층이 코사인을 다 차지한다. 크기를 맞추고 섞는 법을 학습해야 한다
크로스 어텐션에서 글 토큰도 층마다 바뀐다고 봄 12 크로스 어텐션에서 글은 읽히기만 한다. 글 토큰이 그림을 보고 바뀌는 것은 합동 어텐션이다
합동 어텐션은 셈이 훨씬 무겁다고 봄 13 그림 토큰 4096개에 글 512개면 그림끼리보다 1.27배, 77개면 1.04배다
글 토큰의 위치가 모두 같으면 순서를 잃는다고 봄 14 순서는 언어모델 안에서 이미 은닉 상태에 들어갔다. 위치 좌표가 꼭 필요한 것은 그림 토큰이다

요약

조건을 거는 글 벡터는 글 인코더가 무엇을 맞히며 배웠는지를 닮는다. CLIP은 미니배치 안에서 그림과 글의 짝을 맞히며 배워, 무엇이 있는지는 잘 가르지만 색을 맞바꾼 두 문장처럼 짝 맞히기에 필요 없던 차이는 벡터를 거의 움직이지 않는다. Stable Diffusion 1.x 는 그 인코더의 마지막 층을 토큰마다 받았는데, 마지막 층의 토큰 자리는 손실에서 신호를 받지 못하는 칸이다. 끝에서 둘째 층은 마지막 층의 끝 토큰이 어텐션으로 읽는 층이라 모든 자리가 신호를 받고, SD2 와 SDXL 은 이 층을 쓴다. clip skip 은 모델이 학습 때 받은 층에 맞추는 손잡이다.

글을 읽는 쪽을 키우는 것이 그림 쪽을 키우는 것보다 남는다는 발견 뒤로, 글 인코더 자리에 T5, 그리고 대화형 언어모델이 들어왔다. 언어모델의 마지막 층은 다음 토큰을 맞히도록 학습돼 그 쪽으로 기울고, 앞쪽 층은 지금 토큰의 낱말 정보가, 가운데 층은 문장의 뜻이 크게 자리 잡는다. 그래서 FLUX.2 는 세 층을, Krea 2 는 열두 층을 쌓아 넘기고, 어느 층을 얼마나 볼지는 디퓨전 쪽의 글 융합 단계가 학습한다. 쌓은 글 토큰 줄은 크로스 어텐션(그림이 글을 읽는다), 합동 어텐션(한 줄로 이어 서로 읽는다), 시간 벡터에 더하는 문장 벡터(그림 전체를 민다) 가운데 하나 이상의 길로 들어가고, 언어모델 인코더를 쓰는 최근 모델은 합동 어텐션 쪽으로 모였다.

flowchart LR
  A["CLIP 마지막 층<br/>토큰마다 77 × 768"] -->|"마지막 층 칸은<br/>학습 신호가 없다"| B["끝에서 둘째 층<br/>SD2 · SDXL"]
  B -->|"짝 맞히기로는<br/>짜임을 덜 배운다"| C["T5 · 언어모델 인코더<br/>Imagen · SD3 · Qwen-Image"]
  C -->|"마지막 층은<br/>다음 토큰 쪽"| D["여러 층 쌓기<br/>FLUX.2 3층 · Krea 2 12층"]
  D --> E["글 융합 단계가<br/>섞는 비중을 배운다"]

막힌 곳

이제 「빨간 정육면체가 파란 공 위에」라는 글을 디퓨전이 읽을 수 있는 벡터 줄로 바꾸는 길을 안다. 그런데 사용자가 원하는 것이 「이 사진 속 사람의 얼굴로」, 「이 옷을 입혀서」라면 어떨까? 얼굴 생김새나 옷의 무늬는 아무리 긴 글로 적어도 정확히 전해지지 않는다. Krea 2 의 글 인코더는 원래 그림까지 읽는 시각언어모델이었다. 글 대신 그림을, 그것도 여러 장을 조건으로 넣으려면 그 그림은 어떤 토큰 줄이 되어 어느 자리로 들어가야 할까?