혼동하기 쉬운 점과 요약
토론 1. 어텐션은 점수가 가장 큰 토큰 하나를 꺼내 오나
단톡방 질문에 대한 지난 메시지 넷의 점수가 3, 3, 0, 0이고 1인당 가격이 12,000원, 30,000원, 8,000원, 5,000원이면, 어텐션이 읽어 오는 가격은 얼마인가?

이번엔 지난 메시지 넷의 점수가 3, 3, 0, 0이에요. 가격은 12,000원, 30,000원, 8,000원, 5,000원이고요. 어텐션이 읽어 오는 가격은 얼마일까요?

어텐션은 결국 점수가 가장 높은 메시지를 찾아 읽는 거니까, 점수 3인 둘 가운데 하나겠죠. 12,000원이나 30,000원이요.

계산해 볼게. e³이 둘이고 e⁰이 둘이라 비중이 0.476, 0.476, 0.024, 0.024야. 섞으면 0.476 × 42,000 + 0.024 × 13,000이라 20,300원쯤.

20,300원이면 어느 메시지에도 없는 가격이네요. 가장 높은 하나를 골라 오는 줄 알았는데, 비중대로 섞으니 두 가격의 한가운데쯤이 나왔어요.

문제 1에서는 왜 12,000원 하나를 읽은 것처럼 보였을까요?

점수 3짜리가 하나뿐이라 비중 81%가 거기로 몰렸고, 나머지는 서로 지웠으니까요. 하나를 고른 게 아니라 섞은 결과가 하나에 가까웠던 거예요.

그럼 하나만 읽게 하고 싶으면 점수 차이를 벌려야겠네요. 문제 1에서 점수를 세 배로 키웠을 때처럼요. 그래도 비중이 정확히 1이 되지는 않고요.

그래요. 어텐션은 소프트맥스 비중으로 모두를 섞어요. 점수 차이와 배율이 쏠림을 정하고, 점수가 비슷한 토큰이 여럿이면 그 값들을 섞은, 어느 토큰에도 없는 벡터를 읽어 와요.
토론 2. 글 인코더의 폭만 맞춰 주면 U-Net 은 그대로 쓸 수 있나
Stable Diffusion 1.x 의 글 인코더(폭 768)를 폭 1024인 다른 글 인코더로 바꾸고, 그 사이에 1024 → 768 선형 층 하나만 끼운다. U-Net 은 그대로 쓸 수 있는가?

Stable Diffusion 1.x 의 글 인코더를 폭 1024인 다른 글 인코더로 바꾸고, 그 사이에 1024를 768로 줄이는 선형 층 하나만 끼운다고 해요. U-Net 은 그대로 쓸 수 있을까요?

크기만 맞으면 되죠. 문제 13에서 걸린 게 열쇠·값 행렬의 크기였으니까, 768로 줄여서 넣으면 그 행렬들을 하나도 안 바꿔도 돼요. 선형 층만 배우면 되니까 싸고요.

폭이 똑같이 768인 다른 글 인코더 둘을 생각해 봐요. 「red」라는 낱말이 두 인코더에서 같은 벡터로 나올까요?

따로 학습했으니 같을 리가 없죠. 768개 수의 자리마다 뜻이 다를 거예요. 아, 그럼 크기를 맞춰도 U-Net 의 열쇠·값 행렬은 옛 인코더의 자리 뜻대로 읽는 거네요.

그럼 끼운 선형 층이 할 일은 새 인코더의 벡터를 옛 인코더가 냈을 벡터 자리로 옮기는 거야. 두 인코더가 낱말의 뜻을 서로 다르게 나눠 담았다면, 선형 층 하나로 그게 될지부터 모르겠어.

그래요. 폭을 맞추는 것과 뜻을 맞추는 것은 다른 일이에요. 그래서 글 인코더를 바꾼 모델은 대개 U-Net 을 다시 학습하고, U-Net 을 그대로 두려면 새 글 벡터를 옛 글 벡터 자리로 옮겨 주는 연결 신경망을 따로 학습해 끼워요. 어느 쪽이든 학습이 들어가요.
혼동하기 쉬운 점
| 혼동하기 쉬운 생각 | 나온 문제 | 바로잡는 법 |
|---|---|---|
| 점수가 가장 큰 것 하나만 읽는다고 봄 | 토론 1 | 소프트맥스 비중으로 모두를 섞는다. 점수 차이와 배율이 쏠림을 정한다 |
| 점수를 키우면(나누지 않으면) 확실하게 골라 좋다고 봄 | 2 | 처음부터 99.97%로 쏠리면 그래디언트 p(1 − p)가 0.000335로 사라진다. √d_k 로 나눠 점수의 표준편차를 1로 맞춘다 |
| √d_k 로 나누면 학습 뒤의 쏠림도 막힌다고 봄 | 2 | 성분이 독립인 처음 상태에서 크기를 맞출 뿐이다. 학습이 만든 쏠림은 남는다 |
| 그림을 두 배로 키우면 점수 표도 두 배라고 셈 | 3 | 칸이 네 배, 점수 표는 칸 수의 제곱이라 열여섯 배다 |
| 소프트맥스를 질의 묶음으로 잘라 계산하면 답이 달라진다고 봄 | 3 | 소프트맥스는 한 질의의 줄 안에서만 나눈다. 줄 묶음마다 따로 해도 같다 |
| 회전 위치 인코딩에서 내적만 보고 절대 자리를 안다고 봄 | 4 | 내적에는 자리의 차이만 남는다. 회전 주파수 하나로는 한 바퀴 뒤 차이도 겹친다 |
| 셀프 어텐션을 쓰는 신경망은 늘 순서를 모른다고 봄 | 5, 6 | 어텐션 앞에 자리를 아는 층(합성곱)이 없을 때만이다 |
| 머리를 나누면 파라미터와 계산이 머리 수만큼 는다고 봄 | 7 | 행렬을 머리 수로 자를 뿐이라 파라미터와 곱셈 수 둘 다 머리 하나일 때와 같다. 느는 것은 소프트맥스(비중 분포)의 수다 |
| 머리들의 비중 평균을 「머리 하나였을 때의 비중」으로 읽음 | 8 | 평균 낸 비중은 어떤 소프트맥스에서도 나온 값이 아니다 |
| 문장 하나의 비중 표로 머리의 역할을 정함 | 8 | 그 문장에서 보인 읽기 경향일 뿐이다. 여러 문장으로 확인해야 한다 |
| 층 정규화가 토큰의 정보를 지우지 않는다고 봄 | 9 | 토큰 하나의 평균과 크기를 지운다. 앞 정규화는 그래서 줄기에는 정규화 전 값을 남긴다 |
| 앞 정규화의 뒤쪽 블록은 일을 안 한다고 봄 | 10 | 처음에는 블록이 더하는 벡터가 줄기에 비해 작지만, 학습이 그 벡터의 크기와 방향을 정한다 |
| 뒤 정규화 트랜스포머를 깊게 쌓고 워밍업 없이 큰 학습률로 시작함 | 11 | 블록 24벌 실험에서 손실이 ln 64 에서 내려오지 않았다. 워밍업을 두거나 앞 정규화를 쓴다 |
| 크로스 어텐션은 글 토큰이 하나여도 칸마다 다르게 읽는다고 봄 | 12 | 토큰이 하나거나 모두 같으면 모든 칸이 같은 벡터를 받는다 |
| 「어텐션 블록」의 파라미터는 대부분 어텐션이라고 봄 | 13 | SD 1.x 에서는 MLP 가 55.7%다 |
| 글 인코더를 바꿔도 U-Net 은 그대로 쓸 수 있다고 봄 | 13, 토론 2 | 크로스 어텐션의 열쇠·값 행렬은 글 쪽 폭에 맞춰져 있어 크기부터 바뀐다. 폭을 맞춰도 U-Net 은 옛 글 인코더의 벡터를 읽도록 배웠다 |
| 적어 둔 누계·캐시는 앞 기록이 바뀌어도 쓸 수 있다고 봄 | 14, 15 | 앞 기록(앞 토큰의 열쇠·값)이 다시 바뀌지 않을 때만 맞다. 트랜스포머에서는 마스크가 그 보장이다 |
| KV 캐시 크기에서 열쇠·값 두 벌을 빼먹음 | 16 | 2 × 블록 수 × 열쇠·값 머리 수 × 머리 길이 × 바이트 |
요약
합성곱은 자리마다 무게를 정해 두어 멀리 있는 칸을 읽기 어려웠다. 셀프 어텐션은 토큰마다 질의·열쇠·값을 만들고, 질의와 열쇠의 내적을 √d_k 로 나눠 소프트맥스를 씌운 비중으로 값을 섞어, 거리와 상관없이 내용이 맞는 토큰을 읽는다. 내용만 보므로 토큰을 뒤섞어도 출력이 따라 옮겨 갈 뿐이라, 자리는 위치 인코딩으로 따로 적는다. 자리 벡터를 더하는 사인 형태에서 질의와 열쇠를 자리만큼 돌리는 회전 형태로 넘어가면서, 내적에는 자리의 차이만 남게 되었고 그림은 행과 열을 따로 돌린다. 한 소프트맥스는 평균 하나만 내므로 질의·열쇠·값을 여러 머리로 나눠 따로 읽고 이어 붙인다. 계산량과 파라미터는 머리 하나일 때와 같다. 여러 머리 어텐션과 토큰마다의 MLP 를 「층 정규화 → 어텐션이나 MLP → 잔차 더하기」로 감싼 트랜스포머 블록을 쌓되, 정규화를 어텐션·MLP 의 입력에 두면 깊이 쌓아도 워밍업 없이 학습된다. 질의를 그림 칸에서, 열쇠와 값을 글 토큰에서 만들면 크로스 어텐션이 되어 칸마다 필요한 낱말을 골라 읽는다. 한 토큰씩 이어 쓰는 모델은 뒤 토큰을 가려 앞 토큰의 열쇠와 값이 바뀌지 않게 하고, 그것을 KV 캐시에 적어 두어 스텝마다 새 토큰의 계산만 한다.
flowchart LR A["합성곱<br/>자리마다 정한 무게"] -->|"멀리 있는 칸을<br/>내용으로 못 고른다"| B["셀프 어텐션<br/>질의·열쇠로 비중, 값을 섞기"] B -->|"뒤섞어도<br/>같게 읽는다"| C["위치 인코딩<br/>사인 더하기 → 회전"] B -->|"소프트맥스 하나는<br/>평균 하나"| D["여러 머리 어텐션"] D --> E["트랜스포머 블록<br/>층 정규화 → 어텐션·MLP → 잔차"] C --> E E -->|"글을 읽어야 한다"| F["크로스 어텐션<br/>질의는 그림, 열쇠·값은 글"] E -->|"한 토큰씩 이어 쓴다"| G["마스크 + KV 캐시"]
정리 연습문제
물음. 지난 메시지 넷에 대한 어텐션 점수가 3, 3, 0, 0이다. 어텐션이 읽어 오는 값은 무엇인가?
- [ ] 점수가 3인 메시지 둘 가운데 하나의 값 〔틀림: 어텐션은 하나를 골라 오지 않는다. 점수가 같은 두 메시지가 비중을 거의 반씩 나눠 가진다.〕
- [x] 네 메시지의 값을 소프트맥스 비중대로 섞은 것. 점수 3인 둘이 거의 반씩 차지한다 〔맞음: 소프트맥스 비중으로 모두를 섞는다. 점수가 비슷한 토큰이 여럿이면 어느 토큰에도 없는 값을 읽어 온다.〕
- [ ] 네 메시지의 값을 똑같이 4분의 1씩 섞은 것 〔틀림: 점수 차이가 비중을 정한다. 점수 0인 두 메시지의 비중은 2%를 조금 넘을 뿐이다.〕
물음. 질의와 열쇠의 내적을 √d_k 로 나눈 뒤 소프트맥스를 씌운다. 나누는 목적은 무엇인가?
- [ ] 나누지 않는 편이 낫다. 점수가 클수록 확실하게 고른다 〔틀림: 처음부터 한 토큰으로 99.97%까지 쏠리면 그래디언트가 거의 사라져 학습이 나아가지 않는다.〕
- [x] 학습을 시작할 때 점수의 표준편차를 1로 맞춰, 비중이 처음부터 한 토큰으로 쏠리지 않게 한다 〔맞음: 쏠리지 않은 비중에서 출발해야 그래디언트가 살아 있다.〕
- [ ] 학습이 끝난 뒤에도 비중이 한 토큰으로 쏠리지 않게 막는다 〔틀림: 나누기는 성분이 서로 독립인 처음 상태에서 크기를 맞출 뿐이다. 학습이 만든 쏠림은 그대로 남는다.〕
물음. 폭이 같은 어텐션을 머리 하나에서 머리 여덟 개로 나눈다. 파라미터와 곱셈 수는 어떻게 되는가?
- [ ] 둘 다 여덟 배가 된다 〔틀림: 질의·열쇠·값 행렬을 머리 수로 자를 뿐이라 새 행렬이 생기지 않는다.〕
- [x] 둘 다 머리 하나일 때와 같다. 늘어나는 것은 소프트맥스(비중 분포)의 수다 〔맞음: 같은 행렬을 여덟 조각으로 나눠 쓰고, 조각마다 따로 비중을 매긴다.〕
- [ ] 파라미터는 같고 곱셈 수만 여덟 배가 된다 〔틀림: 머리 하나가 맡는 길이가 8분의 1로 줄어, 곱셈 수도 머리 하나일 때와 같다.〕
물음. 그림의 가로와 세로를 모두 두 배로 키워 칸 수를 늘렸다. 셀프 어텐션의 점수 표는 몇 배가 되는가?
- [ ] 두 배 〔틀림: 가로와 세로가 함께 두 배라 칸만 해도 네 배다.〕
- [ ] 네 배 〔틀림: 네 배가 되는 것은 칸 수다. 점수 표는 모든 칸 쌍의 점수를 담는다.〕
- [x] 열여섯 배 〔맞음: 칸이 네 배이고, 점수 표의 크기는 칸 수의 제곱이다.〕
물음. 크로스 어텐션에서 질의는 그림 칸에서, 열쇠와 값은 글 토큰에서 만든다. 글 토큰이 단 하나라면 그림 칸들은 무엇을 받는가?
- [ ] 칸마다 다른 벡터. 칸의 질의가 서로 다르기 때문이다 〔틀림: 질의가 달라도 읽을 토큰이 하나뿐이면 비중은 늘 그 토큰 하나에 모인다.〕
- [x] 모든 칸이 같은 벡터 〔맞음: 소프트맥스에 들어가는 점수가 하나라 비중이 언제나 1이다. 칸마다 다르게 읽으려면 글 토큰이 여럿이고 서로 달라야 한다.〕
- [ ] 아무것도 받지 못한다 〔틀림: 비중 1로 그 토큰의 값을 그대로 받는다.〕
물음. 한 토큰씩 이어 쓰는 언어 모델은 앞 토큰들의 열쇠와 값을 KV 캐시에 적어 두고 다시 쓴다. 다시 써도 되는 근거는 무엇인가?
- [x] 뒤 토큰을 가려 두어서, 토큰을 하나 더 붙여도 앞 토큰들의 열쇠와 값이 바뀌지 않는다 〔맞음: 작은 트랜스포머로 재면 마스크가 있을 때 앞 토큰 출력의 차이가 반올림 차이뿐이었다.〕
- [ ] 앞 토큰의 열쇠와 값은 조금 바뀌어도 결과에 큰 차이가 없다 〔틀림: 마스크가 없으면 토큰 하나를 붙였을 때 앞 토큰의 출력이 눈에 띄게 바뀌었다. 적어 둔 값은 바뀌지 않을 때만 다시 쓸 수 있다.〕
- [ ] 열쇠와 값은 토큰 내용과 상관없이 자리마다 정해져 있다 〔틀림: 열쇠와 값은 토큰마다 그 층의 은닉 상태에서 만든다.〕
막힌 곳
이제 그림의 칸들이 거리와 상관없이 서로를 읽고, 글 토큰까지 골라 읽게 할 수 있지만, 셀프 어텐션의 점수 표는 칸 수의 제곱으로 자랐다. Stable Diffusion 1.x 가 512 × 512 그림을 만들 때 가장 고운 단계의 칸이 4096개였던 것은, 그림을 가로세로 8배 줄인 64 × 64칸 위에서 일했기 때문이다. 픽셀마다 칸 하나로 두면 칸이 262,144개, 점수 표 하나에 687억 개가 넘는 점수가 들어간다. 그 64 × 64칸, 칸마다 수 4개인 그림은 어디서 왔을까? 그림을 작게 줄여 놓고 그 위에서 노이즈를 섞고 걷어 내도, 줄이기 전의 그림으로 되살릴 수 있을까?