나만의 언어모델 만들기 - Wordpiece Tokenizer 만들기

nawnoes·2020년 10월 26일
9

NLP

목록 보기
2/45
post-thumbnail

Wordpiece Tokenizer 만들기

개요

말뭉치 데이터(Corpus)를 바탕으로 언어모델을 만드려고 할때, 말뭉치 데이터를 언어모델에 학습시키기 위해서는 우리가 사용하는 자연어를 벡터로 변환하는 과정이 필요하다.

자연어를 벡터로 변환하기 위해서는 자연어를 토큰화 하고, 토큰화된 단어들에 인덱스를 부여해서, 부여된 인덱스를 바탕으로 원핫 벡터나 학습을 통해밀집된 벡터들을 만들 수 있다.

원 핫 벡터의 경우 단어가 많아질 수록 정보를 표현하는데 많은 공간이 필요하며, 이러한 벡터들이 공간상에서 의미가 있다고 볼 수 없다. 따라서 밀집된 벡터를 만들기 위해 Word2Vec과 같은 다양한 방법들이 사용된다. 이와 같이 단어를 벡터로 표현하는 것을 워드임베딩(word embedding)이라 한다.

위와 같이 단어를 벡터로 만들기 위해서는, 우리가 가진 말뭉치, 문장 데이터를 토큰으로 나누어 주어야한다. 이때 말뭉치나 입력으로 들어온 문장을 토큰로 나누어 주는것을 토큰화한다고 하며, Tokenizer가 문장을 토큰으로 나누어 준다. 이 때 주의할 점은 토큰은 단어 일 수도 있으며, 단어가 아닐 수도 있다.

언어모델을 학습하기 위한 토크나이저로 wordpiece tokenizer를 사용하기로 한다.

Vocab

vocab이란 무엇인가?

자연어처리에서 vocab은 vocabulary의 약자로 단어들의 사전을 의미한다.

사전이라는 단어가 생소하다면, 텍스트 파일에 토큰화 된 단어들이 나열 되어 있는 파일로 보면 된다. 아래 vocab.txt은 생성된 vocab 파일의 예시이다.

vocab.txt

[PAD]
[UNK]
[CLS]
[SEP]
[MASK]
지시
##훈련
##기구
##물에
런던
##해지는
늘어난
상황이다
...생략...

Tokenizer

토크나이저란 위에 설명한 바와 같이 입력으로 들어온 문장들에 대해 토큰으로 나누어 주는 역할을 한다.

토크나이저는 크게 Word TokenizerSubword Tokenizer으로 나뉜다.

word tokenizer

Word Tokenizer의 경우 단어를 기준으로 토큰화를 하는 토크나이저를 말하며,

subword tokenizer

subword tokenizer의 경우 단어를 나누어 단어 안에 단어들로 토큰화를 하는것을 말한다. 예를들어 경찰차, 경찰관, 경찰복과 같은 단어들이 있는 경우, 아래와 같이 단어의 분절들로 나누어질 수 있다.

경찰
##차
##관
##복

subword tokenizer은 vocab에 없는 단어들에 대해서도 좋은 성능을 보인다는 장점을 가진다.

Wordpiece 워드피스

wordpiece tokenizer는 위에 설명한 subword tokenizer의 종류 중 하나이다. subword tokenizer에서 대표적으로 사용되는 방법으로 BPE(Byte Pair Encoding) 방법이 있다.

일반적으로 많이 사용하는 Sentencepiece의 경우 빈도수를 기반으로 BPE를 수행하며, Wordpiece의 경우 likelihood를 기반으로 BPE를 수행한 알고리즘이다.

BERT의 경우 Wordpiece를 이용한 tokenizer를 사용하였고, sentencepiece를 사용한 모델 또한 많다. 선택에 따라 필요한 tokenizer를 활용할 수 있다.

Wordpiece Tokenizer 만들기

huggingface tokenizers 설치

pip install tokenizers

말뭉치 파일로 Wordpiece vocab 만들기

import argparse
from tokenizers import BertWordPieceTokenizer

parser = argparse.ArgumentParser()

parser.add_argument("--corpus_file", type=str)
parser.add_argument("--vocab_size", type=int, default=22000) # 만들 Vocab의 숫자 
parser.add_argument("--limit_alphabet", type=int, default=6000)

args = parser.parse_args()

tokenizer = BertWordPieceTokenizer(
    vocab_file=None,
    clean_text=True,
    handle_chinese_chars=True,
    strip_accents=False, # Must be False if cased model
    lowercase=False,
    wordpieces_prefix="##"
)

tokenizer.train(
    files=[args.corpus_file],
    limit_alphabet=args.limit_alphabet,
    vocab_size=args.vocab_size
)

tokenizer.save("./ch-{}-wpm-{}-pretty".format(args.limit_alphabet, args.vocab_size),True)

생성된 vocab 파일 전처리

import json # import json module

vocab_path = "../vocab/ch-6000-wpm-22000-pretty"

vocab_file = '../data/wpm-vocab-all.txt'
f = open(vocab_file,'w',encoding='utf-8')
with open(vocab_path) as json_file:
    json_data = json.load(json_file)
    for item in json_data["model"]["vocab"].keys():
        f.write(item+'\n')

    f.close()

Tokenizer 테스트

huggingface transformers 패키지 필요

from transformers.tokenization_bert import BertTokenizer

vocab_path = "../data/wpm-vocab-all.txt"

tokenizer = BertTokenizer(vocab_file=vocab_path, do_lower_case=False)

test_str = ' [CLS] 나는 워드피스 토크나이저를 써요. 성능이 좋은지 테스트 해보려 합니다. [SEP]'
print('테스트 문장: ',test_str)

encoded_str = tokenizer.encode(test_str,add_special_tokens=False)
print('문장 인코딩: ',encoded_str)

decoded_str = tokenizer.decode(encoded_str)
print('문장 디코딩: ',decoded_str)

"""
테스트 문장:   [CLS] 나는 워드피스 토크나이저를 써요. 성능이 좋은지 테스트 해보려 합니다. [SEP]
문장 인코딩:  [2, 9310, 4868, 6071, 12467, 21732, 12200, 6126, 6014, 4689, 6100, 18, 11612, 6037, 9389, 6073, 16784, 17316, 6070, 10316, 18, 3]
문장 디코딩:  [CLS] 나는 워드피스 토크나이저를 써요. 성능이 좋은지 테스트 해보려 합니다. [SEP]
"""

Fin

언어모델 학습하기 위한 Vocab 및 Tokenizer 생성 완료

References

0개의 댓글