포스팅 개요
이번 포스팅은 자연어 처리에서 최근 많이 사용하는 subword 분절 방식인 sentencepiece와 huggingface sentencepiece 사용 방법을 정리합니다.
최근에 자연어처리쪽 모델을 다룰 일이 있어서 형태소 분석기를 사용할 까 하다가 sentnecepiece를 사용해 봤는데 너무 좋은 경험이 되어서 이를 정리하고자 합니다.
제가 참고한 자료는 아래와 같습니다.
- 성능을 비교한 자료 : keep-steady.tistory.com/37
- byte pair encoding을 쉽게 설명해준 자료 : wikidocs.net/22592 , lovit.github.io/nlp/2018/04/02/wpm/
- github.com/e9t/nsmc
포스팅 본문
토크나이징(Tokenizing)
자연어처리에서 토크나이징(tokenizing)은 문장을 토큰으로 나누는 과정입니다. 모델을 훈련할 때 이 토크나이징 된 단어의 개수(단어 사전)은 모델 성능에 다양한 영향을 미치게 됩니다. 특히 Out of Vocabulary(OOV) 문제는 굉장히 이슈가 되는 사항입니다. 미등록 된 단어가 문제가 되는 이슈이죠.
한국어 같은 경우에는 형태소 분석기를 많이 사용하게 되는데요. 이 out of vocabulary 문제를 해결하기 위해서 사용자 단어 사전을 만들어주기도 합니다. 하지만 매번 이렇게 추가하는 것은 굉장한 노동력이 필요합니다.
이를 해결하기 위해서 Subword 분절 방식이 나오게 됩니다. Subword 분절 방식에는 Word piece model, Byte pair Encoding(BPE) 등 다양한 방법이 있습니다. 최근 자연어처리 모델 (Transformer, BERT 등)들은 이 subword 분절 방식을 사용하고 있습니다.
그러면 저 Subword 분절 방식을 사용하면 모든 단어를 전부 수용할 수 있는가? 그것은 아닙니다. 여기에서도 loop를 몇 번 돌 것인가, 단어 수를 몇 개까지 수용할 것인가 등 다양한 parameter가 있는데 이것들을 잘 조정하는 것이 핵심입니다.
그러면 위와 같은 subword 분절 방식을 어떻게 사용할 수 있을까요?
이미 짱짱이신 google 형님들과 huggingface에서 관련 패키지를 배포해주었습니다.
google은 sentencepiece, huggingface에서는 tokenizer로 공개를 해주었죠.
사용법 - google sentencepiece
먼저 구글에서 공개해준 sentencepiece 모델 사용 방법에 대해서 소개합니다.
설치 방법은 pip로 설치할 수 있습니다.
- pip install sentencepiece
그리고 각종 예제는 제가 개요에 올려놓은 google sentencepiece github에 각종 예시들이 있습니다. 이번 포스팅에서도 간단하게 사용법을 정리해둡니다.
제가 진행한 환경은 아래와 같습니다.
- Python 3.7 ~ Python3.8
- Naver 영화 평점 데이터 NSMC
1. Data load
먼저 data를 가져옵니다. 저는 네이버 영화 평점 데이터를 사용했습니다. 관련 데이터는 NSMC github에서 받을 수 있습니다.(감사합니다!)
데이터는 위와 같은 형태로 제공됩니다. id가 있으며 document column에 text 정보가 담겨있습니다.
2. Text 저장
학습을 위해서는 저 text를 한 곳에 모아서 저장을 해두어야 합니다. 즉, 위 네이버 영화 평점 데이터 셋 기준으로는 data.document에서 관련된 text를 전부 저장해두어야 합니다.
참고로, null 데이터가 있으니 시작 전에 dropna를 하시는 것을 추천 드립니다. 저는 그냥 예외처리로 묶었습니다.
그리고 나서 데이터를 가져와서 잘 저장되어 있는지 체크해봅니다.
3. Google sentencepiece 사용하기
이제 google sentencepiece를 사용합니다. input file에는 위에서 만든 text 데이터를 가르키도록 합니다. 또한, 저는 여기서 사전 크기 (vocab_size)를 5000으로 두었습니다. 실제 모델에 적용하려는 것이 아닌 사용 법을 정리하기 위함이서서 적은 크기로 잡았습니다. 보통 실제 모델에서 사용할 때는 25,000 ~ 35,000 정도로 사용한다고 많이 들었습니다.
4. 훈련하기
이제 sentencepiece를 훈련합니다. sentencepiece는 아래와 같이 불러올 수 있습니다.
import sentecepiece as spm
spm.SentencePieceTrainer.Train()
이렇게 훈련을 시켜주니까 NSMC 데이터 셋 기준으로 CPU time이 2분 36초가 걸린 것을 확인할 수 있습니다.
5. 결과 확인하기
이렇게 만든 sentencepiece를 이용해서 문자열을 넣어 그 결과 값을 도출할 수도 있습니다.
- 원본 문자열이 쪼개졌을 때의 형태
- id 값으로 변환 했을 때의 형태
사용법 - Huggingface tokenizer
다음은 hugginface가 제공해주는 tokenzier입니다. 사실 huggingface에서 제공해주는 tokenizer에는 다양한 종류가 있습니다.
- byte level bpe tokenzier
- char bpe tokenzier
- sentnecepiece bpe tokenizer
- bert wordpiece tokenzier
저는 sentencepiece와 비교하기 위해서 huggingface tokenzier 중 sentencepiece bpe tokenzier를 사용했습니다.
설치하는 방법은 아래와 같습니다.
- pip install tokenizers
그리고 사용하는 방법은
from tokenizers import SentencePieceBPETokenizer
와 같이 불러와서 사용할 수 있습니다.
아래는 그것에 대한 사진입니다.
1. 훈련하기
간단하게는 huggingface tokenzier 사용법은 간단하게 아래와 같이 vocab_size만 정하고 train할 파일이 있는 요소의 path만 제시하여 사용할 수 있습니다. 그 외에도 다양한 parameter가 존재합니다.
- min_frequency : 최소 빈도수. 만약 3으로 지정하면 3회 이상 등장한 것에 대해서 수행
- vocab_size : vocab의 size
- special_tokens : [UNK], [CLS]와 같은 스페셜 토큰을 지정
- limit_alphabet : initial token이 유지되는 숫자. 이 숫자가 크면 모든 글자를 커버할 수 있다.
저는 간단하게 vocab_size만 지정하였습니다. special_token 사용하는 방법은 개요에 올려놓은 huggingface와 sentencepiece 비교 블로그를 참고하시면 자세히 나와있습니다!
여기서 CPU times가 21초가 나왔습니다. 아까 google sentencepiece에서는 2분 36초가 나왔었는데요.
즉, huggingface의 tokenzier가 훨씬 빠른 모습을 보여줍니다.
2, 결과 확인하기
google sentencepiece때와 마찬가지로 문자열을 넣어서 token이 쪼개지는 것과 그것에 대한 id 값으로 변형할 수 있습니다.
sentencepiece와는 다르게 tokenzier.encode에 단어를 넣고 그 output을 사용해서 output.ids, output.tokens 등으로 확인할 수 있습니다.
3. huggingface tokenzier 저장하고 불러오는 방법
huggingface의 tokenzier는 저장하고 불러오는 방법이 특이합니다. 각 tokenizer마다 사용법이 다른데요.
sentencepiece같은 경우에는 save_model을 수행하면 아래와 같은 2개의 파일이 생성됩니다.
- vocab.json
- merges.txt
이 두개를 저장하고 당연히 불러올 때 저 2개를 같이 불러와주어야 합니다.
맺음말
이번 포스팅에서는 자연어처리에서 많이 사용되는 subword를 구축할 수 있는 google sentencepiece와 huggingface의 tokenzier에 대해서 알아보았습니다.
각가의 사용법이 다르고 속도도 다르기 때문에 적절하게 사용하시면 좋을 것 같습니다!