Lesson 09는 측정 가능한 실패로 끝났습니다. 장난감 복사 과제(toy copy task)에서 GRU 인코더-디코더(encoder-decoder)는 길이 5에서는 89% 정확도(accuracy)를 보이지만, 길이 80에서는 거의 무작위 수준(chance)으로 떨어집니다. 그 이유는 학습 버그(training bug)가 아니라 구조 자체에 있습니다. 인코더가 모은 모든 정보가 하나의 고정 크기 은닉 상태(fixed-size hidden state)에 압축되어야 하고, 디코더는 그 이외의 것을 전혀 볼 수 없기 때문입니다.
바다나우(Bahdanau), 조(Cho), 벤지오(Bengio)는 2014년에 세 줄로 요약되는 해결책을 제시했습니다. 디코더에게 마지막 인코더 상태만 건네지 말고, 모든 인코더 상태를 그대로 유지합니다. 디코더의 각 단계(step)에서는 "지금 인코더 위치 i를 얼마나 봐야 하는가?"를 가중치(weight)로 계산하고, 그 가중치를 이용해 인코더 상태의 가중 평균을 만듭니다. 이 가중 평균이 바로 문맥(context)이며, 디코더 단계마다 새로 만들어집니다.
이것이 아이디어의 전부입니다. 트랜스포머(Transformer)는 이를 확장했습니다. 셀프 어텐션(self-attention)은 같은 시퀀스 안에서 어텐션을 적용했고, 멀티 헤드 어텐션(multi-head attention)은 이를 병렬로 수행했습니다. 그러나 이미 2014년 버전의 어텐션만으로 병목(bottleneck)은 깨졌고, 그 다음 트랜스포머로의 전환은 개념적 도약이라기보다 엔지니어링의 영역에 가깝습니다.
사전 테스트
2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요
1.기본 인코더-디코더(encoder-decoder)에서 고정 크기 은닉 상태(fixed-size hidden state)가 입력 시퀀스가 길어질수록 병목이 되는 이유는 무엇인가요?
2.어텐션(attention)의 쿼리-키-값(query-key-value) 프레임워크에서 쿼리(query)의 역할은 무엇인가요?
0/2 답변 완료
개념
디코더 단계 t마다 다음을 수행합니다.
이전 디코더 은닉 상태 s_{t-1}을 쿼리(query) 로 사용합니다.
이를 모든 인코더 은닉 상태 h_1, ..., h_T와 견주어 점수(score)를 매깁니다. 인코더 위치마다 스칼라(scalar) 하나가 나옵니다.
점수에 소프트맥스(softmax)를 적용해 합이 1이 되는 어텐션 가중치 α_{t,1}, ..., α_{t,T}를 얻습니다.
v_α의 형상은 (d_attn,)이고, v_α와의 내적(inner product)이 스칼라 점수로 축소됩니다. 이것이 v_α가 하는 일입니다. 어떤 마법이 아니라, 어텐션 차원 벡터를 스칼라 점수로 바꾸는 사영(projection)일 뿐입니다.
루옹(곱셈, multiplicative) 점수. 세 가지 변형이 있습니다.
dot: e_{t,i} = s_t^T * h_i. d_s == d_h가 강제되는 조건입니다. 인코더가 양방향이면 이 방식은 피하시기 바랍니다.
general: e_{t,i} = s_t^T * W * h_i이며, W의 형상은 (d_s, d_h)입니다. 차원이 같아야 한다는 제약이 사라집니다.
concat: 사실상 바다나우 형태입니다. 앞의 두 방식이 더 가볍기 때문에 거의 쓰지 않습니다.
바다나우 / 루옹에서 짚어야 할 한 가지 함정. 바다나우는 현재 단어를 생성하기 이전 디코더 상태인 s_{t-1}을 사용하고, 루옹은 생성한 이후 상태인 s_t를 사용합니다. 둘을 섞어 쓰면 기울기(gradient)가 미묘하게 어긋나 디버깅(debugging)이 매우 어려워집니다. 한 논문을 골랐다면 그 논문의 규약(convention)을 끝까지 따르시기 바랍니다.
각 함수가 세 줄 정도로 끝납니다. 이 단순함이 루옹 논문이 빠르게 자리 잡은 이유입니다. 대부분의 과제에서 정확도는 비슷하면서 코드는 훨씬 적습니다.
Step 3: 숫자로 따라가 보는 예시
세 개의 인코더 상태가 대략 "cat", "sat", "mat"를 나타낸다고 가정하고, 디코더 상태가 첫 번째 상태와 가장 잘 정렬되어 있다면, 어텐션 분포는 위치 0에 집중됩니다. 디코더 상태를 세 번째 인코더 상태와 정렬되도록 바꾸면 가중치는 위치 2로 이동하고, 문맥 벡터도 그 흐름을 따라갑니다.
첫 번째 행이 가장 큰 가중치를 얻습니다. 그런 다음 디코더 상태를 세 번째 인코더 상태에 가깝게 움직여보면, 가중치가 이동하는 것을 직접 관찰할 수 있습니다. 어텐션은 결국 명시적인 정렬(alignment)입니다.
Step 4: 트랜스포머로 이어지는 다리인 이유
위 설명을 Q/K/V 언어로 번역하면 다음과 같습니다.
쿼리(Query) = 디코더 상태 s_{t-1}
키(Key) = 인코더 상태들 (점수를 계산할 대상)
값(Value) = 인코더 상태들 (가중치를 곱해 합산할 대상)
고전적 어텐션에서는 키와 값이 같은 대상입니다. 셀프 어텐션은 둘을 분리해서, 하나의 시퀀스를 자기 자신에게 질의하게 만들고 K와 V에 서로 다른 학습된 사영을 적용합니다. 멀티 헤드 어텐션은 서로 다른 학습된 사영을 가지고 이 과정을 병렬로 수행합니다. 트랜스포머는 이 단계 전체를 여러 번 쌓고 RNN을 걷어내 버린 구조입니다.
수학은 동일합니다. 형상도 동일합니다. 바다나우 어텐션에서 스케일드 닷-프로덕트 어텐션(scaled dot-product attention)으로 넘어가는 교육적 도약은 대부분 표기(notation)의 변화에 지나지 않습니다.
이것이 트랜스포머의 어텐션 층(layer)입니다. 쿼리 배치는 5개 위치, 키/값 배치는 10개 위치, 각 벡터는 128차원이며 헤드(head)는 8개입니다. output은 문맥이 보강된 새 쿼리들이고, weights는 시각화 가능한 5x10 정렬 행렬(alignment matrix)입니다.
고전적 어텐션이 여전히 중요한 자리
교육 목적. 단일 헤드, 단일 층, RNN 기반 버전은 모든 개념을 눈으로 직접 확인할 수 있게 해줍니다.
트랜스포머가 들어가지 않는 온디바이스(on-device) 시퀀스 과제.
2014-2017년의 논문을 읽을 때. 바다나우의 규약을 모르면 잘못 읽기 쉽습니다.
기계 번역(machine translation, MT)에서의 세밀한 정렬(fine-grained alignment) 분석. 트랜스포머 모델에서도 원시 어텐션 가중치는 해석 도구로 쓰이며, 그 의미를 알아야 제대로 읽을 수 있습니다.
어텐션 가중치를 곧 설명으로 보는 함정
어텐션 가중치는 해석 가능해 보입니다. 위치별로 합이 1이고, 그래프로 그릴 수 있으며, 값이 크다는 것이 곧 "여기를 봤다"처럼 느껴집니다. 평가자들이 좋아할 만한 그림이기도 합니다.
하지만 보이는 것만큼 해석 가능하지는 않습니다. Jain과 Wallace(2019)는 일부 과제에서 어텐션 분포를 임의의 다른 분포로 바꾸어도 모델의 예측이 달라지지 않을 수 있음을 보였습니다. 어블레이션(ablation)이나 반사실(counterfactual) 검증 없이 어텐션 가중치를 추론의 근거로 제시하지 않도록 하시기 바랍니다.
산출물 만들기
outputs/prompt-attention-shapes.md로 저장합니다.
---
name: attention-shapes
description: Debug shape bugs in attention implementations.
phase: 5
lesson: 10
---
Given a broken attention implementation, you identify the shape mismatch. Output:
1. Which matrix has the wrong shape. Name the tensor.
2. What its shape should be, derived from (d_s, d_h, d_attn, T_enc, T_dec, batch_size).
3. One-line fix. Transpose, reshape, or project.
4. A test to catch regressions. Typically: assert `output.shape == (batch, T_dec, d_h)` and `weights.shape == (batch, T_dec, T_enc)` and `weights.sum(dim=-1) close to 1`.
Refuse to recommend fixes that silently broadcast. Broadcast-hiding bugs surface later as silent accuracy degradation, the worst kind of attention bug.
For Bahdanau confusion, insist the decoder input is `s_{t-1}` (pre-step state). For Luong, `s_t` (post-step state). For dot-product, flag dimension mismatch between query and key as the most common first-time error.
연습문제
쉬움. 인코더의 패딩 토큰(padding token)이 어텐션 가중치 0을 받도록 마스킹된 소프트맥스(masked softmax)를 구현합니다. 가변 길이(variable-length) 시퀀스가 섞인 배치(batch)에서 동작을 검증합니다.
중간. 루옹 general 형태에 멀티 헤드 어텐션을 추가합니다. d_h를 n_heads 그룹으로 나누고, 헤드별로 어텐션을 수행한 뒤 결과를 이어붙입니다(concatenate). 단일 헤드 경우가 이전 구현과 일치하는지 검증합니다.
어려움. Lesson 09의 장난감 복사 과제에 바다나우 어텐션을 붙인 GRU 인코더-디코더를 학습합니다. 시퀀스 길이별 정확도를 그래프로 그리고 어텐션이 없는 기준선(baseline)과 비교합니다. 길이가 길어질수록 격차가 벌어지는 것을 통해 어텐션이 병목을 풀어준다는 사실을 확인합니다.