열렬히.뛰기

2장 : 문장의 토큰화

머신러닝 & 딥러닝 > 자연어처리 (1) : BERT와 GPT > 2장 : 문장의 토큰화

토근화란?

  • 문장을 토큰 시퀸스로 나누는 과정
  • 토큰화를 수행하는 프로그램: 토크나이저
    • 꼬꼬마, 은전한닢 등 존재.
    • 각 토큰에 품사를 붙여주는 품사 부착도 수행.
    • 자세한 라이브러리를 보고 싶다면 클릭

단어단위 토큰화

  • 어절 단위로 문자를 쪼개는 방법
  • 어휘 집합의 크기가 커질 수 있다는 단점이 존재

문자단위 토큰화

  • 어휘 집합의 크기가 작아짐.
  • 미등록 토큰(어휘집합에 없는 토큰) 문제에서 자유로움

그러나, 다음과 같은 단점도 존재함.

  • 토큰 시퀸스의 길이 자체가 길어짐
  • 각 문자 토큰이 형태소보다 작아질 수 있음.
    • 의미가 사라져 버림.

서브워드 단위 토큰화

  • 단어단위와 문자단위의 중간
  • ex) 바이트 페어 인코딩

바이트 페어 인코딩

  • 원래 정보를 압축하던 알고리즘. 최근에는 NLP에 자주 쓰임
    • GPT → BPE 기법
    • BERT → 워드피스 기법

BPE 기법

  • 문자열을 병합해서 압축하는 기법
  • ex) “aaabdaaabac” → “ZabdAabac” → “ZYdZYac” → “XdXac”
    • aa를 병합해 Z로 표현했다.
    • ab를 병합해 Y로 표현했다.
    • ZY를 병합해 X로 표현했다.
  • 단어 길이 : 11개 → 5개 / 사전 길이 : 4개 → 7개
  • 사전의 크기가 지나치게 늘어나지 않으면서도 단어 길이를 줄임.

어휘 집합 구축

  1. 말뭉치 준비하고 공백으로 나눠주기
    • 공백으로 나눠주기를 프리토크나이즈 라고 한다.
    • ex. cookie → [‘c’, ‘o’, ‘o’, ‘k’, ‘i’, ‘e’]
  2. 바이그램 쌍을 생성
  3. 이를 토대로 어휘 집합을 구축한다.
    • vocab.json 생성
  4. 병합 우선순위 생성
    • merge.txt

토큰화

어휘집합과 병합 우선순위를 기반으로 시행.

  1. 문자를 공백 단위로 쪼개기
  2. 병합 우선순위 부여
  3. 우선순위가 높은 순대로 먼저 합쳐줌
  4. 다시 병합 우선순위 부여
  5. 병합 대상이 없다면 어휘집합에 있는지 검사
    • 어휘 집합에 없으면 미등록 토큰으로 처리

워드피스 기법

문자열을 토큰으로 인식한다는 점에서는 동일

단, 어휘 집합 구축 시 문자열을 병합하는 기준이 다름

병합 시 말뭉치의 우도를 가장 높이는 쌍을 병합.

ex. 병합후보가 a, b일때

\frac {\dfrac{\#ab}{n}} {\dfrac{\#a}{n} \times \dfrac{\#b}{n} }

수식의 값이 커지려면 a와 b가 독립임을 가정했을 때보다 둘이 자주 동시에 등장해야 함.

즉, 워드피스는 병합 후보에 오른 쌍들을 미리 병합해 보고 잃는 것과 가치 등을 판단한 후 병합.

토큰화

  • 분석 대상 어절에 어휘 집합에 있는 서브워드가 포함돼 있을 때 해당 서브워드를 어절에서 분리.
  • 단, 서브워드가 여러 개면 가장 긴 것 선택
  • 이후 나머지 어절 중에서 서브워드를 다시 찾고, 분리
    • 서브워드 후보가 하나도 없으면 해당 문자열 전체를 미등록 단어로 취급

어휘 집합 구축

  • 여기서부터는 코딩.
  • Google colab을 사용하자.

ratsnlp, Korpora 준비

python
!pip install ratsnlp
python
from Korpora import Korpora
nsmc = Korpora.load("nsmc", force_download=True)

NSMC 전처리

python
import os
def write_lines(path, lines):
with open(path, 'w', encoding='utf-8') as f:
for line in lines:
f.write(f'{line}\n')
write_lines("/content/train.txt", nsmc.train.get_all_texts())
write_lines("/content/test.txt", nsmc.train.get_all_texts())

디렉터리 만들기

python
import os
os.makedirs("/gdrive/My Drive/nlpbook/bbpe", exist_ok = True)

바이트 수준 BPE 어휘 집합 구축

python
from tokenizers import ByteLevelBPETokenizer
bytebpe_tokenzier = ByteLevelBPETokenizer()
bytebpe_tokenzier.train(
files = ["/content/train.txt", "/content/test.txt"],
vocab_size = 10000,
special_tokens = ["[PAD]"]
)
bytebpe_tokenzier.save_model("/gdrive/My Drive/nlpbook/bbpe")

디렉토리 만들기

python
import os
os.makedirs("/gdrive/My Drive/nlpbook/wordpiece", exist_ok=True)

워드피스 어휘집합 구축

python
from tokenizers import BertWordPieceTokenizer
wordpiece_tokenizer = BertWordPieceTokenizer(lowercase=False)
wordpiece_tokenizer.train(
files = ["/content/train.txt", "/content/test.txt"],
vocab_size = 10000
)
wordpiece_tokenizer.save_model("/gdrive/My Drive/nlpbook/wordpiece")

토근화하기

준비코드

python
!pip install ratsnlp
python
from google.colab import drive
drive.mount("/gdrive", force_remount=True)

GPT 입력값 설정

python
from transformers import GPT2Tokenizer
tokenizer_gpt = GPT2Tokenizer.from_pretrained("/gdrive/My Drive/nlpbook/bbpe")
tokenizer_gpt.pad_token = "[PAD]"
python
Sentences = [
"아 더빙...진짜 짜증나네요 목소리",
"연기가 별로 답이 없는 것 같다.",
"별루였다..."
]
tokenized_sentences = [tokenizer_gpt.tokenize(sen) for sen in Sentences]
tokenized_sentences
python
batch_inputs = tokenizer_gpt(
Sentences,
padding = "max_length",
max_length = 12,
truncation = True
)

BERT 입력값 만들기

python
from transformers import BertTokenizer
tokenizer_bert = BertTokenizer.from_pretrained(
"/gdrive/My Drive/nlpbook/wordpiece",
do_lower_case = False
)
python
batch_inputs = tokenizer_bert(
Sentences,
padding = "max_length",
max_length = 12,
truncation = True
)
python
batch_inputs["input_ids"]

""" 결과
[[2, 623, 2639, 16, 16, 16, 1993, 3682, 1990, 3467, 3, 0],
 [2, 2347, 2092, 6184, 2062, 128, 2278, 16, 3, 0, 0, 0],
 [2, 3341, 2183, 16, 16, 16, 3, 0, 0, 0, 0, 0]]
"""

문장 1과 문장 3에는 뒤에 패딩 토큰 0이 붙음.

  • 패딩 토큰이란? 더미토큰으로써 길이를 맞춰주는 역할을 함.