LabHub
배우기 러닝패스 코스

트랜스포머 — 어텐션을 손으로 계산한다 · 문맥 길이와 비용 · 실습

문맥 길이의 비용을 직접 센다

LabHub 에서 이어서 보기

목표

곱셈을 세는 계수기를 만들어 문맥 길이 n 이 늘 때 무엇이 n 제곱으로 늘고 무엇이 n 에 비례해 느는지 직접 세어 확인한다. 두 몫을 나란히 놓은 표를 만들고, n 제곱 몫이 선형 몫을 따라잡는 교차점을 자기가 센 숫자로 찾는다. 인과 마스크가 남기는 점수가 n(n+1)/2 개뿐이라는 것, 점수 행렬을 통째로 들면 원소가 n 제곱 개라는 것, 한 토큰을 붙일 때 새로 생기는 점수는 줄 하나뿐이라는 것까지 정수로 센다.

왜 중요한가

"문맥 길이에 대해 제곱" 이라는 말은 반쪽만 맞다. 한 층 안에는 성질이 다른 두 계산이 섞여 있다. 어텐션의 점수와 섞기는 자리마다 문맥 전체를 훑어서 제곱으로 자라지만, 질의·열쇠·값 투영과 출력 투영과 피드포워드는 자리 하나하나에 똑같이 한 번씩 도는 일이라 자리 수에만 비례한다. 어느 쪽이 지배하는지는 길이와 모델 폭이 함께 정한다. 그래서 문맥 한도를 늘렸을 때의 비용을 하나의 배율로 어림하면 반드시 틀린다.
이 실습은 시간을 재지 않는다. 같은 코드도 기계와 부하에 따라 다르고 컨테이너 안에서는 더 흔들려서, 재어 봐야 견줄 수가 없다. 대신 곱셈 횟수를 센다. 횟수는 어디서 돌려도 같은 정수라 남에게 근거로 보여 줄 수 있다. 여기 나오는 숫자는 전부 여러분의 계수기가 센 값이고, 실제 모델의 초나 GB 는 재지 않으므로 쓰지 않는다.
모델 모양은 Attention Is All You Need 의 base 설정을 가정으로 쓴다 — D_MODEL = 512, D_FF = 2048, N_HEADS = 8. 이것은 이 실습이 정한 가정이지 여러분이 쓰는 모델의 값이 아니다.
채점기는 여러분이 적어 둔 설명을 믿지 않는다. 여러분의 모듈을 실제로 불러 매번 다른 크기로 함수를 두드려 보고, 계수기가 실제로 얼마나 올라갔는지까지 대조한다. 크기는 실행마다 바뀌므로 값을 외워 넣을 수 없다.

단계

1. /root/work/tf-cost/cost.py 에 상수 D_MODEL = 512·D_FF = 2048·N_HEADS = 8 과 계수기 MulCount, 그리고 그것을 쓰는 dot(a, b, ctr) 를 만드세요.
2. attn_scores(Q, K, ctr)·attn_mix(A, V, ctr)·quad_mults(n, d_model) 을 더해 n 제곱으로 자라는 몫을 세게 하세요.
3. matvec(M, x, ctr)·per_position_mults(d_model, d_ff, ctr)·linear_mults(n, d_model, d_ff) 를 더해 자리 수에 비례하는 몫을 세게 하세요.
4. cost_table(ns, d_model, d_ff) 를 만들어 길이마다 (n, n제곱 몫, 선형 몫, 합) 을 돌려주게 하세요.
5. crossover_n(d_model, d_ff) 를 만들어 n 제곱 몫이 선형 몫을 처음으로 따라잡는 길이를 찾게 하세요.
6. causal_pairs(n)wasted_pairs(n) 을 만들어 인과 마스크가 남기는 점수와 버리는 칸을 세게 하세요.
7. score_bytes(n, n_heads, itemsize)·max_context_for_bytes(budget_bytes, n_heads, itemsize)·append_pairs(n)·generate_pairs(n, g) 를 만드세요.
8. 위 함수들을 실제로 돌린 결과를 /root/work/tf-cost/cost_report.json/root/work/tf-cost/cost_report.md 에 기록하세요.

참고

무엇을 재지 않는가

시간을 재지 않습니다. 실제 모델의 GB 나 초도 쓰지 않습니다. 재어 보지 않은 숫자를 기록에 적으면 그 기록은 근거가 없습니다.

단계 8개

  1. 곱셈을 세는 자를 만든다
  2. n 제곱으로 자라는 몫
  3. 자리 수에만 비례하는 몫
  4. 두 몫을 나란히 놓는다
  5. 교차점을 찾는다
  6. 마스크가 버리는 절반을 센다
  7. 메모리와 한 줄씩 늘어나는 점수
  8. 센 숫자를 기록으로 남긴다