English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

게스트
1 / ?
수업 목록으로

쿼리, 키, 값

동일한 입력으로부터의 세 가지 선형 매핑

임베딩(활동 4) 후, 각 위치는 768차원 벡터 x_t를 운반합니다. 어텐션은 x의 세 가지 서로 다른 프로젝션을 생성하는 것으로 시작합니다:


Q (쿼리): 이 위치가 알고 싶은 것은 무엇인가?


K (키): 이 위치가 다른 위치에 제공하는 것은 무엇인가?


V (값): 주의를 받으면 이 위치가 전달하는 내용은 무엇인가?


각 투영은 학습된 가중치 행렬에서 나온다:


Q = x · W_Q     # W_Q shape: (d_model, d_k)
K = x · W_K     # W_K shape: (d_model, d_k)
V = x · W_V     # W_V shape: (d_model, d_k)

백프로퍼게이션을 통해 훈련되는 세 개의 행렬. 모델은 학습합니다: 이 위치에서 어떤 쿼리가 유용한 과거 맥락을 가장 잘 검색할까? 이 위치의 내용을 잘 광고하는 키는 무엇일까? 선택되었을 때 어떤 값을 전달할까?


Scaled dot-product attention


도서관 비유

도서관 카드 카탈로그를 상상해 보세요. 특정 주제(query)를 염두에 두고 들어갑니다. 모든 카드에는 키워드(key)가 나와 있습니다. 주제가 카드의 키워드와 일치하면 책 내용(value)을 가져옵니다. Attention은 모든 토큰에 대해 병렬로 이 작업을 수행합니다: 모든 위치가 다른 모든 위치를 쿼리하고, 정렬을 랭킹하며, 값 벡터의 가중 조합을 검색합니다.


ANDREA-120M 차원


수량비고
d_model768위치마다의 벡터 크기
n_head12병렬 어텐션 헤드
d_k64헤드당 차원 (= d_model / n_head)
T1024컨텍스트 길이

d_k = d_model / n_head = 768 / 12 = 64. 각 헤드는 전체 768차원 공간의 64차원 부분을 봅니다. Activity 6 (grow_a_language_model_multi_head)에서 헤드당 분할을 자세히 다룹니다.

d_k 계산하기

두 ANDREA 변형에 대해 d_k를 계산하세요. (a) ANDREA-12M: d_model = 384, n_head = 12. (b) ANDREA-480M: d_model = 1536, n_head = 24. 각 경우에 대해 공식 d_k = d_model / n_head를 보여주세요.

왜 sqrt(d_k)로 나누는가

점수 행렬

Q와 K가 존재하면(각각 shape (T, d_k)), 어텐션은 점수 행렬을 계산합니다:


scores = Q · K^T     # shape: (T, T)

scores[i, j] = 위치 i의 쿼리가 위치 j의 키와 얼마나 강하게 정렬되는지. 모든 (i, j) 쌍마다 하나의 점수: 1024 × 1024 = 1,048,576 scores per attention head per forward pass.


왜 나누는가

두 개의 무작위 d차원 단위 벡터의 내적은 크기가 sqrt(d) 정도입니다. 스케일링 없이, scores는 d_k와 함께 증가합니다:


- d_k = 64: 일반적인 내적 값은 8 정도의 크기.

- d_k = 256: 일반적인 내적 값은 16 정도의 크기.

- d_k = 4096: 일반적인 내적 값은 64 정도의 크기.


큰 점수들은 뾰족한 softmax를 생성합니다 (한 위치가 지배하고, 다른 곳에서 그래디언트가 사라짐). 학습이 멈춥니다. 스케일링이 크기를 수정합니다:


scaled_scores = (Q · K^T) / sqrt(d_k)

ANDREA-120M의 경우, sqrt(d_k) = sqrt(64) = 8입니다. 모든 점수가 8로 나누어집니다. d_k에 관계없이 크기가 대략 단위 스케일로 유지됩니다. Softmax가 잘 작동합니다. 그래디언트가 흐릅니다.


Vaswani의 원래 정당화

Attention Is All You Need (2017)에서: 'd_k의 값이 클 때, 내적의 크기가 커져 softmax 함수를 극히 작은 그래디언트가 있는 영역으로 밀어붙입니다.' sqrt(d_k) 나눗셈이 그 성장을 상쇄합니다.


코드 뷰

microgpt_cuda.cu 내부에서 이 스케일링은 리터럴 나눗셈으로 나타납니다:


scores[i][j] = dot(Q[i], K[j]) * (1.0f / sqrtf(d_k));

각 점수당 하나의 부동소수점 곱셈. 저렴함. 중요함.

d_model = 4096에서의 스케일링

연구팀이 d_model = 4096 & n_head = 32로 ANDREA-2B를 구축했다고 가정하세요. (a) d_k를 계산하세요. (b) sqrt(d_k)를 계산하세요. (c) 팀이 이 규모에서 sqrt(d_k)로 나누는 것을 잊어버리면 어떤 일이 일어날지 한 문장으로 설명하세요.

위치 i가 위치 j > i를 볼 수 없는 이유

생성에서 비롯된 제약

ANDREA는 한 번에 하나의 토큰을 생성합니다. 추론 시, 위치 0에서 첫 번째 토큰을 생성한 후, 위치 1에서 위치 0의 출력을 보고 두 번째 토큰을 생성하며, 이런 식으로 진행됩니다. 모델은 생성 중에 미래 토큰에 절대 접근할 수 없습니다.


훈련도 이를 반영해야 합니다. 훈련 중 위치 5가 위치 6에 주의를 기울일 수 있다면, 모델은 단축경로를 학습하게 됩니다: '토큰 6을 토큰 6을 읽음으로써 예측하라'. 추론 시 이 단축경로는 사라집니다(토큰 6이 아직 존재하지 않음). 모델의 훈련 대 추론 행동이 치명적으로 분기될 것입니다.


마스크

인과적 마스크는 위치 i에서 위치 j > i로의 주의를 차단합니다. 구현: j > i인 모든 곳에서 scaled_scores[i][j] = -infinity로 설정. 소프트맥스 후 해당 항목들은 exp(-inf) = 0이 됩니다. 마스크는 미래 위치에 대한 주의를 깔끔하게 0으로 만듭니다.


for i in range(T):
for j in range(T):
if j > i:
scaled_scores[i][j] = -1e9   # 사실상 -inf

소프트맥스(행별) 적용 후, 각 행의 합은 1이 되지만, [0, i] 항목만 확률 질량을 가집니다. 위치 i는 과거 위치의 정보만 혼합합니다.


마스크 시각화

마스크가 적용된 점수 행렬의 형태 (T, T)는 하삼각 구조처럼 보입니다:


마스크 적용 후 scaled_scores, 행별 softmax:

행 0:  [1.0, 0,   0,   0,   ...]   # 자신만 봄
행 1:  [0.4, 0.6, 0,   0,   ...]   # 위치 0, 1을 봄
2행:  [0.2, 0.3, 0.5, 0,   ...]   # 0, 1, 2를 봄
3행:  [0.1, 0.2, 0.3, 0.4, ...]   # 0, 1, 2, 3을 봄
...

행당 엄격한 하삼각 확률 분포. 미래는 보이지 않음.


왜 Decoder-Only Transformer가 이것을 필요로 하는가

ANDREA, GPT, LLaMA와 같은 디코더 전용 모델들은 모두 하나의 목표를 공유합니다: 과거로부터 다음 토큰을 예측하는 것. 인과 마스크는 이 목표를 병렬로 훈련 가능하게 만듭니다: 모든 위치가 동시에 자신의 다음 토큰 예측을 계산하며, 어떤 위치도 앞을 들여다보는 치트 없이요.

마스크 & 맛

Activity 2 (intro)에서는 세 가지 트랜스포머 맛을 다루었습니다: 인코더 전용, 인코더-디코더, 디코더 전용. (a) 어떤 맛이 인과 마스크를 사용하나요? (b) 다른 맛(인코더 전용, BERT처럼)이 인과 마스크를 사용하지 않는 이유를 한 문장으로 설명하세요. (c) 마스크가 없는 인코더는 대신 어떤 목표로 훈련하나요?

점수에서 출력으로

소프트맥스: 점수에서 확률로

마스킹되고 스케일링된 점수는 여전히 실수 범위에 있습니다. 소프트맥스는 각 행을 확률 분포로 변환합니다:


A[i][j] = exp(scaled_scores[i][j]) / sum_k exp(scaled_scores[i][k])

세 가지 속성이 결과로 나타납니다:


- 모든 (i, j)에 대해 A[i][j] >= 0.

- 모든 행 i에 대해 sum_j A[i][j] = 1.

- 더 큰 원시 점수는 더 큰 확률을 생성 (단조 증가).


행 i의 확률 벡터는 모델에게 알려줍니다: 출력 계산 시 위치 i가 각 이전 위치에 얼마나 주의를 기울여야 하는가?


가중 V 합계

위치 i에 대한 최종 어텐션 출력:


output[i] = sum_j A[i][j] · V[j]

각 값 벡터 V[j]는 어텐션 확률 A[i][j]로 가중되고, 그 후 합산됩니다. 위치 i의 출력은 모든 이전 위치의 값 벡터를 관련성에 따라 가중하여 결합한 것입니다.


행렬 형태로, 한 번에 모든 위치:


Attention(Q, K, V) = softmax(mask(Q · K^T / sqrt(d_k))) · V

한 줄. 전체 어텐션 메커니즘. Vaswani 등은 2017년에 그 줄을 썼습니다; 트랜스포머는 그 이후로 근본적으로 변하지 않았습니다.


헤드당 출력 형태

하나의 어텐션 헤드 출력: 형태 (T, d_k). ANDREA-120M의 경우: (1024, 64). 12개의 헤드가 병렬로 계산; 출력이 (1024, 768)으로 연결되어 최종 선형 투영(W_O)으로 전달된 후, 트랜스포머 블록의 MLP로 이어짐.


Activity 6 (grow_a_language_model_multi_head)는 멀티헤드 분할을 다룸. Activity 7 (grow_a_language_model_transformer_block)은 어텐션 주변의 모든 것(잔차 연결, 레이어 정규화, MLP)을 다룸.

파이프라인 종합

전체 어텐션 파이프라인을 자신의 말로 종합하세요. 입력 벡터 x_5(예: 시퀀스의 5번째 위치)에서 어텐션 출력[5]까지 단일 위치 i에 일어나는 과정을 설명하세요. 네 가지 연산을 순서대로 명명: (1) Q/K/V로 투영, (2) 모든 위치에 대한 스케일된 점수 계산, (3) 인과 마스크 + softmax 적용, (4) 확률로 가중된 V 벡터 합산. 한 단락으로.