LabHub
배우기 러닝패스 코스

트랜스포머 — 어텐션을 손으로 계산한다 · 회전 위치 임베딩(RoPE) · 실습

위치를 회전으로 넣는다

LabHub 에서 이어서 보기

목표

회전 위치 임베딩(RoPE)을 표준 라이브러리만으로 직접 만든다. 짝수 차원을 두 개씩 쌍으로 묶어 쌍마다 다른 속도로 자리만큼 돌리고, 그렇게 돌린 질의와 키의 내적이 두 자리의 차이에만 의존한다는 것을 숫자로 확인한다. 더하는 방식(절대 위치 인코딩)을 나란히 만들어 같은 간격에서 값이 흔들리는 것을 견주고, 회전이 길이를 바꾸지 않는다는 것과 거리가 멀어질 때 어느 성분이 남는지를 잰다.

왜 중요한가

자리 벡터를 더하면 내적을 펼쳤을 때 q·P[n]P[m]·k 처럼 한쪽 자리만 든 항이 남는다. 그 항들은 차이로 묶이지 않으므로, 간격이 똑같아도 문장 앞쪽에서 잰 값과 뒤쪽에서 잰 값이 달라진다. 언어에서 중요한 것은 대개 몇 칸 앞의 낱말인가인데 점수에는 절대 자리가 섞여 들어와 있는 것이다.
회전은 그 문제를 연산 자체로 푼다. 두 벡터를 같은 방향으로 같이 돌리면 사이 각이 변하지 않으므로, 각각 제 자리만큼 돌린 뒤 내적하면 값이 차이에만 의존한다. 이것은 근사가 아니라 등식이고, 그래서 숫자로 확인할 수 있다.
이 실습은 모델을 부르지 않는다. 이 파드의 시스템 파이썬에는 numpy 가 없고 인터넷도 없다. math 만으로 만들고, 여기서 잰 숫자만 쓴다. 그래서 "어느 모델이 어떤 밑을 쓴다" 같은 말은 여기서 하지 않는다.
채점기는 여러분이 적어 둔 설명을 믿지 않는다. 여러분의 모듈을 실제로 불러 매번 다른 차원과 자리로 함수를 두드려 보고, 채점기가 따로 계산한 값과 허용 오차 안에서 대조한다. 입력은 실행마다 바뀌므로 값을 외워 넣을 수 없다.

단계

1. /root/work/tf-rope/rope.pyDIM = 64·THETA_BASE = 10000.0·demo_vectors()·dot(a, b)·thetas(d, base=THETA_BASE) 를 만드세요. thetas 는 쌍마다 다른 회전 속도를 돌려줍니다.
2. rotate_pair(x0, x1, angle) 를 더해 평면 위의 점 하나를 angle 라디안만큼 반시계로 돌리게 하세요.
3. apply_rope(vec, pos, base=THETA_BASE) 를 더해 벡터를 쌍으로 묶고 각 쌍을 pos * theta_i 만큼 돌린 새 벡터를 돌려주게 하세요.
4. rope_score(q, k, m, n, base=THETA_BASE) 를 만들어 m 번 자리의 질의와 n 번 자리의 키를 각각 돌린 뒤 내적하게 하세요.
5. sin_pos(pos, d, base=THETA_BASE)add_score(q, k, m, n, base=THETA_BASE) 를 만들어 더하는 방식의 같은 점수를 재게 하세요.
6. offset_scan(q, k, offset, starts) 를 만들어 같은 간격을 여러 시작 자리에서 재게 하세요. 돌려주는 값은 (시작자리, 회전 점수, 더하는 점수) 짝의 목록입니다.
7. turns(d, delta, base=THETA_BASE)slow_pairs(d, delta, base=THETA_BASE) 를 만들어 간격마다 쌍이 몇 바퀴를 도는지, 아직 한 바퀴를 안 넘긴 쌍이 몇 개인지 재게 하세요.
8. 잰 값을 /root/work/tf-rope/rope_report.json/root/work/tf-rope/rope_report.md 에 기록하세요.

참고

단계 8개

  1. 쌍마다 다른 회전 속도
  2. 평면 위에서 한 번 돌린다
  3. 벡터를 자리만큼 돌린다
  4. 돌린 질의와 키의 점수
  5. 더하는 방식을 나란히 둔다
  6. 같은 간격이면 같은 점수다
  7. 멀어지면 어느 쌍이 남는가
  8. 잰 것을 기록으로 남긴다