요약
- 트랜스포머는 토큰마다 벡터 한 줄씩 가진 (토큰 수 × d) 행렬을 블록 수십 개에 통과시키며, 모양은 그대로 두고 내용만 문맥에 맞게 고쳐 쓴다.
- 블록 하나 = 어텐션(토큰 사이에서 정보를 옮김) + FFN(토큰 하나 안에서 가져온 정보를 조합) + 잔차 연결 + LayerNorm.
- 텍스트는 안쪽 어디에서도 나오지 않는다. 맨 끝 출력층이 마지막 벡터를 사전 크기의 점수로 바꿀 때만 나온다.
본문
트랜스포머 동작 원리
https://www.youtube.com/watch?v=6s69XY025MU&ab_channel=%EC%9E%84%EC%BB%A4%EB%B0%8B
트랜스 포머 어텐션: 관계를 잘 반영해서 표현을 수정해감으로써 문제를 해결하는 딥러닝 방법
2017년에 발표되고 많은 기술들의 기반 기술로 돌아가고 있음
- 트랜스포머는 어텐션을 핵심 요소로 사용한다.
학습시킬때는 문장기준으로 단어들 사이의 상관관계를 찾고
출력을 내보낼땐 입력 토큰, 그리고 지금까지 나온 출력 토큰을 바탕으로 그 다음 토큰을 예측함
텐서 기초
- 정보 보존
- 어떤 정보를 표현하는 W 텐서에 어떤 값을 곱한 텐서 W1에는 W가 남아 있음
- weigthed sum
- N개의 텐서의 가중 평균(가중치의 합이 1인)은 정보들의 중간지점을 의미함
- 내적
- 서로 비슷한 값을 내적하면 값이 크고, 다르면 값이 작다
query, key, value
-
검색 상자에 입력하는 텍스트 Query
-
비디오 or 기사 제목으로 표시되는 결과가 key
-
그 안의 내용은 value
-
하나의 정보를 가진 query 텐서(query sequence)
-
N개의 키 텐서
- query 텐서와 N개의 키 텐서 각각에 대한 내적 진행
- 내적한 값을 정규화함(exp, )
입력 => 표현 변환 => 출력
표현 변환
- 관계 계산
- 추상화
전체 흐름 (2026-09-23 튜터링으로 정리)
텍스트 → 토크나이저 → 토큰 임베딩 + 위치 임베딩 → X (토큰 수 × d)
→ 블록 × N [LayerNorm → 셀프 어텐션 → (+) → LayerNorm → FFN → (+)]
→ 출력층: 마지막 벡터 → 사전 크기 점수 → 다음 토큰
1. 입력: 토큰마다 벡터 하나
- 토큰들이 벡터 하나로 합쳐지지 않는다. 임베딩 표에서 토큰마다 한 줄씩 꺼내 (토큰 수 × d) 행렬 X를 만든다.
2. 어텐션: 관련도를 재고, 그 비율대로 섞는다
- Q = 내가 찾는 것, K = 각 토큰의 이름표, V = 찾았을 때 건네줄 내용. K와 V를 나누는 이유는 "찾게 만드는 특징"과 "건네줄 내용"이 다를 수 있어서다.
- Q·Kᵀ → softmax → 비율 행렬 (토큰 수 × 토큰 수). d와 무관하다.
- 비율 · V → 각 토큰 벡터가 다른 토큰 V의 가중 평균으로 업데이트된다. 출력은 새 토큰이 아니라 같은 토큰들의 업데이트된 벡터이고 모양은 입력과 같다.
- 계산 과정은 Transformer에서 self attention 계산 과정에 자세히 있다.
3. 어텐션은 순서를 모른다 → 위치 임베딩
- 비율은 Q와 K의 내용으로만 정해지므로 토큰 순서를 섞어도 각 토큰의 결과가 같다. "dog bites man"과 "man bites dog"를 구분하지 못한다.
- 그래서 1단계와 2단계 사이에 자리마다 위치 벡터를 더한다. 같은 dog라도 자리가 다르면 벡터가 달라지고 Q·K도 달라진다.
- 방식: 사인파 고정값(원조 트랜스포머, Whisper 인코더) / 학습형 표(GPT-2, Whisper 디코더) / RoPE(Q·K를 위치만큼 회전, Llama 등).
- Whisper 디코더가 최대 448토큰인 건 학습형 위치 표가 448줄이라서다.
4. FFN: 토큰마다 따로 가공한다
- 어텐션은 섞기(가중 평균)만 한다. 섞인 정보에서 새 의미를 뽑으려면 비선형 변환이 필요하다.
- 구조: d → 4d → GELU → d. 모든 토큰에 같은 가중치를 각자 따로 적용하고, 토큰끼리는 섞지 않는다.
- 블록당 파라미터가 어텐션 4d², FFN 8d²라서 블록 파라미터의 약 3분의 2가 FFN이다.
- 어텐션 = 회의(정보 주고받기), FFN = 자리로 돌아가 각자 생각하기.
5. 잔차 연결과 LayerNorm
x = x + 어텐션(LN(x)),x = x + FFN(LN(x)). 결과로 갈아치우지 않고 수정분만 더해서 원래 정보를 보존하고, 깊게 쌓아도 학습이 버틴다.- LayerNorm은 각 부품에 들어가기 전에 값 크기를 맞춘다(pre-norm, Whisper 방식).
- 입력과 출력 모양이 같아서 블록을 몇 개든 쌓을 수 있다.
6. 문맥 임베딩: 같은 단어가 문맥마다 다른 벡터가 된다
| 문장 | 처음 "먹었다" | 어텐션으로 섞인 것 | FFN 후 의미 |
|---|---|---|---|
| 밥을 먹었다 | 같음 | 밥 | 식사했다 |
| 욕을 먹었다 | 같음 | 욕 | 비난받았다 |
| 겁을 먹었다 | 같음 | 겁 | 무서워졌다 |
- 어텐션을 빼고 FFN만 남기면 세 "먹었다"는 끝까지 똑같다. 옆 토큰을 볼 통로가 없기 때문이다.
- word2vec 같은 이전 방식은 단어마다 벡터가 하나로 고정이라 이걸 구분하지 못했다.
7. 인코더와 디코더
- 인코더: 모든 토큰이 앞뒤를 전부 본다. Whisper는 30초 오디오를 1500 × 1280으로 만든다. → Transformer에서 encoder는 입력을 추상화한다.
- 디코더: causal mask로 자기와 앞 토큰만 본다. 뒤쪽 점수를 softmax 전에 -∞로 만들어 비율이 0이 되게 한다. 생성 땐 뒤 토큰이 없고, 학습 땐 정답을 베끼지 못하게 하려는 것이다. → Encoder에서 self attention 계산시 Lower Triangular를 이용해 인과적 구조로 예측가능한 트랜스포머 구조를 만든다.
- 크로스 어텐션: Whisper 디코더 블록은 셀프 어텐션 → 크로스 어텐션 → FFN. 크로스 어텐션은 Q를 디코더에서, K·V를 인코더 출력에서 가져온다.
- GPT·Llama는 디코더만 있고, 프롬프트를 같은 줄의 앞쪽 토큰으로 넣는다.
8. 헷갈렸던 것
- "FFN이 가공한다" ≠ 텍스트 출력. FFN 출력도 d차원 벡터다. 텍스트는 마지막 출력층에서만 나온다(Whisper large-v3 사전 51,866개).
- 토크나이저는 맨 처음 한 번 글자를 자르기만 하고 의미를 가공하지 않는다.
다음에 볼 것: KV 캐시
- causal mask 때문에 새 토큰이 붙어도 과거 토큰의 K·V는 바뀌지 않는다 → 저장해 두고 새 토큰 것만 계산하면 된다.
- 크로스 어텐션 K·V는 인코더 출력에서 오므로 디코딩 내내 고정이다.
관련 노트
- Transformer에서 self attention 계산 과정
- Transformer에서 encoder는 입력을 추상화한다.
- Encoder에서 self attention 계산시 Lower Triangular를 이용해 인과적 구조로 예측가능한 트랜스포머 구조를 만든다.
- Whisper 음성 처리와 최적화 방식
- LoRA는 Transformer의 Attention 레이어에 주로 적용된다
참고
- https://www.youtube.com/watch?v=6s69XY025MU
- 논문: Vaswani et al., "Attention Is All You Need" (2017) — https://arxiv.org/abs/1706.03762
- https://github.com/openai/whisper/blob/main/whisper/model.py — 인코더 사인파·디코더 학습형 위치 임베딩, MLP 4배+GELU, pre-norm, causal mask, 크로스 어텐션
- https://huggingface.co/openai/whisper-large-v3/blob/main/config.json — d_model 1280, 32+32레이어, ffn 5120, 최대 448토큰, 사전 51,866
함께 읽기 좋은 글
- Encoder에서 self attention 계산시 Lower Triangular를 이용해 인과적 구조로 예측가능한 트랜스포머 구조를 만든다.
- Whisper large-v3에서 beam search는 greedy보다 정확도 이득이 거의 없다
- faster-whisper large-v3는 greedy + VAD + 이어받기 끔이 가장 빠르면서 정확도도 뒤지지 않는다
- faster-whisper 결과가 실행마다 달라지는 건 temperature fallback 샘플링이 이전 텍스트 이어받기로 번지는 탓으로 보인다
- Whisper에 numpy 배열을 넘기면 리샘플 없이 16kHz로 간주한다