자연어처리를 오랫동안 하다보니 나만의 한글 데이터셋에 Bert, Transformer 등 새로운 모델의 입력을 만들어야 할 일이 많다.
한국어 자연어처리를 하는사람들이라면 매번 데이터셋에 맞는 sub-word 모델을 학습하고 vocab 사전을 만들어야한다
본 글에서는 내 데이터를 서브워드 분절하는 방법을 다루고자 한다
서브워드를 만드는 알고리즘은 사실 너무 많다.
1) 구글의 sentencepiece
2) opennmt
3) rust로 짜여 속도가 빠른 huggingface의 tokenizers
4) bpe 기법을 고안한 rsennrich의 코드
본 글에서는 구글의 sentencepiece 사용법을 다루고 다음글에서 huggingface의 tokenizers와 비교해 보려 한다
자연어 처리 시 모든 단어들을 벡터화 하는데 한계가 있다.
우리가 사용하는 글에는 이름, 숫자, 희귀단어나 단어장에 없는 신종어, 변형어, 약어가 섞여 있다.
이런 Rare word problem에서 Out-of-vocabulary(OOV) 문제가 발생하는데 이를 해결하기 위하여 Sub-word 전략을 사용한다.
BPE(Byte Pair Encoding) 알고리즘은 NMT, BERT 등 최근 자연어처리 알고리즘에서 전처리로 이용되는 서브워드(sub-word) 단위 분절 방법이다.
단어는 의미를 가진 더 작은 서브워드들의 조합으로 이루어진다. 빈도수에 따라 문자를 병합하여 subword를 구성한다.
예를 들면 "conference" -> 'con', 'f', 'er', 'ence' 로 분절 할 수 있다.
한국어, 일본어, 영어 등 언어 형식에 구애받지 않고, 별도의 문법 입력 없이 조사 구분이 가능하다.
어휘에서 자유롭게 학습이 가능하고, Rare word를 위한 back-off model이 필요 없다. 그리고 성능 향상 효과도 있다.
서브워드 단위로 쪼개면 차원과 sparsiry도 줄일 수 있다. 그리고 처음본 단어(unknown word) 처리에 효과적이다.
BPE-dropout
- BPE의 성능 개선하기 위한 방법으로 Subword regularization method 이다. 이 방법은 robustness와 accuracy를 향상시킨다. 학습데이터로 BPE를 학습 시 merge 부분에 랜덤으로(주로 10%) 확률로 dropout을 가하여 모델이 다른 segmantation을 보도록 학습하고, 이를 이용한 분절 시 dropout을 끄는 방식이다
이를 통해 같은 입력 단어가 다양한 분절 결과를 가질 수 있다. 아래 오른쪽 표는 BPE-dropout이 일반 BPE에 비해 다양한 NMT 문제에서 BLEU 수치가 높아짐을 모인다.
- 희귀 단어(자주 등장하지 않는 단어)에 강하다
왼쪽 그림은 BPE로 source data를 임베딩한 결과이다(SVD). 파란 점이 rare words(희귀단어) 인데, BPE는 희귀 단어들이 자기들끼리 모여있는 경향이 있다. 그에 반해 BPE-dropout은 희귀단어들도 일반 단어들과 잘 섞여 있다
이는 희귀 단어라 할지라도 일반단어와 함께 잘 어우러져 있고 그러므로 희귀단어가 입력 문장에 나왔을 때도 잘 임베딩 될 수 있다는걸 보여준다
- 오타에 강하다
오타가 섞인 번역에서 특히 더 좋은 성능을 보인다. 오른쪽 표를 보면 misspelled 상황에서 BPE에 비해 성능차이가 많이 난다. 즉 오타에 훨씬 강건하다.
- 코드
BPE를 고안한 R. sennirich는 하루만에 이를 반영한 코드를 공개했다. https://github.com/rsennrich/subword-nmt/blob/master/subword_nmt/apply_bpe.py 267line, 아래 코드는 그 구현부분이다. Symbol pairs의 list를 구축할 때, dropout(=0.1) 확률로 해당 segmantation을 누락시킨다.
pairs = [(bpe_codes[pair],i,pair) for (i,pair) in enumerate(zip(word, word[1:])) if (not dropout or random.random() > dropout) and pair in bpe_codes]
1. 구글 sentencepiece 설치하기
command line에 pip를 이용하여 간편하게 설치할 수 있다.
pip install sentencepiece
2. 사용법
1) 모델 만들기
- 가지고 있는 text로 빈도수 기반 BPE 모델을 만들 수 있다.
- 파이썬을 이용하여 sentencepiece 를 호출하고, spm.SentencePieceTrainer.Train 함수를 실행한다.
--input : 학습시킬 text의 위치
--model_name : 만들어질 모델 이름, 학습 후 <model_name>.model, <model_name>.vocab 두 파일 생성
--model_type : 어느 방식으로 학습할것인가, (unigram(default), bpe, char, word)
--vocal_size : Subword 갯수 설정, 보통 3,200개
--character_coverage : 몇%의 데이터를 커버할것인가, default=0.9995, 데이터셋이 적은 경우 1.0으로 설정
- 아래 코드를 수행하면 m.model, m.vocab이 생성된다.
15만 문장 학습 시 48s 소요
%%time
import sentencepiece as spm
input_file = 'data/train_tokenizer.txt'
vocab_size = 32000
model_name = 'subword_tokenizer_kor'
model_type = 'bpe'
user_defined_symbols = '[PAD],[UNK],[CLS],[SEP],[MASK],[UNK1],[UNK2],[UNK3],[UNK4],[UNK5]'
input_argument = '--input=%s --model_prefix=%s --vocab_size=%s --user_defined_symbols=%s --model_type=%s'
cmd = input_argument%(input_file, model_name, vocab_size,user_defined_symbols, model_type)
spm.SentencePieceTrainer.Train(cmd)
2) BPE 분절하기
- 1) 과정 에서 가지고 있는 text로 BPE 모델을 만들었다.
- 이 모델(m.model)을 이용하여 분절을 수행한다.
%python
>>> import sentencepiece as spm
>>> sp = spm.SentencePieceProcessor()
>>> sp.Load("m.model")
2-1) text -> subword
sp.EncodeAsPieces("This is a test")
['▁This', '▁is', '▁a', '▁', 't', 'est']
2-2) text -> subword id
sp.EncodeAsIds("This is a test")
[497, 100, 49, 6, 47, 514]
2-3) subword id -> text
sp.DecodeIds([497, 100, 49, 6, 47, 514])
'This is a test'
2-4) subword -> text
sp.DecodePieces(['▁This', '▁is', '▁a', '▁', 't', 'est'])
'This is a test'
2-5) subword size
sp.GetPieceSize()
1000
2-6) id -> piece
sp.IdToPiece(2)
sp.IdToPiece(2)
'</s>'
2-7) piece -> id
sp.PieceToId('')
sp.PieceToId('')
2-8) Drop-out 사용하기
enable_sampling=True 일 때 Drop-out이 적용되며 alpha=0.1은 10% 확률로 dropout 한다는 의미이다.
for _ in range(5):
print(sp.encode('This is a test', out_type=str, enable_sampling=True, alpha=0.1, nbest_size=-1))
2-9) encode의 인자로 encoding 하기
print(sp.encode('나는 오늘 아침밥을 먹었다.', out_type=str))
print(sp.encode('나는 오늘 아침밥을 먹었다.', out_type=int))
이와같이 구글 sentencepiece 파이썬 버전을 이용하여 손쉽기 BPE를 수행할 수 있다.
reference
https://github.com/google/sentencepiece
https://kh-kim.gitbook.io/natural-language-processing-with-pytorch/00-cover-3/06-bpe
https://github.com/rsennrich/subword-nmt
BPE-dropout : arxiv.org/abs/1910.13267
'AI > 자연어처리(NLP)' 카테고리의 다른 글
TransCoder, 비지도학습 기반 프로그래밍 언어 번역기 (0) | 2020.10.08 |
---|---|
한국어 자연어처리 1편_서브워드 구축(Subword Tokenizer, Mecab, huggingface VS SentencePiece) (5) | 2020.07.01 |
BERT를 파해쳐 보자!! (7) | 2019.10.29 |
Transformer-XL 정리, 사용법 (1) | 2019.07.03 |
GPT-2 (Generative Pre-Training 2) (2) | 2019.03.26 |