부스트캠프 AI Tech 4기
[NLP_KLUE] 3. 한국어 Tokenizing
- -
Tokenizing의 목적
- 의미를 지닌 단위로 자연어를 분절
- Model의 학습 시, 동일한 size로 입력
⇒ tokenizer는 특정 사이즈로 token의 개수를 조절하는 함수가 필수로 포함되어야 한다.
어절 단위 tokenizing
모든 문장을 띄어쓰기 단위로 분리하는 것
max_seq_length = 10
text = "오늘은 KLUE 대회 첫 날이다."
tokenized_text = text.split(" ")
# padding
tokenized_text += ["padding"] * (max_seq_length - len(tokenized_text))
# truncation
tokenized_text = tokenized_text[:max_seq_length]
print(tokenized_text)
# ['오늘은', 'KLUE', '대회', '첫', '날이다.', 'padding', 'padding', 'padding', 'padding', 'padding']
class Tokenizer:
def __init__(self):
self.tokenizer_type_list = ["word"]
self.pad_token = "<pad>"
self.max_seq_length = 10
self.padding = False
def tokenize(self, text, tokenizer_type):
assert tokenizer_type in self.tokenizer_type_list, "정의되지 않은 tokenizer_type입니다."
if tokenizer_type == "word":
tokenized_text = text.split(" ")
if self.padding:
tokenized_text += [self.pad_token] * (self.max_seq_length - len(tokenized_text))
return tokenized_text[:self.max_seq_length]
else:
return tokenized_text[:self.max_seq_length]
def batch_tokenize(self, texts, tokenizer_type):
for i, text in enumerate(texts):
texts[i] = self.tokenize(text, tokenizer_type)
return texts
word_tokenizer = Tokenizer()
word_tokenizer.pad_token = "[PAD]"
word_tokenizer.max_seq_length = 10
word_tokenizer.padding = True
print(word_tokenizer.tokenize("페이커가 숙제 방송을 진행중입니다.", "word"))
# ['페이커가', '숙제', '방송을', '진행중입니다.', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]']
형태소 단위 tokenizing
from konlpy.tag import Mecab
mecab = Mecab()
print(mecab.pos("아버지가방에들어가신다."))
#[('아버지', 'NNG'), ('가', 'JKS'), ('방', 'NNG'), ('에', 'JKB'), ('들어가', 'VV'), ('신다', 'EP+EF'), ('.', 'SF')]
class Tokenizer:
def __init__(self):
self.tokenizer_type_list = ["word", "morph"]
self.pad_token = "<pad>"
self.max_seq_length = 10
self.padding = False
def tokenize(self, text, tokenizer_type):
assert tokenizer_type in self.tokenizer_type_list, "정의되지 않은 tokenizer type 입니다."
if tokenizer_type == "word":
tokenized_text = text.split(" ")
elif tokenizer_type == "morph":
tokenized_text = [lemma[0] for lemma in mecab.pos(text)]
if self.padding:
tokenized_text += [self.pad_token] * (self.max_seq_length - len(tokenized_text))
return tokenized_text[:self.max_seq_length]
else:
return tokenized_text[:self.max_seq_length]
def batch_tokenize(self, texts, tokenizer_type):
for i, text in enumerate(texts):
texts[i] = self.tokenize(text, tokenizer_type)
return texts
print(my_tokenizer.tokenize("점심으로 계란 볶음밥이랑 라면 먹었음", "morph"))
# ['점심', '으로', '계란', '볶음밥', '이랑', '라면', '먹', '었', '음', '[PAD]']
음절 단위 tokenizing
음절 단위 tokenizing은 한 자연어를 한 글자씩 분리
text = "우리집 고양이들이 요새 계속 밥달라고 보채고 있다."
tokenized_text = list(text) # split 함수는 입력 string에 대해서 특정 string을 기반으로 분리해줍니다.
print(tokenized_text)
# ['우', '리', '집', ' ', '고', '양', '이', '들', '이', ' ', '요', '새', ' ', '계', '속', ' ', '밥', '달', '라', '고', ' ', '보', '채', '고', ' ', '있', '다', '.']
class Tokenizer:
def __init__(self):
self.tokenizer_type_list = ["word", "morph", "syllable"]
self.pad_token = "<pad>"
self.max_seq_length = 10
self.padding = False
def tokenize(self, text, tokenizer_type):
assert tokenizer_type in self.tokenizer_type_list, "정의되지 않은 tokenizer_type입니다."
if tokenizer_type == "word":
tokenized_text = text.split(" ")
elif tokenizer_type == "morph":
tokenized_text = [lemma[0] for lemma in mecab.pos(text)]
elif tokenizer_type == "syllable":
tokenized_text = list(text)
if self.padding:
tokenized_text += [self.pad_token] * (self.max_seq_length - len(tokenized_text))
return tokenized_text[:self.max_seq_length]
else:
return tokenized_text[:self.max_seq_length]
def batch_tokenize(self, texts, tokenizer_type):
for i, text in enumerate(texts):
texts[i] = self.tokenize(text, tokenizer_type)
return texts
자소 단위 tokenizing
한글은 하나의 문자도 최대 초성, 중성, 종성, 총 3개의 자소로 분리가 가능하다.
자소 분리를 위해 hgtk 라이브러리를 사용
import hgtk
text = "자소 분리"
tokenized_text = list(hgtk.text.decompose(text))
print(tokenized_text)
# ['ㅈ', 'ㅏ', 'ᴥ', 'ㅅ', 'ㅗ', 'ᴥ', ' ', 'ㅂ', 'ㅜ', 'ㄴ', 'ᴥ', 'ㄹ', 'ㅣ', 'ᴥ']
class Tokenizer:
def __init__(self):
self.tokenizer_type_list = ["word", "morph", "syllable", "jaso"]
self.pad_token = "<pad>"
self.max_seq_length = 10
self.padding = False
def tokenize(self, text, tokenizer_type):
assert tokenizer_type in self.tokenizer_type_list, "정의되지 않은 tokenizer_type입니다."
if tokenizer_type == "word":
tokenized_text = text.split(" ")
elif tokenizer_type == "morph":
tokenized_text = [lemma[0] for lemma in mecab.pos(text)]
elif tokenizer_type == "syllable":
tokenized_text = list(text)
elif tokenizer_type == "jaso":
tokenized_text = list(hgtk.text.decompose(text))
if self.padding:
tokenized_text += [self.pad_token] * (self.max_seq_length - len(tokenized_text))
return tokenized_text[:self.max_seq_length]
else:
return tokenized_text[:self.max_seq_length]
def batch_tokenize(self, texts, tokenizer_type):
for i, text in enumerate(texts):
texts[i] = self.tokenize(text, tokenizer_type)
return texts
WordPiece tokenizing
from tokenizers import BertWordPieceTokenizer
# Initialize an empty tokenizer
wp_tokenizer = BertWordPieceTokenizer(
clean_text=True, # [이순신, ##은, ' ', 조선]에서 ' '(띄어쓰기)를 지우고자 할 때 True / Bert는 clean_text=True
handle_chinese_chars=True,
strip_accents=False, # True: [YepHamza] -> [Yep, Hamza] : 대문자 기준 분리
lowercase=False,
)
# train
wp_tokenizer.train(
files="my_data/wiki_20190620_small.txt", # corpus file
vocab_size=10000,
min_frequency=2,
show_progress=True,
special_tokens=["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"],
limit_alphabet=1000,
wordpieces_prefix="##"
)
# Save the files
wp_tokenizer.save_model("wordPieceTokenizer", "my_tokenizer") # 디렉토리, vocab 저장 이름
# ['wordPieceTokenizer/my_tokenizer-vocab.txt']
print(wp_tokenizer.get_vocab_size())
# 10000
text = "이순신은 조선 중기의 무신이다."
tokenized_text = wp_tokenizer.encode(text)
print(tokenized_text)
# Encoding(num_tokens=10, attributes=[ids, type_ids, tokens, offsets, attention_mask, special_tokens_mask, overflowing])
print(tokenized_text.tokens)
# ['이', '##순', '##신은', '조선', '중', '##기의', '무', '##신이', '##다', '.']
print(tokenized_text.ids)
# [706, 1454, 7607, 2002, 755, 2606, 452, 8496, 1017, 16]
class Tokenizer:
def __init__(self):
self.tokenizer_type_list = ["word", "morph", "syllable", "jaso", "wordPiece"]
self.pad_token = "<pad>"
self.max_seq_length = 10
self.padding = False
def tokenize(self, text, tokenizer_type):
assert tokenizer_type in self.tokenizer_type_list, "정의되지 않은 tokenizer_type입니다."
if tokenizer_type == "word":
tokenized_text = text.split(" ")
elif tokenizer_type == "morph":
tokenized_text = [lemma[0] for lemma in mecab.pos(text)]
elif tokenizer_type == "syllable":
tokenized_text = list(text)
elif tokenizer_type == "jaso":
tokenized_text = list(hgtk.text.decompose(text))
elif tokenizer_type == "wordPiece":
tokenized_text = wp_tokenizer.encode(text).tokens
if self.padding:
tokenized_text += [self.pad_token] * (self.max_seq_length - len(tokenized_text))
return tokenized_text[:self.max_seq_length]
else:
return tokenized_text[:self.max_seq_length]
def batch_tokenize(self, texts, tokenizer_type):
for i, text in enumerate(texts):
texts[i] = self.tokenize(text, tokenizer_type)
return texts
부스트캠프 AI Tech 교육 자료를 참고하였습니다.
728x90
'부스트캠프 AI Tech 4기' 카테고리의 다른 글
[NLP_KLUE] 5. GPT (1) | 2022.12.08 |
---|---|
[NLP_KLUE] 4. BERT / Huggingface Tokenizer (2) | 2022.11.15 |
[NLP_KLUE] 2. 한국어 전처리 (0) | 2022.11.14 |
[NLP_KLUE] 1. 자연어 단어 임베딩 / 딥러닝 기반 자연어처리와 언어모델 (0) | 2022.11.14 |
[WEEK08] CI (0) | 2022.11.14 |
Contents