참고 : 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
  • 사전의 크기
    • 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) 토큰화 ( 위 어휘 집합으로 토큰화 진행 )


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 : 병합의 우선 순위


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’토큰 “있음”

Tags:

Categories:

Updated: