참고 : Do it! BERT와 GPT로 배우는 자연어처리
2. 문장을 작은 단위로 쪼개기
토큰화
-
수행 방법 3가지
- 문자 / 단어 / 서브워드
-
토크나이저 : 토큰화를 수행하는 프로그램
-
ex) mecab (은전한닢), kkma(꼬꼬마)
( 토큰화 뿐만 아니라, POS tagging(품사 부착) 까지 수행가능 )
-
단어 단위 토큰화
ex) “공백” 기준으로 분리
- 장점 : tokenizer 불필요
- 단점 : vocabulary size가 매우 커질 수 있음
어제 카페 갔었어
어제 카페 갔었는데요
-----------------
[어제, 카페, 갔었어]
[어제, 카페, 갔었는데요]
ex) mecab으로 토큰화
- 의미있는 단위로 묶음
- 어휘 사전이 급격히 커지는 것 방지
어제 카페 갔었어
어제 카페 갔었는데요
-----------------
[어제, 카페, 갔었, 어]
[어제, 카페, 갔었, 는데요]
문자 단위 토큰화
- 한글 : 11,172개
- 한글 + (알파벳+숫자+기호) : 15,000여개
- 장점 : 너무 크지 않은 어휘 사전 & 미등록 토큰 X
- 단점 : 토큰 자체에 의미가 있기 어려움
- ex) “밁”의 의미는…?
어제 카페 갔었어
어제 카페 갔었는데요
-----------------
[어, 제, 카, 페, 갔, 었, 어]
[어, 제, 카, 페, 갔, 었, 는, 데, 요]
서브워드 토큰화
- “단어 단위” & “문자 단위”의 중간
- ex) BPE (Byte Pair Encoding)
- GPT = BPE로 토큰화
- BERT = wordpiece로 토큰화
BPE ( Byte Pair Encoding )
- 1994년에 제안된 정보압축 알고리즘
- idea : 가장 많이 등장한 문자열 병합
- example :
- aaabdaaabac
- “aa”가 가장 많이 등장 ( 총 4번 )
- “Z”로 치환
- ZabdZabac
- “Za” & “ab”가 가장 많이 등장 ( 총 2번 )
- 알파벳 순서 상, “ab”를 “Y”로 치환
- ZYdZYac
- “ZY”가 가장 많이 등장 ( 총 2번 )
- “X”로 치환
- XdXac
- aaabdaaabac
- 사전의 크기
- before : 4 ( a, b, c, d )
- after : 7 ( a, b, c, d, Z, Y, X )
- 데이터의 길이
- before : 11 ( aaabdaaabac )
- after : 5 ( ZYdZYac)
- 사전 크기 증가를 억제하면서도, 정보를 효율적으로 압축할 수 있는 알고리즘
-
대상 언어에 대한 사전지식 X
- BPE를 통한 토큰화의 절차
- 1) 어휘 집합 구축 ( 원하는 어휘 집합 size 도달할 때까지 )
- 우선, 공백을 기준으로 모두 나눠줌 ( = pre-tokenize )
- bi-gram 쌍끼리 묶어서 빈도를 합침
- 2) 토큰화 ( 위 어휘 집합으로 토큰화 진행 )
- 1) 어휘 집합 구축 ( 원하는 어휘 집합 size 도달할 때까지 )
Wordpiece
- BPE와의 공통점 : “자주 등장한 문자열”을 토큰으로 인식
- 차이점 : 말뭉치의 likelihood를 가장 높이는 쌍을 병합
어휘집합 구축하기
step 1) 데이터 다운로드
from Korpora import Korpora
nsmc = Korpora.load("nsmc", force_download = True)
step 2) 데이터 저장하기
- 순수 text 형태로
import os
def write_lines(data_dir, data):
with open(data_dir, 'w', encoding = 'utf-8') as f:
for line in data:
f.write(f'{line}\n')
data_train_dir = "/root/train.txt"
data_test_dir = "/root/test.txt"
write_lines(data_train_dir, data.train.get_all_texts())
write_lines(data_test_dir, data.test.get_all_texts())
step 3) 토크나이저 학습
step 3-1) GPT 토크나이저 ( BPE )
from tokenizers import ByteLevelBPETokenizer
tokenizer_GPT = ByteLevelBPETokenizer()
tokenizer_GPT.train(
files = [data_train_dir, data_test_dir],
vocab_size = 10000,
special_tokens = ["[PAD]"]
)
tokenizer_GPT_dir = "/gdrive/My Drive/nlpbook/bbpe"
tokenizer_GPT.save_model(tokenizer_GPT_dir)
- 이 결과로,
tokenizer_dir
에 2개의 파일이 저장된다.- 1)
vocab.json
: 바이트 수준 BPE의 “어휘 집합” - 2)
merges.txt
: 병합의 우선 순위
- 1)
step 3-2) BERT 토크나이저 ( WordPiece )
from tokenizers import BertWordPieceTokenizer
tokenizer_BERT = BertWordPieceTokenizer(lowercase = False)
tokenizer_BERT.train(
files = [data_train_dir, data_test_dir],
vocab_size = 10000
)
tokenizer_BERT_dir = "/gdrive/My Drive/nlpbook/wordpiece"
tokenizer_BERT.save_model(tokenizer_BERT_dir)
step 4) 토큰화 수행
- (1) 토크나이저 선언
- (2) 샘플 토큰화
- (3) 전체 토큰화
step 4-1) GPT 토큰화 수행
- (1) 토크나이저 선언
from transformers import GPT2Tokenizer
tokenizer_GPT = GPT2Tokenizer.from_pretrained(tokenizer_GPT_dir)
tokenizer_GPT.pad_token = "[PAD]"
- (2) 샘플 토큰화
sentences = ["xxxx","xxxxx","xxxxxx"]
sentences_tokenized = [tokenizer_GPT.tokenize(s) for s in sentences]
- (3) 전체 토큰화
batch_inputs = tokenizer_GPT(sentences, # data (list)
padding = "max_length",
max_length = 12, # ex) [525,6346,123,23,6,0,0,0,0,0,0,0]
trunctation = True
)
-
(4) 결과
-
1)
input_ids
: 인덱싱된 토큰 (정수값) -
2)
attention_mask
: 일반 토큰 (1), 패딩 (0) -
특징 : 앞/뒤에 ‘CLS’, ‘SEP’토큰 “없음”
-
step 4-2 ) BERT 토큰화 수행
- (1) 토크나이저 선언
from transformers import BertTokenizer
tokenizer_BERT = BertTokenizer.from_pretrained(tokenizer_BERT_dir,
do_lower_case = False)
- (2) 샘플 토큰화
sentences = ["xxxx","xxxxx","xxxxxx"]
sentences_tokenized = [tokenizer_BERT.tokenize(s) for s in sentences]
- (3) 전체 토큰화
batch_inputs = tokenizer_BERT(sentences, # data (list)
padding = "max_length",
max_length = 12, # ex) [525,6346,123,23,6,0,0,0,0,0,0,0]
trunctation = True
)
- (4) 결과
- 1)
input_ids
: 인덱싱된 토큰 (정수값) - 2)
attention_mask
: 일반 토큰 (1), 패딩 (0) - 3)
token_type_ids
: segment ( 1번째 문장 : 0, 2번째 문장 : 1) - 특징 : 앞/뒤에 ‘CLS’, ‘SEP’토큰 “있음”
- 1)