๐ค Tokenizers ํตํฌ์ด
๐ค Tokenizers ํตํฌ์ด (Quicktour)
๐ค Tokenizers ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ธฐ๋ฅ๋ค์ ๋น ๋ฅด๊ฒ ์ดํด๋ณผ๊ฒ์. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ค๋๋ ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋ ํ ํฌ๋์ด์ ์ ๊ตฌํ์ ์ ๊ณตํ๋๋ฐ, ์ฌ์ฉํ๊ธฐ ์ฝ๊ณ ๋งค์ฐ ๋น ๋ฆ ๋๋ค.
์ฒ์๋ถํฐ ํ ํฌ๋์ด์ ๋น๋
๐ค Tokenizers ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ผ๋ง๋ ๋น ๋ฅธ์ง ๋ณด์ฌ๋๋ฆฌ๊ธฐ ์ํด, wikitext-103 (ํ ์คํธ 516M) ์์ ์ ํ ํฌ๋์ด์ ๋ฅผ ๋ช ์ด ๋ง์ ํ๋ จ์์ผ ๋ณผ๊ฒ์. ๋จผ์ ์ด ๋ฐ์ดํฐ์ ์ ๋ค์ด๋ก๋ํ๊ณ ์์ถ์ ํ์ด์ผ ํด์:
wget https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-103-raw-v1.zip
unzip wikitext-103-raw-v1.zip
ํ ํฌ๋์ด์ ํ๋ จ
์ด ํฌ์ด์์๋ Byte-Pair Encoding (BPE) ํ ํฌ๋์ด์ ๋ฅผ ๋น๋ํ๊ณ ํ๋ จ์ํฌ ๊ฑฐ์์. ํ ํฌ๋์ด์ ์ ๋ค์ํ ์ ํ์ ๋ํด ๋ ์๊ณ ์ถ๋ค๋ฉด ๐ค Transformers ๋ฌธ์์ ์ด ๊ฐ์ด๋๋ฅผ ํ์ธํ์ธ์. ์ฌ๊ธฐ์ ํ ํฌ๋์ด์ ๋ฅผ ํ๋ จํ๋ค๋ ๊ฒ์:
- ํ๋ จ ๋ง๋ญ์น์ ์๋ ๋ชจ๋ ๋ฌธ์๋ฅผ ํ ํฐ์ผ๋ก ์์ํ๋ค.
- ๊ฐ์ฅ ํํ ํ ํฐ ์์ ์ฐพ์ ํ๋์ ํ ํฐ์ผ๋ก ๋ณํฉํ๋ค.
- ์ดํ(์ฆ ํ ํฐ ์)๊ฐ ์ํ๋ ํฌ๊ธฐ์ ๋๋ฌํ ๋๊น์ง ๋ฐ๋ณตํ๋ค.
๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฃผ API๋ class Tokenizer์์. ์ฌ๊ธฐ BPE ๋ชจ๋ธ๋ก ํ๋๋ฅผ ์ธ์คํด์คํํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
from tokenizers import Tokenizer
from tokenizers.models import BPE
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
wikitext ํ์ผ๋ค์์ ํ ํฌ๋์ด์ ๋ฅผ ํ๋ จํ๋ ค๋ฉด trainer๋ฅผ ์ธ์คํด์คํํด์ผ ํ๋๋ฐ, ์ด ๊ฒฝ์ฐ BpeTrainer์์.
from tokenizers.trainers import BpeTrainer
trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
vocab_size๋ min_frequency ๊ฐ์ ํ๋ จ ์ธ์(์ฌ๊ธฐ์๋ ๊ธฐ๋ณธ๊ฐ 30,000๊ณผ 0์ผ๋ก ๋จ๊ฒจ๋ )๋ฅผ ์ค์ ํ ์ ์๋๋ฐ, ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ๋์ค์ ์ฌ์ฉํ special_tokens๋ฅผ ์ฃผ๋ ๊ฑฐ์์ (ํ๋ จ ์ค์๋ ์ ํ ์ฌ์ฉ๋์ง ์์ง๋ง ์ดํ์ ์ฝ์
๋๋๋ก).
ํน์ ํ ํฐ ๋ฆฌ์คํธ๋ฅผ ์ฐ๋ ์์๋ ์ค์ํด์: ์ฌ๊ธฐ์๋ "[UNK]"๊ฐ ID 0, "[CLS]"๊ฐ ID 1์ ์ป๊ฒ ๋๊ณ ์ด๋ ๊ฒ ์ด์ด์ง๋๋ค.
from tokenizers.pre_tokenizers import Whitespace
tokenizer.pre_tokenizer = Whitespace()
์ด์ ์ฌ์ฉํ๋ ค๋ ์๋ฌด ํ์ผ ๋ฆฌ์คํธ์ ํจ๊ป Tokenizer.train ๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ๋ง ํ๋ฉด ๋ผ์.
files = [f"data/wikitext-103-raw/wiki.{split}.raw" for split in ["test", "train", "valid"]]
tokenizer.train(files, trainer)
์ ์ฒด wikitext ๋ฐ์ดํฐ์
์์ ํ ํฌ๋์ด์ ๋ฅผ ํ๋ จํ๋ ๋ฐ ๋ช ์ด๋ฐ์ ๊ฑธ๋ฆฌ์ง ์์์! ์ค์ ๊ณผ ์ดํ๋ฅผ ๋ชจ๋ ๋ด์ ๋จ์ผ ํ์ผ๋ก ํ ํฌ๋์ด์ ๋ฅผ ์ ์ฅํ๋ ค๋ฉด Tokenizer.save ๋ฉ์๋๋ฅผ ์ฐ๋ฉด ๋ผ์.
tokenizer.save("data/tokenizer-wiki.json")
๊ทธ ํ์ผ์์ ํ ํฌ๋์ด์ ๋ฅผ ๋ค์ ๋ถ๋ฌ์ค๋ ค๋ฉด Tokenizer.from_file classmethod๋ฅผ ์ฌ์ฉํด์.
tokenizer = Tokenizer.from_file("data/tokenizer-wiki.json")
ํ ํฌ๋์ด์ ์ฌ์ฉ
ํ ํฌ๋์ด์ ๋ฅผ ํ๋ จํ์ผ๋ ์ด์ ์ํ๋ ์ด๋ค ํ
์คํธ์๋ Tokenizer.encode ๋ฉ์๋๋ก ์ฌ์ฉํ ์ ์์ด์.
output = tokenizer.encode("Hello, y'all! How are you ๐ ?")
์ด๊ฒ์ ํ
์คํธ์ ํ ํฌ๋์ด์ ์ ์ ์ฒด ํ์ดํ๋ผ์ธ์ ์ ์ฉํด์ Encoding ๊ฐ์ฒด๋ฅผ ๋ฐํํด์. ์ด ํ์ดํ๋ผ์ธ์ ๋ํด ๋ ์์ธํ ๋ฐฐ์ฐ๊ณ , ๊ทธ ์ผ๋ถ๋ฅผ ์ ์ฉ(๋๋ ์ปค์คํฐ๋ง์ด์ฆ)ํ๋ ๋ฐฉ๋ฒ์ ์ด ํ์ด์ง๋ฅผ ํ์ธํ์ธ์.
ํ์ฒ๋ฆฌ (Post-processing)
from tokenizers.processors import TemplateProcessing
tokenizer.post_processor = TemplateProcessing(
single="[CLS] $A [SEP]",
pair="[CLS] $A [SEP] $B:1 [SEP]:1",
special_tokens=[
("[CLS]", tokenizer.token_to_id("[CLS]")),
("[SEP]", tokenizer.token_to_id("[SEP]")),
],
)
๊ทธ๋ค์ ๋ฌธ์ฅ ์์ฉ ํ
ํ๋ฆฟ์ ์ง์ ํ๋๋ฐ, ์ด๋ "[CLS] $A [SEP] $B [SEP]" ํํ์ฌ์ผ ํด์. ์ฌ๊ธฐ์ $A๋ ์ฒซ ๋ฒ์งธ ๋ฌธ์ฅ, $B๋ ๋ ๋ฒ์งธ ๋ฌธ์ฅ์ ๋ํ๋ด์. ํ
ํ๋ฆฟ์ ์ถ๊ฐ๋ :1์ ์
๋ ฅ์ ๊ฐ ๋ถ๋ถ์ ์ํ๋ type IDs๋ฅผ ๋ํ๋ด์: ๋ชจ๋ ๊ฒ์ ๊ธฐ๋ณธ๊ฐ์ 0์ด๋ผ (๊ทธ๋์ $A:0์ด ์์) ์ฌ๊ธฐ์๋ ๋ ๋ฒ์งธ ๋ฌธ์ฅ์ ํ ํฐ๊ณผ ๋ง์ง๋ง "[SEP]" ํ ํฐ์ ๋ํด 1๋ก ์ค์ ํฉ๋๋ค.
output = await tokenizer.encode("Hello, y'all! How are you ๐ ?")
console.log(output.getTokens())
// ["[CLS]", "Hello", ",", "y", "'", "all", "!", "How", "are", "you", "[UNK]", "?", "[SEP]"]
๋ฌธ์ฅ ์์์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๋ ค๋ฉด ๋ ๋ฌธ์ฅ์ Tokenizer.encode์ ๋๊ธฐ๋ฉด ๋ผ์.
๋ฐฐ์น๋ก ์ฌ๋ฌ ๋ฌธ์ฅ ์ธ์ฝ๋ฉ
๐ค Tokenizers ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ต๋ ์๋๋ฅผ ์ป์ผ๋ ค๋ฉด Tokenizer.encode_batch ๋ฉ์๋๋ก ํ
์คํธ๋ฅผ ๋ฐฐ์น ๋จ์๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ต๊ณ ์์.
output = tokenizer.encode_batch(["Hello, y'all!", "How are you ๐ ?"])
๋ฌธ์ฅ ์ ๋ฐฐ์น๋ฅผ ์ฒ๋ฆฌํ๋ ค๋ฉด Tokenizer.encode_batch ๋ฉ์๋์ ๋ ๋ฆฌ์คํธ๋ฅผ ๋๊ธฐ๋ฉด ๋ผ์: ๋ฌธ์ฅ A ๋ฆฌ์คํธ์ ๋ฌธ์ฅ B ๋ฆฌ์คํธ.
output = tokenizer.encode_batch(
[["Hello, y'all!", "How are you ๐ ?"], ["Hello to you too!", "I'm fine, thank you!"]]
)
์ฌ๋ฌ ๋ฌธ์ฅ์ ์ธ์ฝ๋ฉํ ๋๋ Tokenizer.enable_padding์ผ๋ก ์ถ๋ ฅ์ ๊ฐ์ฅ ๊ธด ๋ฌธ์ฅ์ ๋ง์ถฐ ์๋์ผ๋ก ํจ๋ฉํ ์ ์์ด์. pad_token๊ณผ ๊ทธ ID๋ฅผ ์ง์ ํ๋ฉด ๋ฉ๋๋ค (ํจ๋ฉ ํ ํฐ์ ID๋ ์ด์ ์ฒ๋ผ Tokenizer.token_to_id๋ก ๋ค์ ํ์ธํ ์ ์์ด์).
tokenizer.enable_padding(pad_id=3, pad_token="[PAD]")
ํจ๋ฉ์ direction(๊ธฐ๋ณธ์ ์ค๋ฅธ์ชฝ)์ ์ค์ ํ๊ฑฐ๋, ๋ชจ๋ ์ํ์ ํน์ ๊ฐ์๋ก ํจ๋ฉํ๊ณ ์ถ๋ค๋ฉด length๋ฅผ ์ง์ ํ ์ ์์ด์ (์ฌ๊ธฐ์๋ ์ค์ ํ์ง ์์ ๊ฐ์ฅ ๊ธด ํ
์คํธ์ ํฌ๊ธฐ์ ๋ง์ถฅ๋๋ค).
output = tokenizer.encode_batch(["Hello, y'all!", "How are you ๐ ?"])
print(output[1].tokens)
# ["[CLS]", "How", "are", "you", "[UNK]", "?", "[SEP]", "[PAD]"]
์ด ๊ฒฝ์ฐ ํ ํฌ๋์ด์ ๊ฐ ์์ฑํ attention mask๊ฐ ํจ๋ฉ์ ๊ณ ๋ คํฉ๋๋ค.
์ฌ์ ํ๋ จ (Pretrained)
์ฌ์ ํ๋ จ ํ ํฌ๋์ด์ ์ฌ์ฉ
์ ์ฅ์์ tokenizer.json ํ์ผ๋ง ์์ผ๋ฉด Hugging Face Hub์ ์ด๋ค ํ ํฌ๋์ด์ ๋ ๋ถ๋ฌ์ฌ ์ ์์ด์.
from tokenizers import Tokenizer
tokenizer = Tokenizer.from_pretrained("bert-base-uncased")
๋ ๊ฑฐ์ ์ดํ ํ์ผ์์ ์ฌ์ ํ๋ จ ํ ํฌ๋์ด์ ์ํฌํธ
์ดํ ํ์ผ๋ง ์์ผ๋ฉด ์ฌ์ ํ๋ จ ํ ํฌ๋์ด์ ๋ฅผ ๋ฐ๋ก ์ํฌํธํ ์๋ ์์ด์. ์๋ฅผ ๋ค์ด, ๊ณ ์ ์ ์ธ ์ฌ์ ํ๋ จ BERT ํ ํฌ๋์ด์ ๋ฅผ ์ด๋ ๊ฒ ์ํฌํธํฉ๋๋ค.
from tokenizers import BertWordPieceTokenizer
tokenizer = BertWordPieceTokenizer("bert-base-uncased-vocab.txt", lowercase=True)
bert-base-uncased-vocab.txt ํ์ผ์ ๋ค์์ผ๋ก ๋ค์ด๋ก๋ํ๋ค๋ฉด ๋ง์ด์ฃ .
wget https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-vocab.txt
์ถ์ฒ: ๊ณต์๋ฌธ์