LabHub
배우기 러닝패스 코스

트랜스포머 — 어텐션을 손으로 계산한다 · 토큰화와 어휘 · 실습

토크나이저를 손으로 만든다

LabHub 에서 이어서 보기

목표

바이트 수준 BPE 를 표준 라이브러리만으로 직접 만든다. UTF-8 바이트에서 출발해 인접 쌍을 세고, 가장 흔한 쌍을 합치는 규칙을 배우고, 그 규칙을 배운 순서대로 적용해 부호화한 뒤 원문으로 정확히 되돌린다. 마지막에 어휘 크기를 바꿔 가며 토큰 수가 줄어드는 곡선을 재고, 같은 내용의 한국어 문단과 영어 문단을 하나의 어휘로 부호화해 토큰 수를 나란히 놓는다.

왜 중요한가

요금도 문맥 한도도 단위가 토큰인데, 토큰은 글자도 낱말도 아니다. 어떤 조각을 하나로 셀지는 어휘를 만들 때 정해지고 어휘는 모델마다 다르다. 그래서 "글자 수에 얼마를 곱하면 된다" 는 어림은 언어가 바뀌는 순간 무너진다. 한글 음절 하나는 UTF-8 로 3바이트라, 어휘가 작으면 한 글자가 토큰 셋이 된다.
이 실습은 실제 모델의 토크나이저를 부르지 않는다. 이 파드에는 transformers·tokenizers·tiktoken 이 없고 numpy 도 시스템 파이썬에는 없다. 대신 같은 알고리즘을 손으로 만들고, 여러분이 만든 어휘로 잰 숫자만 쓴다. 그래서 "어느 모델은 이 문장을 몇 토큰으로 센다" 같은 말은 여기서 하지 않는다.
알고리즘 자체는 한 문장이다 — 가장 자주 붙어 다니는 둘을 하나로 합치는 일을 어휘가 원하는 크기가 될 때까지 되풀이한다. 어려운 것은 세부다. 겹치는 자리를 어떻게 셀지, 동점을 어떻게 깰지, 부호화할 때 규칙을 어떤 순서로 적용할지가 정해져 있지 않으면 같은 글로 돌려도 어휘가 매번 달라진다.
채점기는 여러분이 적어 둔 설명을 믿지 않는다. 여러분의 모듈을 실제로 불러 매번 다른 입력으로 함수를 직접 두드려 보고, 채점기가 따로 계산한 값과 대조한다. 입력은 실행마다 바뀌므로 값을 외워 넣을 수 없다.

단계

1. /root/work/tf-token/bpe.py 에 표본 문단 SAMPLE_KO·SAMPLE_ENto_ids(text)·from_ids(ids) 를 만드세요. 글을 UTF-8 바이트 목록으로 열고 다시 글로 되돌립니다.
2. count_pairs(ids) 를 더해 이웃한 두 개가 몇 번 붙어 나오는지 세게 하세요. 열쇠는 (앞, 뒤) 짝이고 겹치는 자리도 그대로 셉니다.
3. merge(ids, pair, new_id) 를 더해 그 짝이 나오는 자리를 새 번호 하나로 바꾸게 하세요. 왼쪽부터, 겹치지 않게 갑니다.
4. MIN_PAIR_COUNT = 2train(text, vocab_size) 를 만들어 병합 규칙을 배운 순서대로 모으게 하세요. 새 번호는 256부터 하나씩 올라갑니다.
5. encode(text, merges) 를 만들어 배운 순서 그대로 병합을 적용하게 하세요.
6. decode(ids, merges) 를 만들어 번호를 끝까지 풀고 원문으로 되돌리게 하세요. 어휘에 없던 글자가 섞여도 원문과 한 글자도 달라지면 안 됩니다.
7. vocab_curve(text, sizes) 를 만들어 어휘 크기마다 같은 글이 몇 토큰이 되는지 재게 하세요. 돌려주는 값은 (어휘크기, 토큰수) 짝의 목록입니다.
8. 어휘를 두 벌 배워 같은 두 문단을 재고, /root/work/tf-token/token_report.json/root/work/tf-token/token_report.md 에 결과를 기록하세요.

참고

단계 8개

  1. 글을 바이트로 연다
  2. 이웃한 둘을 센다
  3. 한 쌍을 하나로 합친다
  4. 병합 규칙을 배운다
  5. 배운 순서대로 부호화한다
  6. 한 글자도 다르지 않게 되돌린다
  7. 어휘를 키우면 토큰이 준다
  8. 어휘가 누구의 글로 만들어졌는가