Tokenizer는 크게 4단계로 구성되어 있습니다.
1. Nomalization : 불필요한 문자 제거, 유니코드 정규화 등 텍스트 정리
2. Pre-Tokenization : 단어 단위로 분해
3. Model : 사전에 토큰화된(pre-tokinzed) 단어로 토큰 시퀀스 생성
4. Postprocessor : 스페셜 토큰 삽입, attention mask와 token type id 생성
각 단계를 예시를 들며 살펴보겠습니다.
1. Normalization
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
print(type(tokenizer.backend_tokenizer))
print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?"))
(참고) uncased는 대소문자, 발음기호를 삭제하지만, cased는 삭제하지 않습니다.
2. Pre-Tokenizer
예시 문장 "Hello, My friend?"를 여러 토크나이저로 pre-tokenization하며 비교해보겠습니다. 문장에는 구두점(,)과 이중공백이 포함되어 있습니다.
BERT 토크나이저는 구두점을 구분하지만 이중 공백은 무시했습니다.
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, My friend?")
# [('Hello', (0, 5)), (',', (5, 6)), ('My', (7, 9)), ('friend', (11, 17)), ('?', (17, 18))]
gpt 기반 토크나이저는 이중 공백을 무시하지 않고, 'Ġ'라는 특수토큰으로 대체했습니다.
gpt_tokenizer = AutoTokenizer.from_pretrained("gpt2")
gpt_tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, My friend?")
# [('Hello', (0, 5)), (',', (5, 6)), ('ĠMy', (6, 9)), ('Ġ', (9, 10)), ('Ġfriend', (10, 17)), ('?', (17, 18))]
SentencePiece 알고리즘을 기반으로 하는 T5 토크나이저는 공백을 유지하지만, 구두점과 물음표는 구분하지 않습니다.
t5_tokenizer = AutoTokenizer.from_pretrained("t5-small")
t5_tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, My friend?")
# [('▁Hello,', (0, 6)), ('▁My', (7, 9)), ('▁friend?', (11, 18))]
SentencePiece
SentencePiece를 사용하면 Normalization과 Pre-tokenizer 단계가 필요하지 않을 수 있습니다.
SentencePiece는 텍스트 전처리를 위한 토큰화 알고리즘인데, 텍스트를 일련의 유니코드 문자로 간주하고 공백은 _로 바꿔줍니다. Unigram 알고리즘과 함께 사용하면 pre-tokenization 단계도 필요하지 않습니다. 이는 공백 문자가 사용되지 않는 언어(중국어, 일본어)에 매우 유용합니다.
주요 특징은 reversible tokenization입니다. 공백에 특별한 처리를 하지 않기 때문에, 토큰을 연결하고 _를 공백으로 바꾸는 것만으로 디코딩이 수행됩니다.- 정규화된 텍스트 생성. 앞에서 본 것처럼 BERT 토크나이저는 반복되는 공백을 제거하므로 토큰을 되돌릴 수 없습니다.
Model for Subword Splitting and Merging
SentencePiece에는 다양한 서브워드 분할 및 병합 전략을 사용할 수 있습니다. 그중 가장 유명한 세가지 방법을 소개합니다.
모델 | BPE | WordPiece | Unigram |
Training | 작은 vocabulary부터 시작하고, 토큰을 병합하는 규칙을 학습 모든 문자를 서브워드로 처리하고, 가장 빈도가 높은 바이트 페어를 병합하면서 새로운 서브워드 집합을 생성 |
작은 vocabulary부터 시작하고 토큰을 병합하는 규칙을 학습 단어 목록을 가지고 시작하며, 주어진 텍스트에 있는 모든 단어를 자주 나오는 부분어로 분할하고, 이들을 병합하여 새로운 서브워드를 생성 |
large vocabulary부터 시작하고 토큰을 삭제하는 규칙을 학습 모든 단어를 하나의 서브워드로 처리하고, 빈도에 따라 새로운 서브워드 생성. 빈도에 따라 샘플링되는데, 효율적인 학습을 위해 랜덤성을 추가. |
Training step | 가장 일반적인 쌍에 해당하는 토큰을 병합 | 가장 빈번한 쌍에 대한 스코어를 기반으로 토큰을 병합함 | 전체 corpus에서 loss를 최소화 하는 단어의 모든 토큰을 제거 |
Learns | 병합 규칙, vocab | vocab | 각 토큰의 점수와 vocab |
Encoding | 단어를 문자로 분할하고 학습 중에 학습된 병합을 적용 | 어휘의 처음부터 시작하여 가장 긴 하위 단어를 찾은 다음 나머지 단어에 대해서도 동일한 작업 수행 | 훈련 중에 학습한 점수를 사용하여 토큰으로 분할될 가능성이 가장 높은 항목을 찾음 |
지금부터는 각 모델을 예시를 들어 설명하겠습니다. 예시에는 아래 다섯가지 단어를 사용합니다.
"hug", "pug", "pun", "bun", "hugs"
BPE(Byte Pari Encoding)
텍스트를 압축하는 알고리즘으로 개발된 후 OpenAI에서 GPT 모델을 사전 학습할 때 토큰화를 위해 사용되었습니다.
GPT, GPT-2, RoBERTa, BART, DeBERTa에서 사용되었습니다.
예시에 대한 기본 vocabulary는 ["b", "g", "h", "n", "p", "s", "u"]가 됩니다. 기본 vocabulary에는 최소한 모든 ASCII 문자가 포함되어 있습니다. 하지만 토큰화 하는 예제가 훈련 코퍼스에 없는 문자를 사용할 경우, 해당 문자는 [UNK] 토큰으로 변환됩니다. NLP 모델이 이모티콘이 포함된 글을 분석하는데 안좋은 결과를 보이는 이유 중 하나입니다.(참고) GPT-2와 RoBERTa 토크나이저는 byte-level BPE라는 트릭을 사용합니다. 즉, 단어가 유니코드가 아니라 바이트로 작성된 것으로 간주합니다. vocabularty 크기 (256)는 작지만 모든 문자가 포함되며, UNK로 변환되지 않습니다.
기본 vocabulary를 얻은 후, 기존 어휘의 두 요소를 병합하는 규칙을 학습하여, 원하는 크기의 vocabulary가 될 때까지 새 토큰을 추가합니다.
# 1. 빈도 계산
("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)
# 2. 각 단어를 토큰으로 변환
("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5)
# 3. 가장 빈번하게 발생하는 쌍 찾고 병합
("u", "g") -> "ug"
# Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug"]
# Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5)
# 4. 원하는 vocabulary 크기가 될 때까지 반복
아래와 같은 규칙을 학습했을 때, "bug"는 ["b", "ug"]로 토큰화됩니다. 하지만 "mug"는 "m"이 vocabulary에 없기 때문에 ["[UNK]", "ug"]로 토큰화 됩니다.
("u", "g") -> "ug"
("u", "n") -> "un"
("h", "ug") -> "hug"
WordPiece
Google에 BERT를 pretraining하기위해 개발한 토큰화 알고리즘입니다.
이후 DistilBERT, MobileBERT, Funnel Transformers 및 MPNET 등 BERT 기반의 모델에서 사용되었습니다.
BPE와 유사하지만 실제 토큰화는 다르게 수행됩니다.
BPE와 마찬가지로 병합 규칙을 학습합니다. BPE는 가장 빈번한 쌍을 병합하지만, WordPiece는 스코어에 따라 병합합니다.
score = ( freq_of_pair ) / ( freq_of_first_element x freq_of_second_element )
쌍의 빈도를 각 부분의 빈도의 곱으로 나누어서, 개별 요소의 빈도 대비 쌍의 빈도가 높은 쌍을 우선적으로 병합합니다.
# 1. 빈도 계산
("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)
# 2. 나누기
("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5)
# 3. 스코어 계산후 병합
# Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"]
# Corpus: ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5)
# 4. 원하는 크기의 vocabulary가 될 때까지 반복
Unigram
AlBERT, T5, mBART, Big Bird 및 XLNet에서 사용되고, SentencePiece에 자주 사용됩니다.
Unigram은 BPE, WordPiece와 다르게 작동합니다.
기본 large vocabulary에서 시작해서 원하는 어휘 크기에 도달할 때까지 토큰을 제거합니다.
기본 vocabulary를 구축하는데는 여러 옵션이 있는데, 예를 들면 pre-tokenized vocabulary에서 가장 일반적인 하위 문자열을 사용하거나 어휘 크기가 큰 초기 코퍼스에 BPE를 적용할 수 있습니다.
모든 학습 단계에서 현재 주어진 vocabulary에 대한 코퍼스의 loss를 계산합니다.
vocabulary 안에 있는 symbol을 제거했을 때, 전체 loss가 얼마나 증가하는지 계산하여 가장 작게 loss가 증가되는 symbol을 제거합니다.
# 1. large vocabulary 구성(예시에서는 모든 substring)
["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"]
# 2. 각 빈도 count, 총 합 계산
("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16)
("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5)
# -> total : 210
# 3. 확률 계산(ex. "pug" → "p", "u", "g")
P(["p", "u", "g"]) = P(["p"]) x P(["u"]) x P(["g"]) = 5/210 x 36/210 x 20/210 = 0.000389
Unigram에는 매우 많은 계산이 필요합니다.
# 스코어
"hug": ["hug"] (score 0.071428)
"pug": ["pu", "g"] (score 0.007710)
"pun": ["pu", "n"] (score 0.006168)
"bun": ["bu", "n"] (score 0.001451)
"hugs": ["hug", "s"] (score 0.001701)
# loss 계산
10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8
본 포스트는 Hugging Face의 NLP course를 참고하여 작성했습니다.
Introduction - Hugging Face NLP Course
2. Using 🤗 Transformers 3. Fine-tuning a pretrained model 4. Sharing models and tokenizers 5. The 🤗 Datasets library 6. The 🤗 Tokenizers library 9. Building and sharing demos new
huggingface.co
'금융 데이터 분석가 > text-analysis' 카테고리의 다른 글
[NLP] XLNet 토크나이저 처음부터 학습하기 (0) | 2023.11.07 |
---|---|
[NLP] 한국어 모델 fine-tuning (0) | 2023.11.05 |
[NLP Transformers] input, sequence 처리 (0) | 2023.11.04 |
[NLP Transformers] NLP 작업 순서 - Tokenizer, Model, Post Processing (0) | 2023.11.03 |
[NLP Transformers] Encoder, Decoder, Encoder-Decoder 모델 (2) | 2023.11.02 |