huggingface tokenizers 라이브러리를 통한 BBPE 토크나이저 학습 기록

빙수·2022년 8월 20일
1

35GB 텍스트 데이터로 토크나이저를 학습하였습니다.

라이브러리 버전

  • transformers: 4.21.1
  • datasets: 2.4.0
  • tokenizers: 0.12.1
from datasets import load_dataset
from tokenizers import ByteLevelBPETokenizer

tokenizer = ByteLevelBPETokenizer(unicode_normalizer="nfkc", trim_offsets=True)
ds = load_dataset("Bingsu/my-korean-training-corpus", use_auth_token=True)
# 공개된 데이터를 사용할 경우
# ds = load_dataset("cc100", lang="ko")  # 50GB


# 이 데이터는 35GB이고, 데이터가 너무 많으면 컴퓨터가 터져서 일부만 사용했습니다.
ds_sample = ds["train"].train_test_split(0.35, seed=20220819)["test"]


def gen_text(batch_size: int = 5000):
    for i in range(0, len(ds_sample), batch_size):
        yield ds_sample[i : i + batch_size]["text"]


tokenizer.train_from_iterator(
    gen_text(),
    vocab_size=50265,
    min_frequency=2,
    special_tokens=[
        "<s>",
        "<pad>",
        "</s>",
        "<unk>",
        "<mask>",
    ],
)
tokenizer.save("my_tokenizer.json")
# tokenizer.save_model(".", "my_tokenizer")

기본적인 틀은 https://huggingface.co/blog/how-to-train를 참고하였습니다.

tokenizer = ByteLevelBPETokenizer(unicode_normalizer="nfkc", trim_offsets=True)

unicode_normalizer는 paust/pko-t5-base와 유니코드 관련 문서를 참고하였습니다. 원본 roberta-base모델에는 이 옵션이 있지 않습니다. 참고: [유니코드] 한글 인코딩 개념과 발생하는 문제점 정리

ds = load_dataset("Bingsu/my-korean-training-corpus", use_auth_token=True)
이 datasets 저장소에는 Aihub와 모두의 말뭉치 등에서 수집한 텍스트가 있습니다. 라이센스상 공개할 수 없어 밑에 주석으로 다른 공개 데이터셋을 넣어놓았습니다.

def gen_text(batch_size: int = 5000):
    for i in range(0, len(ds_sample), batch_size):
        yield ds_sample[i : i + batch_size]["text"]


tokenizer.train_from_iterator(
    gen_text(),
    vocab_size=50265,
    min_frequency=2,
    special_tokens=[
        "<s>",
        "<pad>",
        "</s>",
        "<unk>",
        "<mask>",
    ],
)

그리고 훈련.
vocab_size는 roberta-base와 같은 크기입니다.
텍스트를 제공하는 이터레이터를 만들고, .train_from_iterator로 훈련합니다.
special_tokens에 들어가는 항목은 순서도 중요합니다.


i5-12600 non-k cpu로 약 7시간이 소요되었습니다.

훈련이 완료된 토크나이저를 다시 불러와, 토크나이저의 post-processor를 변경해줍니다.

from tokenizers import Tokenizer
from tokenizers.processors import RobertaProcessing

tokenizer = Tokenizer.from_file("my_tokenizer.json")
tokenizer.post_processor = RobertaProcessing(
    ("</s>", tokenizer.token_to_id("</s>")),
    ("<s>", tokenizer.token_to_id("<s>")),
    add_prefix_space=False,
)

tokenizer.save("my_tokenizer2.json")

add_prefix_space=False옵션은 roberta-base를 그대로 따라하기 위한 것입니다. 설정하지 않으면 기본값 True가 사용됩니다.

from transformers import RobertaTokenizerFast

rt = RobertaTokenizerFast(tokenizer_file="tokenizer.json")

그리고 RobertaTokenizerFast클래스로 불러옵니다. 다른 Fast 토크나이저로 불러와도 상관없습니다.

rt.save_pretrained("./my_tokenizer")

토크나이저를 저장해준 뒤
생성된 폴더의 tokenizer_config.json파일을 열어 "model_max_length": 512,를 추가합니다.

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Bingsu/BBPE_tokenizer_test")

끝!

0개의 댓글