๐Ÿค— 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

์ถœ์ฒ˜: ๊ณต์‹๋ฌธ์„œ