-
LLM Tokenization 방법 정리 (BytePair, Byte-level BPE, WordPiece, Unigram, SentencePiece)AI/NLP 2024. 4. 22. 10:25728x90
LLM Tokenization 방법 정리
(BytePair, Byte-level BPE, WordPiece, Unigram, SentencePiece)- Tokenization이란
- input text sequence를 Token이라는 더 작은 부분으로 변환하는 과정이다
- 가장 단순한 Tokenization 방법은 공백을 기준으로 나누는 거겠지만, 이는 OOV(out of vocabulary) 문제를 일으킨다
- 이 문제를 해결하기 위해 Subword 기반의 Tokenization를 많이 사용하고 있으며, 이때 훈련 데이터에 없는 단어 등 기존에 보지 못했던 단어들에 대해서도 유연하게 대처할 수 있다
Tokenizer가 중요한 이유
- 토크나이저는 텍스트 처리의 첫 단계로, 그 정확성과 효율성이 전체 모델의 성능에 직접적인 영향을 미칩니다. 만약 토크나이징이 부적절하게 이루어진다면, 모델이 텍스트를 올바르게 이해하지 못하고, 이는 곧 모델의 성능 저하로 이어질 수 있습니다.
- 언어에 따라 토크나이저의 성능이 달라질 수 있으며, 최적화된 토크나이저는 모델의 성능을 크게 향상시킬 수 있습니다.
- ChatGPT를 사용하면서 같은 내용이라도 영어는 빠른데 한국어는 느린 현상을 겪은 경험들이 있으실 겁니다.
- 같은 뜻의 문장이라도 토크나이저로 나뉘는 토큰 수가 달라지기 때문입니다. 토큰 수가 늘어난다는 것은 LLM의 입력과 출력의 길이가 늘어난다는 것을 뜻합니다.
- → 길이가 늘어나면 LLM이 응답하는 시간이 길어집니다.
- → 게다가 LLM API는 길이에 비례하여 과금되기 때문에 이는 고객이 부담하는 비용이 언어에 따라 달라질 수 있다는 의미가 됩니다.
- 좋은 vocab을 만드는 것이 곧 토크나이징 퀄리티와 직결되고, 이는 모델이 맥락 지식을 잘 학습하여 downstream task에서 좋은 성능을 내는 데에까지 영향을 미치기 때문이다.
- 아래는 Subword 기반의 Tokenization 기법들을 살펴본다
BytePairEncoding
- 원래 데이터 압축 알고리즘의 한 유형으로, 자주 나타나는 패턴을 캐릭터(BPE)/바이트(BBPE) 수준에서 압축하는 데 사용되었음 (https://arxiv.org/abs/1508.07909 , )
- 과정
- 어휘 집합 구축 : 자주 등장하는 문자열를 병합하고 이를 어휘 집합에 추가합니다. 이를 원하는 어휘 집합 크기가 될 때까지 반복합니다.
- 어휘 집합을 만들어주기 위해, Corpus의 모든 문장을 공백 기준으로 나누는 "Pre-Tokenize"를 수행
- 다음으로 어절별로 병합 우선순위(빈도 기준으로 )가 높은 바이그램 쌍을 반복해서 병합
- 토큰화 : 토큰화 대상 문장 내 각 어절(띄어쓰기로 문장을 나눈 것)에서 어휘 집합에 있는 서브워드가 포함되어 있을 때 해당 서브워드를 어절에서 분리합니다.
- 어휘 집합 구축 : 자주 등장하는 문자열를 병합하고 이를 어휘 집합에 추가합니다. 이를 원하는 어휘 집합 크기가 될 때까지 반복합니다.
- GPT, GPT-2, RoBERTa, BART 및 DeBERTa, LLaMA 등에서 사용
Byte-Level BPE
- BPE에서 더 나아가, subword 학습을 char level이 아닌 byte level 단위로 수행하는 것
- 이러한 방법을 사용했을때는 사람이 육안으로 토큰들을 확인하는건 불편하지만, OOV(Out-Of-Vocabulary)를 줄일 수 있다는 장점이 있음
- sentencepice에서는 공식적으로 BBPE를 지원하지 않지만, 비슷한 효과를 내는 " --byte_fallback=true" 옵션이 있음
- " --byte_fallback=true" 옵션은 unk 토큰을 만났을때 해당 토큰을 utf-8 byte level로 쪼개서 처리해줌 (참고)
import sentencepiece as spm from pathlib import Path paths = [str(x) for x in Path(data_dir).glob("*.txt")] corpus = ",".join(paths) prefix = "t5-sp-bpe-nsmc-byte-fallback" vocab_size = 31900-7 spm.SentencePieceTrainer.train( f"--input={corpus} --model_prefix={prefix} --vocab_size={vocab_size + 7}" + " --model_type=bpe" + " --max_sentence_length=999999" + # 문장 최대 길이 -> 이게 너무 길면 에러발생함 " --pad_id=0 --pad_piece=<pad>" + # pad (0) " --unk_id=1 --unk_piece=<unk>" + # unknown (1) " --bos_id=2 --bos_piece=<s>" + # begin of sequence (2) " --eos_id=3 --eos_piece=</s>" + # end of sequence (3) " --byte_fallback=true" + # add byte_fallback for unk tokens " --user_defined_symbols=<sep>,<cls>,<mask>") # 사용자 정의 토큰
- Byte 레벨에서의 BPE 과정
- 1. 초기 토큰화:
- 각 문자는 UTF-8 바이트로 변환된 상태에서 개별 바이트 단위로 나눠집니다.
- 예를 들어, "안녕, teacher 의성"은 다음과 같이 표현됩니다
- [EC, 95, 88, EB, 85, 95, 2C, 20, 74, 65, 61, 63, 68, 65, 72, 20, EC, 9D, 98, EC, 84, B1]
- 2. 바이트 쌍 빈도 계산:
- 각 인접한 바이트 쌍의 빈도를 계산합니다. 예를 들어, EC와 95, 95와 88 같은 인접한 쌍들의 빈도를 셉니다.
- 예를 들어, EC 95가 가장 자주 나타나는 경우 이를 하나의 새로운 토큰으로 합칩니다.
- 3. 쌍 합치기:
- 가장 빈도가 높은 쌍을 합쳐 새로운 토큰을 만듭니다.
- 예를 들어, EC 95가 합쳐지면, 이를 EC95라는 새로운 토큰으로 저장하고, 원래 시퀀스에서도 해당 부분을 대체합니다.
- 이 과정을 반복하여 가장 자주 나타나는 쌍을 합쳐 나가면서 최종적으로 원하는 토큰 수에 도달할 때까지 계속 진행합니다.
- 4. 최종 토큰화 결과:
- 예를 들어, "안녕"과 같은 자주 등장하는 단어들은 하나의 토큰으로 합쳐질 수 있습니다.
- Byte-Level BPE는 결국 자주 등장하는 바이트 쌍을 기준으로 텍스트를 효과적으로 압축한 토큰 리스트를 생성합니다.
https://sequencedata.tistory.com/m/81
https://devocean.sk.com/blog/techBoardDetail.do?ID=164570&boardType=techBlog#none
WordPieceEncoding
- 말뭉치에서 자주 등장한 문자열을 토큰으로 인식한다는 점에서 BPE와 본질적으로 유사
- 하지만 어휘 집합을 구축할 때 문자열을 병합하는 기준이 다름
- BPE처럼 단순히 빈도를 기준으로 병합하는 것이 아니라, 병합했을 때 말뭉치의 우도(likelihood)를 가장 높이는 쌍을 병합
- BERT, Electra가 이 WordPiece를 사용한다
Unigram
- 모든 Pre-tokenized 토큰과 서브 워드에서 시작해 점차 사전을 줄여나가는 방식으로 진행
- BPE, WordPiece와 같이 기본 캐릭터에서 서브 워드를 점진적으로 병합해나가는 것과는 차이
- 과정
- 매 스텝마다 Unigram은 주어진 코퍼스와 현재 사전에 대한 Loss를 측정
- 이후, 각각의 서브 워드에 대해 해당 서브 워드가 코퍼스에서 제거되었을 때, Loss가 얼마나 증가하는지를 측정
- 이에 따라 Loss를 가장 조금 증가시키는 p 개 토큰을 제거합니다 (p는 보통 전체 사전 크기의 10-20% 값으로 설정)
- Unigram은 해당 과정을 사용자가 원하는 사전 크기를 지니게 될 때 까지 반복
SentencePieceEncoding
- 지금까지 우리가 살펴본 모든 방법들은 Pre-tokenize 과정을 필요로 함
- 하지만 이것의 문제점 : 모든 언어가 공백을 기준으로 단어를 분절할 수 없다 (중국어, 일본어 등 ... )
- 특징
- SentencePiece는 띄어쓰기를 다른 알파벳 혹은 글자처럼 하나의 character로 취급 ( e.g. "_" )
- Unigram 모델과 BPE(Byte Pair Encoding) 두 가지 모드를 지원
- Unigram 모델은 가능한 모든 토큰의 확률을 학습하고, 가장 낮은 확률을 가진 토큰을 사전에서 제거하는 방식으로 최적의 사전을 만든다
- BPE 모드에서는 가장 자주 등장하는 문자 쌍을 하나의 토큰으로 합치는 방식으로 사전을 구성
- 위 두 모드 중에 어떤 것을 고를 것이냐는 상황에 따라 ... (GPT-4 Said)
- 언어의 특성: 처리하고자 하는 언어의 특성에 따라 다른 모드가 더 효과적일 수 있습니다. 예를 들어, 합성어가 많은 언어는 BPE를 사용할 때 더 효과적일 수 있습니다.
- 학습 데이터의 크기: 크고 다양한 학습 데이터는 Unigram 모델의 사용을 정당화할 수 있으며, 반면에 더 일관된 또는 제한된 데이터셋은 BPE로 더 잘 처리될 수 있습니다.
- 모델의 목적: 텍스트 생성이나 번역 같은 특정 NLP 과제에 따라, 하나의 모델이 다른 모델보다 더 적합할 수 있습니다. 예를 들어, 넓은 어휘를 필요로 하는 과제는 Unigram이 유리할 수 있습니다.
import sentencepiece as spm import torch from torch.utils.data import Dataset spm.SentencePieceTrainer.train(input="sample_text.txt", model_prefix="sentencepiece", model_type="unigram", vocab_size=3000) sp = spm.SentencePieceProcessor() sp.load("sentencepiece.model")
- ALBERT, T5, XLNet이 이 SentencePiece를 사용한다
Related Papers
https://arxiv.org/abs/2402.06196
https://arxiv.org/abs/1508.07909
-> BPE
https://arxiv.org/abs/1808.06226
https://arxiv.org/abs/1609.08144
-> wordpiece
https://arxiv.org/abs/1804.10959
-> unigram
Ref.
https://ratsgo.github.io/nlpbook/docs/preprocess/bpe/
https://huffon.github.io/2020/07/05/tokenizers/
https://huggingface.co/docs/transformers/ko/tokenizer_summary
728x90'AI > NLP' 카테고리의 다른 글
- Tokenization이란