
도해와 최소 사례로 직관적으로 이해하는 Self-attention, Cross-attention, Multi-head Attention
요약
Attention 메커니즘의 핵심인 Self-attention, Cross-attention, Multi-head Attention의 개념을 도해와 사례를 통해 설명합니다. NLP와 시계열 처리 태스크에서 각 메커니즘이 문맥 정보를 어떻게 추출하고 표현을 갱신하는지 다룹니다.
핵심 포인트
- Self-attention은 동일 시퀀스 내 토큰 간 상호작용을 통해 문맥을 구축합니다.
- Cross-attention은 서로 다른 시퀀스 간의 정보를 교환하여 활용합니다.
- Attention은 특정 토큰 처리 시 어떤 정보에 집중할지 결정하는 메커니즘입니다.
- Query, Key, Value 벡터 사영을 통해 가중치 합으로 출력을 생성합니다.

그림 1: Self-attention에서의 Query·Key·Value 생성, attention scores / weights 계산, Value의 가중치 합을 통한 출력 표현 생성 흐름
Attention은 다음 질문에 답하는 메커니즘이다.
자연어 처리 (NLP) 태스크의 경우: 어떤 토큰(단어)을 처리할 때 - 어떤 단어(자기 자신 포함)에 주의를 기울여야 하는가?
-
그리고 각각의 단어에 어느 정도 주의를 기울여야 하는가?
시계열 처리 태스크의 경우: 어떤 토큰(타임 스텝)을 처리할 때 - 현재의 타임 스텝에 유용한 정보를 포함하는 타임 스텝(현재의 타임 스텝 자신 포함)은 무엇인가?
-
그리고 각 타임 스텝이 이 현재의 타임 스텝에 어느 정도 영향을 미쳐야 하는가?
-
여기서 말하는 "처리"란, 현재 요소(단어 또는 타임 스텝)의 표현(representation)을 갱신하는 것을 의미한다.
-
얻어진 표현은 이후의 Transformer 층으로 입력되어 추가적인 변환이나 예측이 이루어진다.
Self-attention은 토큰이 동일한 시퀀스 내의 다른 토큰과 상호작용하여, 문맥을 고려한 자신의 표현을 구축할 수 있도록 한다.
Cross-attention은 어떤 시퀀스의 토큰이 다른 시퀀스로부터 정보를 가져올 수 있도록 한다.
이 두 가지 메커니즘은 많은 시퀀스 모델링(sequence modeling) 태스크에서 사용된다.
이하는 인코더-디코더(encoder-decoder)형 모델의 경우에 대한 예시이다.
| 태스크 | Self-Attention | Cross-Attention |
|---|---|---|
| 기계 번역 | 소스 문장의 문맥을 표현함 | 번역 생성 시 소스 정보를 가져옴 |
| 텍스트 요약 | 문서 전체의 문맥을 모델링함 | 요약 생성을 위해 문서 정보를 가져옴 |
여기서는 기계 번역에서의 계산 흐름을 보여준다.
영어 문장을 일본어로 번역하고 싶다고 가정하자.
I love machine learning
인코더-디코더형 번역 모델에서는 먼저 인코더가 self-attention을 사용하고, 그 후 디코더가 cross-attention을 사용하여 인코더의 출력에 접근한다.
Self-attention에서는 각 토큰이 **동일 시퀀스 내의 모든 토큰(자기 자신 포함)**을 참조하며, 자신의 표현을 갱신하기 위해 어떤 토큰이 가장 유용한지를 판단한다.
이하의 계산 목적은 토큰 love가 문장 전체를 이용하여 어떻게 자신의 문맥화된 표현을 구축하는지를 보여주는 것이다.
| 토큰 | 임베딩 (embedding) |
|---|---|
I | [1.0, 0.5] |
love | [0.8, 1.2] |
machine | [1.5, 0.7] |
learning | [0.6, 1.8] |
참고: 실제로는 임베딩 값은 학습을 통해 얻어진다. 여기서는 계산 흐름을 알기 쉽게 하기 위해 더미(dummy) 값을 사용하고 있다.
임베딩은 이하에서 $X$라고 표기한다.
각 토큰의 현재 표현은 Query, Key, Value 벡터로 사영(projection)된다.
Transformer 아키텍처에서 첫 번째 인코더 층으로의 입력은 토큰 임베딩에 위치 정보(positional information)를 더한 것이다. 하지만 이 예시에서는 단순화를 위해 위치 정보를 무시한다.
| 성분 | 계산 | 의미 |
|---|---|---|
| Query | $Q = X imes W_Q$ | 현재 토큰이 무엇을 찾고 있는가 |
| Key | $K = X imes W_K$ | 이 토큰이 어떤 내용을 가지고 있는지를 나타내는 기술자(descriptor)이며, 다른 토큰이 그것과의 관련성을 판단하기 위한 것 |
| Value | $V = X imes W_V$ | 해당 토큰에 주의가 기울여졌을 때 제공되는 정보 |
- 토큰 임베딩 행렬: $X$ (값은 위의 Step 1에 나타낸 것)
- 사영 행렬 (projection matrix):
W_Q =
\begin{bmatrix}
1.0 & 0.2 \\
...
W_K =
\begin{bmatrix}
0.6 & 0.1 \\
...
W_V =
\begin{bmatrix}
1.2 & 0.0 & 0.5 \\
...
참고: 실제로는 $X$와 사영 행렬의 값 모두 모델 학습 후에 얻어진다. 여기서는 이해를 돕기 위해 계산 과정을 보여줄 목적으로 더미 값을 사용하고 있다.
예를 들어, 토큰 love
의 경우, 계산 과정은 다음과 같다.
love
의 임베딩 (Embedding)은 다음과 같다:
x_{\text{love}} = [0.8,\ 1.2]
이 행 벡터를 각각의 사영 행렬 (Projection Matrix)에 곱한다.
love
의 Query (Q)
Q_{\text{love}} = x_{\text{love}} ⋅ W_Q
= [0.8,\ 1.2] ⋅
\begin{bmatrix}
...
love
의 Key (K)
K_{\text{love}} = x_{\text{love}} ⋅ W_K
= [0.8,\ 1.2] ⋅
\begin{bmatrix}
...
love
의 Value (V)
V_{\text{love}} = x_{\text{love}} ⋅ W_V
= [0.8,\ 1.2] ⋅
\begin{bmatrix}
...
모든 토큰에 대한 사영 후의 벡터:
| 토큰 | Q | K | V |
|---|---|---|---|
I | [1.05, 0.65] | [0.45, 0.60] | [1.10, 0.40, 0.65] |
love | [0.92, 1.24] | [0.12, 1.28] | [0.72, 0.96, 0.76] |
machine | [1.57, 0.93] | [0.69, 0.85] | [1.66, 0.56, 0.96] |
learning | [0.78, 1.74] | [-0.18, 1.86] | [0.36, 1.44, 0.84] |
love
의 Query:
Q_{\text{love}} = [0.92, 1.24]
각 Key와의 내적 (Dot Product):
\begin{aligned}
Q_{\text{love}} \cdot K_I &= 1.158 \\
Q_{\text{love}} \cdot K_{\text{love}} &= 1.6976 \\
...\n\end{aligned}
Raw Attention Score:
[1.158, 1.6976, 1.6888, 2.1408]
$\sqrt{d_k} = \sqrt{2}$로 스케일링 (Scaling) 한다:
Q와 K는 2차원 벡터이므로, $d_k = 2$이다.
[0.8188, 1.2004, 1.1942, 1.5138]
\begin{aligned}
softmax([0.8188, 1.2004, 1.1942, 1.5138])
&\approx [0.1688, 0.2472, 0.2457, 0.3383]
...\n\end{aligned}
보충: softmax는 가중치의 합이 1이 되도록 정규화 (Normalization) 하기 위한 것이다.
따라서 love
는
I
에는 아주 조금만 주의를 기울이고 -
- 자기 자신과
machine
에는 거의 비슷한 정도로 주의를 기울이며 -
learning
에 가장 강하게 주의를 기울인다.
이 예시에서는 learning
이 가장 큰 attention 가중치를 받으므로, love
의 업데이트된 표현 (Representation)에 가장 강력하게 기여한다.
Values:
\begin{aligned}
V_I &= [1.10, 0.40, 0.65] \\
V_{\text{love}} &= [0.72, 0.96, 0.76] \\
...\n\end{aligned}
위에서 계산한 attention 가중치 $[0.1688, 0.2472, 0.2457, 0.3383]$를 사용하여 가중합 (Weighted Sum)을 계산한다:
\begin{aligned}
&0.1688 \cdot [1.10, 0.40, 0.65] \\
&+ 0.2472 \cdot [0.72, 0.96, 0.76] \\
...\n\end{aligned}
love
의 임베딩
[0.8, 1.2]
으로부터, Attention 계산을 통해 love
의 다음 문맥 표현 (Contextual Representation)을 얻을 수 있다:
[0.893, 0.930, 0.818]
이 벡터에는 문장 전체의 정보가 포함되어 있으며, 이후의 처리에 활용될 수 있다.
인코더 (Encoder)가 소스 문장을 처리한 후, 디코더 (Decoder)는 번역 생성을 시작한다.
실제 Transformer 디코더(Decoder)에서는, cross-attention 이전에 이미 생성된 토큰에 대한 masked self-attention도 수행된다. 여기서는 cross-attention의 메커니즘에 초점을 맞추기 위해 그 부분은 생략한다.
디코더가 이미 다음과 같이 생성했다고 가정하자:
私は (나는)
여기서는 attention 메커니즘에 초점을 맞추기 위해, 이미 생성된 토큰이 어떻게 생성되었는지에 대해서는 다루지 않는다.
다음 토큰을 생성하기 위해, 디코더는 영어 문장으로부터의 정보가 필요하다.
이는 cross-attention을 통해 실현된다. 구조는 다음과 같다:
**Query $Q$**는 디코더로부터 온다 -
**Key $K$**와 **Value $V$**는 인코더로부터 온다
다시 말해, 디코더는 현재의 표현(representation)을 사용하여 인코더의 출력에 대해 질의(Query)를 수행하고, 다음 토큰을 예측하는 데 필요한 소스 정보를 가중치에 따라 가져온다.
인코더가 다음과 같은 표현을 생성했다고 가정한다.
| 인코더 토큰 | 인코더 출력 표현 벡터 |
|---|---|
I | [1.020, 0.910] |
love | [0.880, 1.020] |
machine | [1.140, 0.860] |
learning | [0.760, 1.150] |
여기서 보여주는 표현 벡터는 self-attention 연산의 가공되지 않은(raw) 출력 그 자체는 아니다.
실제로 디코더의 cross-attention이 이용하는 벡터는 인코더의 self-attention 출력을 그대로 사용하는 것이 아니라, 그 사이에 몇 가지 추가적인 처리가 이루어진다.
본 글에서는 설명을 간결하게 하기 위해 이 부분의 처리에 대해서는 다루지 않는다.
- 토큰
私は에 대한 현재 디코더 표현: $X_{\text{私は}} = [0.800, 1.500]$ - - cross-attention용 투영 행렬 (projection matrix):
W_Q =
\begin{bmatrix}
0.9 & 0.2 \\
...
W_K =
\begin{bmatrix}
0.5 & 0.1 \\
...
W_V =
\begin{bmatrix}
1.1 & 0.0 & 0.4 \\
...
참고: 앞서 언급했듯이, 실제로 이 값들은 모델의 학습 과정에서 학습된다. 여기서는 계산 과정을 쉽게 따라갈 수 있도록 설명용 더미(dummy) 값을 사용하고 있다.
\begin{aligned}
Q_{\text{私は}}
&= x_{\text{私は}} \cdot W_Q \\
...
\end{aligned}
위에서 보여준 바와 같이, 인코더의 출력은 다음과 같다.
| 인코더 토큰 | 인코더 출력 표현 벡터 |
|---|---|
I | [1.020, 0.910] |
love | [0.880, 1.020] |
machine | [1.140, 0.860] |
learning | [0.760, 1.150] |
- Key:
\begin{aligned}
K_I &= x_I \cdot W_K
= [1.020,0.910]
...
\end{aligned}
- Value:
\begin{aligned}
V_I &= x_I \cdot W_V
= [1.020,0.910]
...
\end{aligned}
\begin{aligned}
Q_{\text{私は}} \cdot K_I &= 1.6709 \\
Q_{\text{私は}} \cdot K_{\text{love}} &= 1.6830 \\
...
\end{aligned}
가공되지 않은 (raw) attention score:
[1.6709,\ 1.6830,\ 1.7060,\ 1.7302]
$\sqrt{2}$로 스케일링 (scaling):
[1.1815,\ 1.1901,\ 1.2063,\ 1.2234]
softmax([1.1815,1.1901,1.2063,1.2234])
\approx
[0.2453,\ 0.2474,\ 0.2515,\ 0.2558]
attention 가중치
[0.2453,\ 0.2474,\ 0.2515,\ 0.2558]
를 각 토큰의 Value
\begin{aligned}
V_I &= [0.940,\ 0.819,\ 0.590] \\
V_{\text{love}} &= [0.764,\ 0.918,\ 0.556] \\
...\n\end{aligned}
를 적용하여, 가중합 (weighted sum)을 계산한다.
\begin{aligned}
&0.2453 \cdot [0.940,0.819,0.590] \\
&+ 0.2474 \cdot [0.764,0.918,0.556] \\
...
\end{aligned}
가중합 (weighted sum)
[0.847,\ 0.887,\ 0.577]
은 현재 디코더 토큰 私は (나는)에 대한 cross-attention의 출력 벡터이다.
이 벡터는 디코더 토큰 私は에 대해, 소스 문장 I love machine learning으로부터 가중치에 따라 혼합된 정보를 나타낸다.
참고: $[0.847,\ 0.887,\ 0.577]$은 다음 일본어 단어 그 자체가 아니다.
- 이것은 토큰
私は에 대한 중간 벡터이며, 영어 문장의 관련 부분을 요약하고 있다. - 디코더는 이 벡터를 후속 레이어에서 사용하여 다음 토큰을 예측하는 데 활용한다.
- 간결함을 위해, 본 글에서는 다음 토큰을 예측하는 메커니즘에 대해서는 다루지 않는다.
Multi-head attention은 여러 개의 self-attention 또는 cross-attention 계산을 병렬로 실행하고, 그 결과를 결합함으로써 토큰 간의 다양한 관계를 포착할 수 있도록 하는 메커니즘이다.
위와 동일한 예시를 사용하여, self-attention 계산을 multi-head self-attention으로 확장한다.
cross-attention에서도 multi-head attention의 개념은 동일하다.
동일한 입력의 은닉 상태 (hidden state)를 사용하여 여러 attention 계산을 수행하지만, 각 헤드 (head)는 각각 서로 다른 학습된 투영 행렬 (projection matrix)을 사용하며, 그 결과를 마지막에 결합한다.
자연어에서는 특정 토큰의 의미가 여러 종류의 정보에 동시에 의존하는 경우가 있다.
I love machine learning이라는 문장에서 love라는 단어는 다음과 같은 것들과 관계를 맺을 수 있다.
learning(의미적 관계)I(문법적 주어)machine learning(주제가 되는 문맥)
단일 attention 계산에서는 이러한 정보들을 하나의 관점으로 묶어서 처리하게 된다.
multi-head attention에서는 모델이 문장을 여러 관점에서 동시에 볼 수 있어, 서로 다른 종류의 관계를 더 쉽게 포착할 수 있다.
각 헤드는 self-attention 섹션에서 설명한 것과 완전히 동일한 attention 계산 절차를 수행하지만, 서로 다른 투영 행렬을 사용한다.
만약 3개의 헤드를 사용한다면 다음과 같다:
(W_Q^{(1)},W_K^{(1)},W_V^{(1)})
(W_Q^{(2)},W_K^{(2)},W_V^{(2)})
(W_Q^{(3)},W_K^{(3)},W_V^{(3)})
따라서 각 헤드는 **각자 고유한 문맥 표현 (contextual representation)**을 생성한다.
토큰 love가 다음과 같은 출력을 생성한다고 가정하자.
헤드 1:
z_{\text{love}}^{(1)}=[0.893,0.930,0.818]
헤드 2:
z_{\text{love}}^{(2)}=[1.020,0.710,0.640]
헤드 3:
z_{\text{love}}^{(3)}=[0.640,1.210,0.580]
각 헤드는 문장 내의 서로 다른 관계를 포착하기 쉬워진다.
출력은 **결합 (concatenate)**되어 하나의 벡터가 된다.
\begin{aligned}
z_{\text{concat}} &= [0.893,0.930,0.818] \\
...
\end{aligned}
결과:
\begin{aligned}
z_{\text{concat}} = [&0.893,\ 0.930,\ 0.818,\ 1.020,\ 0.710,\ 0.640,\ 0.640,\ 1.210,\ 0.580]
...
\end{aligned}
3개의 헤드(head) 출력을 결합했기 때문에 차원이 증가한다.
결합된 벡터는 그 후 행렬 $W_O$를 사용하여 투영(projection)된다.
이 행렬의 값도 실제로는 학습을 통해 얻어지지만, 여기서는 계산을 이해하기 쉽게 보여주기 위해 더미(dummy) 값을 사용한다.
예:
W_O =
\begin{bmatrix}
0.40 & 0.00 & 0.00 \\
...
다음과 같이 계산한다.
\begin{aligned}
z_{\text{final}}
&= z_{\text{concat}} \cdot W_O \\
...
결과:
z_{\text{final}} = [0.8742,\ 0.9230,\ 0.6962]
최종 벡터
[0.8742,\ 0.9230,\ 0.6962]
는 토큰 love에 대한 multi-head attention의 출력이다.
이 벡터는 여러 개의 attention 헤드가 얻은 정보를 결합한 것이며, 각 헤드는 문장 내의 서로 다른 관계에 초점을 맞추기 쉽다.
이 표현은 이후의 처리에 이용된다.
- Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł., & Polosukhin, I. (2017). Attention Is All You Need. arXiv:1706.03762.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기