Query, Key, Value의 의미
Attention이 갑자기 어려워지는 순간
앞장에서 우리는 Self-Attention을 이렇게 이해했다. 문장 안의 각 토큰이 다른 토큰들을 바라보며, 누구를 얼마나 참고할지 정한다. 그리고 그 참고 비율에 따라 주변 토큰의 정보를 섞어 자기 표현을 새로 만든다.
여기까지는 꽤 자연스럽다. 그런데 Transformer 설명을 조금만 더 읽다 보면 갑자기 낯선 세 단어가 튀어나온다.
Query
Key
Value
처음 보면 데이터베이스 용어 같기도 하고, 검색 엔진 용어 같기도 하다. 더 당황스러운 것은 이 세 단어가 거의 항상 Q, K, V라는 약자로 등장한다는 점이다. 설명은 짧다. 입력 벡터 X에 세 개의 행렬을 곱해서 Q, K, V를 만들고, Q와 K를 곱해 Attention score를 구한 뒤, 그 결과로 V를 섞는다고 한다.
수식으로 쓰면 대략 이런 모양이다.
Q = XW_Q
K = XW_K
V = XW_V
Attention(Q, K, V) = softmax(QK^T / sqrt(d_k))V
처음 보는 사람에게는 거의 주문처럼 느껴진다. 하지만 걱정하지 않아도 된다. Q, K, V는 복잡한 마법 장치가 아니라 Attention을 더 유연하게 만들기 위한 역할 분담이다. 핵심은 아주 단순하다.
Query는 '내가 지금 찾고 싶은 것'이다. Key는 '내가 어떤 특징을 가지고 있는지 표시한 이름표'다. Value는 '실제로 전달할 내용물'이다.
이 세 문장만 붙잡고 있으면 된다. 이제 이 직관을 조금씩 수식과 연결해보자.

Query는 질문이고, Key는 이름표다
문장 속 어떤 토큰이 다른 토큰들을 참고하려고 한다고 해보자. 그 토큰은 막연히 아무 정보나 가져오지 않는다. 지금 자기 위치에서 필요한 정보를 찾으려 한다.
예를 들어 다음 문장을 보자.
고양이는 소파 위에서 잠을 잤고, 그것은 매우 편안해 보였다.
여기서 '그것은'이라는 토큰 주변의 표현은 앞에 나온 어떤 대상을 참고해야 한다. '그것'이 가리키는 대상은 무엇일까? 고양이일 수도 있고, 소파일 수도 있다. 사람에게는 문맥상 고양이가 더 자연스럽게 느껴진다. 모델도 비슷한 일을 해야 한다. '그것' 위치의 토큰은 앞에 있는 토큰들 중에서 자기에게 중요한 정보를 찾아야 한다.
이때 '그것'이 던지는 질문이 Query다.
'나는 지금 무엇을 찾고 싶은가?'
그리고 앞에 있는 각 토큰이 가진 검색용 이름표가 Key다.
'나는 이런 특징을 가진 토큰이다.'
'고양이는'이라는 토큰의 Key에는 생물, 주어, 앞서 등장한 대상 같은 정보가 담길 수 있다. '소파'의 Key에는 사물, 장소, 위에 있는 대상 같은 정보가 담길 수 있다. 물론 실제 모델 안에서 이런 단어가 직접 적혀 있는 것은 아니다. 벡터 공간 안에서 그런 방향과 패턴이 학습될 뿐이다.
중요한 것은 Query와 Key가 서로 비교된다는 점이다. '그것'의 Query가 찾는 특징과 '고양이'의 Key가 가진 특징이 잘 맞으면 관련도가 높다. 잘 맞지 않으면 관련도가 낮다.
그래서 Attention score는 Query와 Key를 비교해서 만든다.
score = Query · Key
여기서 가운데 점은 내적을 뜻한다. 내적은 두 벡터가 얼마나 비슷한 방향을 향하는지 재는 계산이다. 두 벡터가 비슷한 방향이면 값이 커지고, 서로 관련 없는 방향이면 값이 작아진다. 아주 단순하게 말하면, Query가 찾는 것과 Key가 내세우는 것이 잘 맞을수록 점수가 커진다.
Query와 Key의 내적은 왜 관련도가 되는가
내적을 조금 더 직관적으로 바라보자. 벡터는 여러 숫자의 묶음이다. 임베딩 장에서 보았듯이, 토큰 하나는 하나의 숫자가 아니라 여러 차원의 벡터로 표현된다. 각 차원은 모델이 학습한 어떤 특징을 담을 수 있다.
가상의 예를 들어보자. 실제 모델이 이렇게 해석 가능한 차원을 그대로 쓰는 것은 아니지만, 이해를 위해 단순화해보겠다.
그것의 Query가 다음과 같은 신호를 갖는다고 하자.
[앞에 나온 대상 필요, 주어 후보 필요, 생물일 가능성 높음]
그리고 각 토큰의 Key가 다음과 같다고 하자.
고양이 Key = [앞에 나온 대상, 주어, 생물]
소파 Key = [앞에 나온 대상, 장소, 사물]
잠 Key = [동작, 서술, 사건]
'그것'의 Query와 '고양이'의 Key는 여러 면에서 잘 맞는다. '앞에 나온 대상'이라는 점도 맞고, '주어 후보'라는 점도 맞고, '생물'이라는 점도 맞는다. 반면 '잠'은 동작에 가깝기 때문에 '그것'이 찾는 대상과는 잘 맞지 않는다.
벡터 내적은 바로 이런 맞물림을 숫자로 계산한다. 각 차원의 값끼리 곱하고 모두 더한다. 같은 특징이 강하게 켜져 있으면 곱한 값이 커진다. 여러 특징이 동시에 맞으면 전체 점수가 더 커진다.
실제 계산은 다음처럼 이루어진다.
score(i, j) = Q_i · K_j
여기서 Q_i는 i번째 토큰의 Query 벡터이고, K_j는 j번째 토큰의 Key 벡터다. 이 값은 i번째 토큰이 j번째 토큰을 얼마나 참고하고 싶은지를 나타낸다.
예를 들어 i가 '그것' 위치이고 j가 '고양이' 위치라면, score(그것, 고양이)는 '그것'이 '고양이'를 얼마나 봐야 하는지에 대한 점수다. j가 '소파'라면 score(그것, 소파)가 된다. 이렇게 모든 토큰 쌍에 대해 점수를 계산하면 Attention score 행렬이 만들어진다.
이 행렬의 각 행은 '한 토큰이 다른 토큰들을 바라보는 방식'을 담고 있다. '그것' 행에는 '고양이'를 얼마나 보는지, '소파'를 얼마나 보는지, '잠'을 얼마나 보는지가 들어 있다.
앞장에서 본 Attention 행렬이 바로 여기서 나온다. 다만 이번에는 입력 벡터끼리 바로 비교하는 것이 아니라, 입력에서 만들어낸 Query와 Key를 비교한다.
점수는 확률처럼 바뀐다
Query와 Key의 내적으로 얻은 점수는 아직 거칠다. 어떤 값은 12.3일 수도 있고, 어떤 값은 -4.8일 수도 있다. 이 값들을 그대로 정보 섞기에 쓰기는 어렵다. 그래서 Transformer는 softmax를 사용한다.
softmax는 여러 점수를 받아서 합이 1이 되는 비율로 바꾸는 함수다. 높은 점수는 더 큰 비율이 되고, 낮은 점수는 거의 0에 가까운 비율이 된다.
예를 들어 '그것'이 앞의 토큰들을 보는 점수가 다음과 같다고 하자.
고양이: 5.0
소파: 2.0
잠: 0.5
softmax를 거치면 대략 이런 느낌의 가중치가 된다.
고양이: 0.92
소파: 0.05
잠: 0.03
정확한 숫자는 예시일 뿐이지만, 의미는 분명하다. '그것'은 자기 표현을 새로 만들 때 '고양이'의 정보를 가장 많이 가져오고, '소파'와 '잠'은 조금만 참고한다.
여기서 한 가지 수식이 더 등장한다.
softmax(QK^T / sqrt(d_k))
왜 sqrt(d_k)로 나눌까? d_k는 Key 벡터의 차원 수다. 벡터 차원이 커지면 내적값도 커지기 쉽다. 내적값이 너무 커지면 softmax가 지나치게 한쪽으로 쏠릴 수 있다. 그러면 모델이 여러 정보를 부드럽게 비교하기보다, 특정 토큰 하나에만 과하게 집중하게 된다. 그래서 차원 크기에 맞춰 점수를 적당히 줄여준다. 이 과정을 스케일링이라고 부른다.
즉 QK^T / sqrt(d_k)는 Query와 Key의 관련도를 계산하되, 값이 너무 커지지 않도록 조절한 결과다.
Value는 실제로 가져오는 정보다
이제 가장 중요한 구분이 남았다. Query와 Key는 서로 비교해서 '어디를 볼지'를 정한다. 하지만 실제로 가져와서 섞는 정보는 Value다.
검색 상황을 떠올려보자. 우리가 도서관에서 책을 찾는다고 해보자. Query는 내가 검색창에 넣은 질문이다. Key는 각 책의 제목, 태그, 색인, 분류표 같은 검색용 정보다. 검색 시스템은 내 질문과 책의 이름표를 비교해 어떤 책이 관련 있는지 점수를 매긴다.
하지만 검색 결과를 클릭했을 때 실제로 읽는 것은 제목이나 태그가 아니다. 책의 본문이다. 그 본문에 해당하는 것이 Value다.
Attention에서도 마찬가지다. Query와 Key는 Attention weight를 만들기 위해 쓰인다. 그런 다음 그 weight로 Value들을 섞는다.
output_i = weight(i,1)V_1 + weight(i,2)V_2 + ... + weight(i,T)V_T
여기서 T는 문장 안의 토큰 수다. i번째 토큰은 모든 토큰의 Value를 조금씩 가져온다. 많이 봐야 하는 토큰의 Value는 큰 비율로 가져오고, 덜 중요한 토큰의 Value는 작은 비율로 가져온다.
앞의 예에서 '그것'이 '고양이'를 0.92만큼 본다면, '그것'의 새 표현에는 '고양이'의 Value가 강하게 섞인다. 이때 Value는 '고양이'라는 단어 자체가 아니라, '고양이' 토큰이 전달하고 싶은 정보 벡터다. 그 안에는 의미, 문법적 역할, 문맥 속 위치, 앞뒤 관계에 관한 정보가 압축되어 있을 수 있다.
정리하면 이렇다.
Query와 Key는 관련도를 계산하는 데 쓰인다.
softmax를 거친 관련도는 Attention weight가 된다.
Attention weight는 Value를 얼마나 섞을지 결정한다.
이 구분을 놓치면 Q, K, V가 모두 비슷한 벡터처럼 보인다. 하지만 역할은 다르다. Query는 찾는 쪽, Key는 찾아지는 쪽의 이름표, Value는 실제 전달되는 내용이다.
왜 굳이 셋으로 나눌까
앞장에서 우리는 Self-Attention을 단순하게 설명하기 위해 입력 벡터 X끼리 직접 비교하는 방식으로 생각했다. 그렇다면 의문이 생긴다. 그냥 X와 X를 비교하고, X를 섞으면 되지 않을까? 왜 굳이 X에서 Q, K, V를 따로 만들까?
이유는 역할이 다르기 때문이다. 같은 토큰이라도 '무엇을 찾는지', '어떻게 찾아질지', '무엇을 전달할지'는 서로 다를 수 있다.
사람의 대화에서도 비슷한 일이 일어난다. 내가 어떤 사람을 찾을 때는 '회의 내용을 잘 아는 사람'을 찾을 수 있다. 이때 내가 던지는 Query는 '회의 내용'이다. 그런데 그 사람이 자기소개서에 내건 Key는 '프로젝트 매니저', '고객 인터뷰 담당', '지난 회의 참석자'일 수 있다. 막상 그 사람에게서 얻고 싶은 Value는 '회의에서 결정된 일정'이다.
찾는 기준, 검색되는 이름표, 전달할 내용은 서로 연결되어 있지만 완전히 같지는 않다.
Transformer는 이 차이를 학습할 수 있게 한다. 입력 벡터 X에 서로 다른 선형 변환을 적용해 Q, K, V를 만든다.
Q = XW_Q
K = XW_K
V = XW_V
여기서 W_Q, W_K, W_V는 학습되는 가중치 행렬이다. 모델은 학습 과정에서 다음 토큰 예측에 도움이 되도록 이 행렬들을 조정한다.
W_Q는 입력에서 '찾고 싶은 특징'을 뽑아내는 방향으로 학습된다. W_K는 입력에서 '찾아질 때 사용할 특징'을 뽑아내는 방향으로 학습된다. W_V는 입력에서 '다른 토큰에게 전달할 내용'을 뽑아내는 방향으로 학습된다.
이 셋을 분리하면 모델은 훨씬 유연해진다. 어떤 토큰은 문법적 연결을 찾기 위해 Query를 만들고, 다른 토큰은 의미적 연결에 잘 걸리도록 Key를 만들 수 있다. 동시에 Value에는 실제로 다음 표현을 만드는 데 필요한 정보를 담을 수 있다.
Q, K, V 분리는 Attention을 단순한 유사도 비교에서 벗어나게 한다. 모델은 '무엇을 기준으로 찾을지'와 '무엇을 가져올지'를 따로 배울 수 있다. 이 차이가 Transformer의 힘을 만든다.
행렬 모양으로 보는 Q, K, V
이제 조금 더 수식에 가까이 가보자. 문장 하나가 토큰 T개로 이루어져 있다고 하자. 각 토큰은 d_model차원의 벡터로 표현된다. 그러면 입력 X의 모양은 다음과 같다.
X: (T, d_model)
예를 들어 토큰이 5개이고 각 토큰 벡터가 8차원이라면 X는 다음과 같은 모양이다.
X: (5, 8)
이제 X에 세 개의 가중치 행렬을 곱한다.
W_Q: (d_model, d_k)
W_K: (d_model, d_k)
W_V: (d_model, d_v)
그러면 Q, K, V의 모양은 다음과 같다.
Q: (T, d_k)
K: (T, d_k)
V: (T, d_v)
숫자를 넣어보면 더 쉽다. T = 5, d_model = 8, d_k = 4, d_v = 4라고 하자.
X: (5, 8)
W_Q: (8, 4) → Q: (5, 4)
W_K: (8, 4) → K: (5, 4)
W_V: (8, 4) → V: (5, 4)
이제 Q와 K를 곱해 Attention score를 만든다.
QK^T: (5, 4) × (4, 5) = (5, 5)
결과가 (5, 5)라는 점이 중요하다. 토큰이 5개이므로, 각 토큰이 다른 5개 토큰을 얼마나 볼지 나타내는 표가 생긴다.
행은 '보는 토큰'이고, 열은 '보이는 토큰'이다. 3번째 행 1번째 열의 값은 3번째 토큰이 1번째 토큰을 얼마나 참고하는지를 뜻한다.
그다음 softmax를 행마다 적용한다. 그러면 각 행의 합이 1이 된다.
Attention weights: (5, 5)
마지막으로 이 Attention weights를 V에 곱한다.
Attention weights × V: (5, 5) × (5, 4) = (5, 4)
출력은 (5, 4)가 된다. 즉 각 토큰마다 새롭게 섞인 4차원 표현이 만들어진다.
전체 흐름은 이렇게 볼 수 있다.
X
│
├─ XW_Q → Q ┐
├─ XW_K → K ├─ QK^T → softmax → Attention weights ┐
└─ XW_V → V ┘ ├─ weights × V → output
┘이 그림에서 눈여겨볼 점은 Q와 K가 먼저 만나서 '비율'을 만든다는 것이다. V는 그 비율이 정해진 뒤에 섞인다. 즉 Q와 K는 길 안내를 하고, V는 실제 짐을 싣고 이동한다.
간단한 문장으로 계산 흐름 따라가기
이번에는 아주 짧은 문장을 생각해보자.
나는 사과를 먹었다
토큰을 단순화해서 다음 네 개라고 하자.
나는 / 사과를 / 먹 / 었다
각 토큰은 임베딩을 거쳐 벡터가 된다. 여기에 위치 정보까지 더해진 뒤 Transformer 블록으로 들어간다. 이 입력을 X라고 하자.
이제 각 토큰에서 Q, K, V가 만들어진다. '먹'이라는 토큰의 입장에서 생각해보자. '먹'은 동작을 나타내므로 누가 먹었는지, 무엇을 먹었는지와 연결되어야 한다. 그래서 '먹'의 Query는 주어와 목적어에 해당하는 정보를 찾는 방향으로 만들어질 수 있다.
'나는'의 Key는 주어 역할을 하는 토큰이라는 특징을 가질 수 있다. '사과를'의 Key는 목적어 역할을 하는 토큰이라는 특징을 가질 수 있다. 그러면 '먹'의 Query는 '나는'과 '사과를'의 Key와 비교될 때 높은 점수를 얻을 수 있다.
점수는 softmax를 거쳐 가중치가 된다. 예를 들어 '먹'이 다른 토큰들을 보는 비율이 다음처럼 나올 수 있다.
나는: 0.35
사과를: 0.50
먹: 0.10
었다: 0.05
그러면 '먹'의 새 표현은 각 토큰의 Value를 이 비율대로 섞어서 만들어진다.
새로운 먹 표현 = 0.35 × V_나는 + 0.50 × V_사과를 + 0.10 × V_먹 + 0.05 × V_었다
이 표현은 단순히 '먹'이라는 단어만 담은 벡터가 아니다. 이제 '나는'이라는 주어와 '사과를'이라는 목적어의 정보가 섞인, 문맥화된 표현이다. 이 표현 덕분에 모델은 뒤이어 나올 토큰을 더 잘 예측할 수 있다.
예를 들어 다음 토큰을 예측해야 한다면, 모델은 '나는 사과를 먹었다'라는 문맥을 바탕으로 문장이 끝날지, 이어서 '그리고'가 나올지, '맛있었다'가 나올지 등을 판단할 수 있다. Self-Attention은 각 토큰이 문장 속 다른 토큰들과 관계를 맺게 만들어준다. Q, K, V는 그 관계 맺기를 정교하게 수행하는 장치다.
같은 입력에서 서로 다른 관점을 뽑아낸다
Q, K, V를 각각 다른 선형 변환으로 만든다는 말은 조금 추상적으로 들릴 수 있다. 하지만 핵심은 단순하다. 같은 사람도 상황에 따라 다른 정보가 중요해진다.
'사과'라는 단어를 생각해보자. 어떤 문맥에서는 과일이라는 의미가 중요하다. 어떤 문맥에서는 회사 이름 Apple과 구분해야 할 수도 있다. 또 어떤 문맥에서는 목적어인지, 주어인지 같은 문법적 역할이 중요하다.
입력 벡터 X에는 이런 가능성이 한꺼번에 들어 있다. 그런데 Attention 계산에서 필요한 역할은 하나가 아니다. 어떤 토큰이 다른 토큰을 찾을 때 사용할 표현이 필요하고, 다른 토큰에게 찾아질 때 사용할 표현도 필요하다. 그리고 실제로 전달할 정보도 필요하다.
그래서 모델은 X를 세 방향으로 투영한다. 투영이란 벡터를 다른 공간으로 옮겨 보는 일이다. 사진 한 장을 정면에서 볼 수도 있고, 옆에서 볼 수도 있고, 확대해서 볼 수도 있는 것처럼, 같은 입력 벡터도 다른 가중치 행렬을 통과하면 다른 관점의 표현이 된다.
W_Q를 통과한 표현은 질문하기 좋은 형태가 된다. W_K를 통과한 표현은 검색되기 좋은 형태가 된다. W_V를 통과한 표현은 전달되기 좋은 형태가 된다.
이때 '좋다'는 기준은 사람이 미리 정해주지 않는다. 모델은 대량의 텍스트를 보며 다음 토큰을 맞히는 방향으로 가중치를 조정한다. 그러다 보면 어떤 Attention head는 주어와 동사의 관계를 잘 잡고, 어떤 head는 가까운 단어를 잘 보고, 어떤 head는 긴 거리의 참조 관계를 잡는 식으로 역할이 나뉠 수 있다. 다음 장에서 다룰 Multi-Head Attention은 바로 이 가능성을 더 확장한 구조다.
Self-Attention에서 self의 의미 다시 보기
여기서 한 가지를 다시 확인하자. Self-Attention에서 self는 같은 입력 안에서 Q, K, V가 모두 나온다는 뜻이다. 즉 한 문장의 토큰들이 자기들끼리 서로를 본다.
입력 X에서 Q를 만들고, 같은 X에서 K를 만들고, 같은 X에서 V를 만든다.
Q = XW_Q
K = XW_K
V = XW_V
그래서 Self-Attention이다. 내가 가진 문장 안의 토큰들이 서로 질문하고, 서로 이름표를 내보이고, 서로 정보를 전달한다.
다른 종류의 Attention도 있다. 예를 들어 번역 모델의 일부 구조에서는 한쪽 문장에서 Query를 만들고, 다른쪽 문장에서 Key와 Value를 만들 수 있다. 영어 문장을 보며 한국어 문장을 생성할 때, 한국어 쪽 토큰이 영어 쪽 토큰들을 참고하는 식이다. 하지만 GPT 계열 모델에서 우리가 주로 다루는 것은 자기 자신의 이전 문맥을 보는 Self-Attention이다.
특히 GPT는 다음 토큰을 예측하는 모델이므로 미래 토큰을 보면 안 된다. 그래서 앞장에서 다룬 causal mask가 필요하다. Q와 K로 점수를 계산하더라도, 현재 위치보다 뒤에 있는 토큰의 점수는 막아야 한다. 그래야 모델이 정답을 미리 훔쳐보지 않는다.
예를 들어 나는 사과를 먹었다를 학습할 때 '사과를' 위치의 토큰이 뒤의 '먹었다'를 볼 수 있다면, 다음 토큰 예측 문제가 너무 쉬워진다. 실제 생성 상황에서는 아직 미래 토큰이 없기 때문이다. 따라서 GPT의 Self-Attention은 '자기 문장 안을 보되, 현재보다 앞쪽만 본다'는 제한을 가진다.
Q, K, V를 한 문장으로 정리하기
이제 Q, K, V의 역할을 다시 한 번 압축해보자.
Query는 각 토큰이 던지는 질문이다. '나는 지금 어떤 정보를 찾아야 하지?'라는 신호다.
Key는 각 토큰이 내거는 이름표다. '나는 이런 정보로 찾아질 수 있어'라는 신호다.
Value는 각 토큰이 실제로 전달하는 내용이다. '나를 참고한다면 이 정보를 가져가'라는 신호다.
Attention 계산은 이 세 역할을 순서대로 사용한다. 먼저 Query와 Key를 비교해 관련도 점수를 만든다. 그 점수를 softmax로 비율로 바꾼다. 마지막으로 그 비율에 따라 Value를 섞어 각 토큰의 새 표현을 만든다.
수식으로는 한 줄이다.
Attention(Q, K, V) = softmax(QK^T / sqrt(d_k))V
하지만 이 한 줄 안에는 꽤 풍부한 이야기가 들어 있다. 토큰 하나하나가 질문을 던지고, 다른 토큰들은 이름표를 내보이며, 선택된 정보들이 다시 섞여 새로운 문맥 표현을 만든다. LLM이 문장을 이어갈 때마다 이런 계산이 여러 층에서 반복된다.
이제 Transformer 설명에서 Q, K, V라는 글자를 만나도 겁먹을 필요가 없다. Q는 찾는 것, K는 찾아지는 기준, V는 가져오는 내용이다. 이 세 가지만 기억하면 Attention 수식은 더 이상 외계어가 아니다.
그리고 다음 단계가 기다리고 있다. 하나의 Attention만으로도 토큰들은 서로를 볼 수 있다. 하지만 문장에는 관계가 하나만 있는 것이 아니다. 같은 문장 안에서도 문법적 관계, 의미적 관계, 위치적 관계, 대명사 참조가 동시에 존재한다. Transformer는 이 여러 종류의 바라보기를 한 번에 수행하기 위해 Attention을 여러 개로 나눈다.
그 구조가 바로 Multi-Head Attention이다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.