Skip to content

Kiwi 형태소 분석기를 활용한 딥러닝 언어 모델 실험실

Notifications You must be signed in to change notification settings

bab2min/kiwi-farm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 

Repository files navigation

키위 농장 Kiwi Farm

한국어 형태소 분석기 Kiwi를 활용한 딥러닝 언어 모델들을 실험적으로 키우는 공간입니다.

BERT, GPT, BART와 같은 딥러닝 언어모델에서는 크기가 고정된 닫힌 어휘 집합을 사용합니다. 따라서 딥러닝 언어모델에 텍스트를 입력하려면 임의의 텍스트를 고정된 어휘 집합으로 분할하여 변환해주는 토크나이저(Tokenizer)가 필수적입니다. 한국어의 경우 오랫동안 개발되어온 형태소 분석기가 있으나, 기존의 형태소 분석기들은 분석결과를 고정된 개수의 어휘로 출력하는 기능이 없었으므로 형태소 분석기를 토크나이저로 사용할 수 없었습니다. 그래서 한국어의 특징을 고려하지 못함에도 Byte Pair Encoding이나 SentencePiece 등을 토크나이저로 사용하고 있는 상황입니다.

Kiwi는 0.15버전에서부터 형태소 분석과 Subword 분절 기능을 통합한 Unigram 토크나이저를 제공합니다. 이 저장소에서는 Kiwi를 기반으로한 토크나이저의 성능을 실험하고, 실제로 이 토크나이저를 기반으로 학습한 딥러닝 모델의 특징을 분석해보고자 합니다.

이 저장소에서 공개된 Kiwi 기반의 딥러닝 언어 모델을 사용하려면 kiwipiepy>=0.15.1transformers>=4.12가 필요합니다. 요구사항이 모두 준비된 상황이라면 아래와 같이 간단하게 kiwi-farm의 모델을 가져와서 사용할 수 있습니다.

from transformers import (
    AutoTokenizer, 
    AutoModelForMaskedLM, 
)
import kiwipiepy.transformers_addon
# kiwipiepy.transformers_addon를 import해야
# KiwiTokenizer가 AutoTokenizer에 등록된다.
# KiwiTokenizer는 PreTrainedTokenizer와 대부분의 기능이 호환되므로
# 기존의 transformers 코드를 그대로 사용할 수 있다.

tokenizer = AutoTokenizer.from_pretrained('kiwi-farm/roberta-base-32k')
model = AutoModelForMaskedLM.from_pretrained('kiwi-farm/roberta-base-32k')

토크나이저

KiwiTokenizer를 학습하는 데에는 다음과 같은 말뭉치를 사용했습니다.

  • 모두의 말뭉치: 문어 말뭉치
  • 모두의 말뭉치: 구어 말뭉치
  • 모두의 말뭉치: 비출판물 말뭉치
  • 모두의 말뭉치: 신문 말뭉치

아래는 KiwiTokenizer와 다른 토크나이저를 비교한 결과입니다.

토크나이저별 통계

토크나이저Vocab SizeSpecial TokensHangul TokensAlnum TokensHanja Tokens
KiwiTokenizer 16k16000712777 (11130 / 1647)804 (295 / 509)1598 (1598 / 0)
KiwiTokenizer 32k32000726285 (21917 / 4368)2446 (965 / 1481)2334 (2334 / 0)
KiwiTokenizer 48k48000739670 (32345 / 7325)4478 (1960 / 2518)2799 (2799 / 0)
KiwiTokenizer 64k64000752877 (42693 / 10184)6806 (3150 / 3656)3173 (3173 / 0)
klue/roberta-base32000528388 (24638 / 3750)2389 (1461 / 928)335 (335 / 0)
beomi/kcbert-base30000528137 (18874 / 9263)630 (425 / 205)0 (0 / 0)
HanBert-54kN-torch54000545702 (32462 / 13240)3533 (2096 / 1437)1821 (914 / 907)
  • 괄호 안의 숫자는 차례로 (Word의 개수 / Subword의 개수) 입니다.
  • 여기서 Word는 공백으로 시작하는 토큰을 가리키며, Subword는 공백 없이 이어지는 토큰을 가리킵니다.

토크나이징 사례

토크나이저제임스웹우주망원경이 발사됐다.
KiwiTokenizer 32k['제임스', '##', '웹', '##우주', '##', '망원경', '이/J', '발사', '되/V', '었/E', '다/E', '.']
klue/roberta-base['제임스', '##웹', '##우주', '##망', '##원', '##경', '##이', '발사', '##됐', '##다', '.']
beomi/kcbert-base['제', '##임', '##스', '##웹', '##우', '##주', '##망', '##원', '##경이', '발사', '##됐다', '.']
HanBert-54kN-torch['제임스', '##웹', '##우', '##주', '##망', '##원경', '~~이', '발사', '##됐다', '.']
  • KiwiTokenizer는 Glue 토큰(##)을 사용합니다. 특정 문자열을 Subword로 분절하는 것보다 Glue + Word를 사용하는게 낫다고 판단되면 후자를 선택합니다. 그 결과 다른 토크나이저에서는 망원경이 망/원/경, 혹은 망/원경 등으로 분절되지만, KiwiTokenizer에서는 망원경 원형 전체가 보존됩니다.
토크나이저힘들어도 끝까지 버텼다.
KiwiTokenizer 32k['힘들/V', '어도/E', '끝', '까지/J', '버티/V', '었/E', '다/E', '.']
klue/roberta-base['힘들', '##어도', '끝', '##까', '##지', '[UNK]', '.']
beomi/kcbert-base['힘들어도', '끝까지', '버', '##텼', '##다', '.']
HanBert-54kN-torch['힘들', '##어', '##도', '끝', '~~까지', '버텼', '##다', '.']
  • 다른 토크나이저에서는 비교적 출현 빈도가 적은 음절인 이 어휘집합에 포함되어 있지 않아 UNK(알 수 없는 토큰)로 처리되곤 합니다. KiwiTokenizer에서는 동사/형용사에 대해서는 형태소 분석을 수행하므로 어간이 어미와 결합해 희귀한 형태가 되더라도 절대 UNK로 처리되지 않습니다.
  • 추가적으로 한글의 경우 초/중성 + 종성을 분리해 표현하는 대체 기능이, 그 외의 문자에 대해서는 UTF8 byte 단위로 분리해 표현하는 대체 기능이 포함되어 있어서, 어떤 문자에 대해서도 UNK가 나오지 않습니다.
토크나이저달려가는 날쌘돌이
KiwiTokenizer 32k['달려가/V', '는/E', '날쌔/V', 'ᆫ/E', '##돌', '이/J']
klue/roberta-base['달려가', '##는', '[UNK]']
beomi/kcbert-base['달려', '##가는', '날', '##쌘', '##돌이']
HanBert-54kN-torch['달려가', '~~는', '[UNK]', '~~이']
  • 위와 유사하게 이라는 음절 때문에 UNK가 생성되는 토크나이저가 있습니다.
토크나이저주거니 받거니 줬거니 받았거니
KiwiTokenizer 32k['주/V', '거니/E', '받/V', '거니/E', '주/V', '었/E', '거니/E', '받/V', '었/E', '거니/E']
klue/roberta-base['주거', '##니', '받', '##거', '##니', '줬', '##거', '##니', '받', '##았', '##거', '##니']
beomi/kcbert-base['주거', '##니', '받', '##거니', '줬', '##거니', '받았', '##거니']
HanBert-54kN-torch['주거', '##니', '받', '##거니', '줬', '##거니', '받', '##았', '##거니']
  • Kiwi는 동/형용사의 경우 형태소 분석을 사용하기 때문에 동일한 단어가 활용형이 달라져서 다른 토큰으로 처리되는 경우가 적습니다.
토크나이저띄 어 쓰 기 엉 망 진 창 으 로 하 기
KiwiTokenizer 32k['띄/V', '어/E', '쓰/V', '기/E', '엉망', '지/V', 'ᆫ/E', '창', '으로/J', '하/V', '기/E']
klue/roberta-base['띄', '어', '쓰', '기', '엉', '망', '진', '창', '으', '로', '하', '기']
beomi/kcbert-base['띄', '어', '쓰', '기', '엉', '망', '진', '창', '으', '로', '하', '기']
HanBert-54kN-torch['띄', '어', '쓰', '기', '엉', '망', '진', '창', '으', '로', '하', '기']
토크나이저띄어쓰기엉망진창으로하기
KiwiTokenizer 32k['띄', '##어', '##쓰기', '##', '엉망', '##진', '##창', '으로/J', '하/V', '기/E']
klue/roberta-base['띄', '##어', '##쓰기', '##엉', '##망', '##진', '##창', '##으로', '##하기']
beomi/kcbert-base['띄', '##어', '##쓰기', '##엉', '##망', '##진창', '##으로', '##하기']
HanBert-54kN-torch['띄', '##어', '##쓰기', '##엉', '##망', '##진', '##창', '##으로', '##하기']
  • Kiwi가 가지고 있는 띄어쓰기 오류 보정 모델 덕분에 띄어쓰기가 엉망인 텍스트에 대해서도 잘 작동합니다.
토크나이저나랏〮말〯ᄊᆞ미〮 듀ᇰ귁〮에〮달아〮 문ᄍᆞᆼ〮와〮로〮서르ᄉᆞᄆᆞᆺ디〮아니〮ᄒᆞᆯᄊᆡ〮
KiwiTokenizer 32k['나', '##랏', '말', 'ᄊ', '##ᆞ', '##미', 'ᄃ', '##ᅲ', '##ᇰ', '##귀', '##ᆨ', '에/J', '달/V', '어/E', '문', '##ᄍ', '##ᆞ', '##ᆼ', '<0xE3>', '<0x80>', '<0xAE>', '##와', '<0xE3>', '<0x80>', '<0xAE>', '##로', '<0xE3>', '<0x80>', '<0xAE>', '##서', '##르', '##ᄉ', '##ᆞ', '##ᄆ', '##ᆞ', '##ᆺ', '##디', '아니', 'ᄒ', '##ᆞ', '##ᆯ', '##ᄊ', '##ᆡ']
klue/roberta-base['[UNK]', '[UNK]', '[UNK]']
beomi/kcbert-base['[UNK]', '[UNK]', '[UNK]']
HanBert-54kN-torch['나', '##랏', '[UNK]', '말', '[UNK]', '[UNK]', '[UNK]', '[UNK]', '[UNK]', '에', '[UNK]', '달아', '[UNK]', '[UNK]', '[UNK]', '와', '[UNK]', '로', '[UNK]', '[UNK]', '[UNK]', '아니', '[UNK]', '[UNK]', '[UNK]']
  • Kiwi는 첫가끝 코드를 지원하여 옛한글에 대해서도 UNK를 생성하지 않습니다. 다만 일부 방점은 어휘집합에 포함되지 않아서 UTF8 byte로 분절됩니다.

AutoEncoding 언어 모델

KiwiTokenizer가 딥러닝 언어 모델에서 얼마나 유용한지 확인하기 위해 실제로 RoBERTa 모델을 사전학습해 보았습니다. 사전학습은 바닥부터 진행된 것은 아니며 이미 강력한 것으로 확인된 klue/roberta-base 모델을 재활용하여 어휘 집합만 갈아끼운 뒤 추가 학습을 진행하는 방식으로 수행되었습니다. 사전 학습은 klue/roberta-base와 동일한 어휘 집합 크기를 가진 KiwiTokenizer 32k와 klue보다 어휘 집합이 2배 큰 KiwiTokenizer 64k를 바탕으로 진행되었습니다. 사전 학습 절차에 대해서는 train_bert.py 코드를 참조해주세요. 사전학습이 완료된 모델은 kiwi-farm/roberta-base-32k(huggingface 모델 저장소)kiwi-farm/roberta-base-64k(huggingface 모델 저장소)에서 다운로드 받을 수 있습니다.

사전 학습이 완료된 모델의 성능을 평가하기 위해 다양한 데이터셋으로 미세조정을 실시하였습니다. 노이즈가 많은 환경을 고려하여 미세조정을 평가할 때 평가데이터셋을 크게 3종류로 변형하였습니다.

  • 기본: 변형 적용 안 함
  • NoSpace: 평가 텍스트에서 공백을 모두 제거
  • AllSpace: 평가 텍스트의 각 글자 사이에 공백 모두 삽입
  • Random: 20%의 확률로 공백을 삽입하거나 제거함
평가 결과 요약
모델NSMCKLUE YNAT
Kiwi RoBERTa Base (32k)0.89920.8501
Kiwi RoBERTa Base (64k)0.90300.8510
Klue RoBERTa Base0.82820.7088
Beomi KcBert Base0.83530.6456
HanBert 54kN Base0.83630.7345
  • 기본, NoSpace, AllSpace, Random 테스트 결과를 평균낸 것
  • 변형이 적용 안 된 평가셋에 대해서는 Klue 모델이 제일 좋은 성능을 내었으나, 공백 오류가 들어갈 수록 모델의 성능이 급하락
  • Kiwi 모델의 경우 공백 오류에 대해 대체적으로 강건한 성능을 보임

미세조정: NSMC

따라해보기

python src/finetuning/sequence_classification.py --model_name_or_path kiwi-farm/roberta-base-32k --output_dir results --dataset nsmc --key document --num_train_epochs 2

python src/finetuning/sequence_classification.py --model_name_or_path kiwi-farm/roberta-base-64k --output_dir results --dataset nsmc --key document --num_train_epochs 2

python src/finetuning/sequence_classification.py --model_name_or_path klue/roberta-base --output_dir results --dataset nsmc --key document --num_train_epochs 2

python src/finetuning/sequence_classification.py --model_name_or_path beomi/kcbert-base --output_dir results --dataset nsmc --key document --num_train_epochs 2
Kiwi RoBERTa Base (32k)
기본NoSpaceAllSpaceRandom
Train 기본0.908520.903040.892040.8933
Train NoSpace0.908940.906920.891420.897
Train AllSpace0.90550.897480.905440.897
Train Random0.90630.90540.90060.90262
Kiwi RoBERTa Base (64k)
기본NoSpaceAllSpaceRandom
Train 기본0.912780.907420.895120.89676
Train NoSpace0.911720.909620.891240.89918
Train AllSpace0.907120.89790.906680.89734
Train Random0.911640.909420.9040.9071
Klue RoBERTa Base
기본NoSpaceAllSpaceRandom
Train 기본0.913360.880680.70130.81746
Train NoSpace0.910140.89280.739920.84966
Train AllSpace0.882480.847120.892440.85532
Train Random0.90390.884180.87230.88838
Beomi KcBert Base
기본NoSpaceAllSpaceRandom
Train 기본0.905080.880360.732220.82366
Train NoSpace0.892160.882620.768960.83242
Train AllSpace0.859860.843320.889260.8565
Train Random0.892120.879880.869620.88248
HanBert 54kN Base
기본NoSpaceAllSpaceRandom
Train 기본0.905940.87330.742260.82358
Train NoSpace0.898680.89110.81710.8501
Train AllSpace0.876060.851560.889360.85506
Train Random0.894080.881420.870720.88

미세조정: Klue YNAT

따라해보기

python src/finetuning/sequence_classification.py --model_name_or_path kiwi-farm/roberta-base-32k --output_dir results --dataset klue --subset ynat --key title --num_train_epochs 3

python src/finetuning/sequence_classification.py --model_name_or_path kiwi-farm/roberta-base-64k --output_dir results --dataset klue --subset ynat --key title --num_train_epochs 3

python src/finetuning/sequence_classification.py --model_name_or_path klue/roberta-base --output_dir results --dataset klue --subset ynat --key title --num_train_epochs 3

python src/finetuning/sequence_classification.py --model_name_or_path beomi/kcbert-base --output_dir results --dataset klue --subset ynat --key title --num_train_epochs 3
Kiwi RoBERTa Base (32k)
기본NoSpaceAllSpaceRandom
Train 기본0.865700.852750.843960.83814
Train NoSpace0.862740.855600.843960.84671
Train AllSpace0.864490.843960.855820.83902
Train Random0.866030.857360.843850.84737
Kiwi RoBERTa Base (64k)
기본NoSpaceAllSpaceRandom
Train 기본0.865810.857800.840340.84034
Train NoSpace0.866910.864490.841000.84769
Train AllSpace0.867240.855600.859440.84802
Train Random0.865480.863290.846160.85198
Klue RoBERTa Base
기본NoSpaceAllSpaceRandom
Train 기본0.868450.824310.430430.71186
Train NoSpace0.871520.857030.531670.76128
Train AllSpace0.801250.776100.784010.75974
Train Random0.860540.844950.689570.81058
Beomi KcBert Base
기본NoSpaceAllSpaceRandom
Train 기본0.837700.796200.295590.65279
Train NoSpace0.829800.816180.319970.67179
Train AllSpace0.743710.718450.773030.72823
Train Random0.818050.804320.595910.77709
HanBert 54kN Base
기본NoSpaceAllSpaceRandom
Train 기본0.866800.825730.515640.72976
Train NoSpace0.852970.825950.504440.73448
Train AllSpace0.771050.745360.767980.73679
Train Random0.849010.819690.658720.78851

참고

About

Kiwi 형태소 분석기를 활용한 딥러닝 언어 모델 실험실

Topics

Resources

Stars

Watchers

Forks

Languages