또르르's 개발 Story

[Stage 2 - 05] Pororo 라이브러리 사용하기 본문

[P Stage 2] KLUE/프로젝트

[Stage 2 - 05] Pororo 라이브러리 사용하기

또르르21 2021. 4. 20. 17:04

 1️⃣ Goal

 

  • [BaseLine 작성] (추가 : 4/12, 새로운 Baseline code)

  • [Data Processing]

    - Exploratory Data Analysis (추가 : 4/12, 기간 : 4/12 ~ )


    - Cross-validation 사용 (추가 : 4/12)

    - 데이터 불균형 해소 (추가 : 4/12)

    - 한국어 전처리 (추가 : 4/13, 기간 : 4/13 ~ 4/13 )

    - 새로운 tokenizer 사용 (추가 : 4/12, 기간 : 4/13 ~ ) 

    - 형태소 분류기 -> BERT wordpiece (추가 : 4/13)

    - [ENT][/ENT] tag를 추가해서 train 돌리기 (추가 : 4/14, 기간 : 4/20 ~ )

    - Pororo 사용해보기 (추가 : 4/20, 기간 : 4/20 ~ )

  • [Model]

    - BERT 모델 사용 (추가 : 4/12, 기간 : 4/14 ~ )

    - Roberta 모델 사용 (추가 : 4/20, 기간 : 4/20 ~ )

    - xlm-roberta 모델 사용 (추가 : 4/20)

    - GPT 모델 사용 (추가 : 4/12)

    - ELECTRA 모델 사용 (추가 : 4/12)

    - KoBERT 모델 사용 (추가 : 4/12)

  • [Training]

    - 앙상블 시도 (추가 : 4/12)

    - Hyperparameter 변경 (추가 : 4/12)

    - Learning Schedular 사용 (추가 : 4/12)

    - 좋은 위치에서 Checkpoint 만들기 (추가 : 4/12)

    - Wandb (Auto ML) 사용 (추가 : 4/12)

  • [Deploy]

    - Python 모듈화 (추가 : 4/12)

 

 

 

 

2️⃣ Learning

1) 문장 토큰 관계 분류 task (토큰마다 Labeling)

dororo21.tistory.com/139

 

[Stage 2 - 이론] 문장 토큰 관계 분류 task

주어진 문장의 각 token이 어떤 범주에 속하는지 분류하는 task입니다. 1️⃣ Named Entity Recognition (NER) 개체명 인식은 문맥을 파악해서 인명, 기관명, 지명 등과 같은 문장 또는 문서에서 특정한 의미

dororo21.tistory.com

 

2) 문장 토큰 단위 분류 모델 학습

 

dororo21.tistory.com/142

 

[Stage 2 - 이론] 문장 토큰 단위 분류 모델 학습

또르르's 개발 Story [Stage 2 - 이론] 문장 토큰 단위 분류 모델 학습 본문 [P Stage 2] KLUE/이론 [Stage 2 - 이론] 문장 토큰 단위 분류 모델 학습 또르르21 또르르21 2021. 4. 20. 22:30 Prev 1 2 3 4 5 6 ··· 142 Next

dororo21.tistory.com

 

 

3) 기계독해 모델 학습

dororo21.tistory.com/143

 

[Stage 2 - 이론] 기계독해 모델 학습

또르르's 개발 Story [Stage 2 - 이론] 기계독해 모델 학습 본문 [P Stage 2] KLUE/이론 [Stage 2 - 이론] 기계독해 모델 학습 또르르21 또르르21 2021. 4. 21. 00:17 Prev 1 2 3 4 5 ··· 142 Next

dororo21.tistory.com

 

 

3️⃣ Main Task

1) pororo 사용

 

카카오브레인에서 개발한 poror를 사용하면 ner(Named Entity Recognition)을 사용할 수 있다고 해서 pororo를 사용해보았습니다.

 

pororo를 import합니다.

from pororo import Pororo

 

ner은 한 문장만 추가하면 사용이 가능합니다.

# pororo ner

ner = Pororo(task="ner", lang="ko")

 

 

2) pororo 사용한 tokenizer dataset 수정

캠퍼분이 올려주신 새로운 Entity 구분 방법 연구에 대해서 올려주셔서 따라해보았습니다.

링크 : https://arxiv.org/pdf/2102.01373.pdf

 

[Wenxuan Zhou et al., arXiv 2021]

 

즉, 이 방식은 @ * entity01의 개체명 * entity01@#^ entity02의 개체명^ entity02 # 형태로 넣어줍니다. #과 @는 entity를 감싸고, *,^은 entity가 나타내는 개체를 감싸서 만드는 방식입니다.

 

[Wenxuan Zhou et al., arXiv 2021]

 

따라서 tokenized_dataset에서 형태를 변경해서 넣어주었습니다.

concat_entity는 기존 방식이며, sentence_list는 새롭게 #,@,\,^를 사용해 전체 sentence에서 entity와 개체명을 구분해주었습니다.

 

def tokenized_dataset(dataset, tokenizer, ner):
  concat_entity = []
  for e01, e02 in zip(dataset['entity_01'], dataset['entity_02']):
    temp = ''
    temp = '#'+e01+' # ' + '[SEP]' + '@' + e02 + ' @ '
    concat_entity.append(temp)

  sentence_list = []
  for sent, ent01, ent02, start1, end1, start2, end2 in tqdm(zip(dataset['sentence'], dataset['entity_01'], dataset['entity_02'],\
          dataset['entity_01_idx0'], dataset['entity_01_idx1'], dataset['entity_02_idx0'], dataset['entity_02_idx1']), total=len(dataset['sentence'])):

      ner_01 = ' ₩ '+ner(ent01)[0][1].lower()+' ₩ '
      ner_02 = ' ^ '+ner(ent02)[0][1].lower()+' ^ '

      start1, end1 = int(start1), int(end1)
      start2, end2 = int(start2), int(end2)

      if start1 < start2:
          sent = sent[:start1]+'#'+ner_01+sent[start1:end1+1]+' # '+sent[end1+1:start2]+\
              '@'+ner_02+sent[start2:end2+1]+ ' @ '+sent[end2+1:]
      else:
          sent = sent[:start2] + '@' + ner_02 + sent[start2:end2 + 1] + ' @ ' + sent[end2 + 1:start1] + \
                 '#' + ner_01 + sent[start1:end1 + 1] + ' # ' + sent[end1 + 1:]

      sentence_list.append(sent)


  tokenized_sentences = tokenizer(
      concat_entity,
      sentence_list,
      # list(dataset['sentence']),  # 2개의 [sep]를 비교하기 때문에?
      return_tensors="pt",
      max_length=200,
      padding='max_length',
      truncation='longest_first',
      add_special_tokens=True,
      )
  return tokenized_sentences

 

이후, model에 special token을 추가해주었습니다.

special_tokens_dict = {'additional_special_tokens': ["#", "@", '₩', '^']}

num_added_toks = tokenizer.add_special_tokens(special_tokens_dict)

 

결과는 다음과 같습니다.

 

  • (기존방식) tokenized_sentence : "entity01[SEP]entity02" + "전체 문장"

    - 하
    이퍼파라미터 : epoch-4, checkpoint-2000, batch_size-16, Model-"bert-base-multilingual-cased"

 

 

  • (시도 1) tokenized_sentence : "#,@,\,^를 사용해서 구분한 전체 문장"

    - 하이퍼파라미터 : epoch-10, checkpoint-5000, batch_size-16, Model-"bert-base-multilingual-cased"

    - Public score를 비교해보았을 때 성능이 약간 떨어지는 것을 알 수 있습니다.

 

 

  • (시도 2) tokenized_sentence : "#entity01 # [SEP] @entity02 @" + "#,@,\,^ 전체 문장"

    - 하이퍼파라미터 : epoch-10, checkpoint-2500, batch_size-16, Model-"bert-base-multilingual-cased"

    - 기존 방식보다는 성능이 떨어지지만, 시도1보다는 약간의 성능이 오른 것을 알 수 있습니다.

 

 

 

  • (시도 3) tokenized_sentence : "#entity01 # [SEP] @entity02 @" + "#,@,\,^ 전체 문장"

    - 하이퍼파라미터 : epoch-20, checkpoint-9000, batch_size-16, Model-"bert-base-multilingual-cased"

    - 시도 2에서 더 많은 epoch을 돌렸을 때의 결과입니다.

    - overfitting을 체크하기 위해 돌려봤는데 시도 2보다 성능이 내려간 것을 알 수 있습니다.

 

 

 

  • (시도 4) tokenized_sentence : "# \ entity01개체명 \ entity01 # [SEP] @ ^ entity02 개체명 ^ entity02 @" + "#,@,\,^ 전체 문장"

    - 하이퍼파라미터 : epoch-5, checkpoint-1500, batch_size-16, Model-"bert-base-multilingual-cased"

    - 가장 좋은 성능을 보였으며, bert 모델임에도 불구하고 74.5% 성능이 나왔습니다.

 

 

 

 

4️⃣ Sub Task

 

없음.

 

5️⃣ Evaluation

 

Data processing
& Tokenizer
Model Training Time Accuracy
4/13 -
EDA
-
    1h -
4/13     -
new baseline
code
-
30m 59.3000%
4/14   -
KoBERT
-
-
epoch : 20
max_len : 128
batch_size : 32
-
23m 72.0000%
4/17   -
"bert-base-multilingual-cased"
BERT
-
-
epoch : 4
batch_size : 16
-
14m 72.8000%
4/19 -
"entity01[SEP]entity02" + "[ENT]가 들어간 전체 문장"
-
    16m 71.2000%
4/19 -
"[ENT]가 들어간 전체 문장"

-
    17m 52.5000%
4/20 -
pororo NER
-
"#,@,\,^를 사용해서 구분한 전체 문장"
-
  -
epoch : 10
checkpoint : 5000
-
50m 70.8000%
4/20 -
"#entity01 # [SEP] @entity02 @"
+
"#,@,\,^ 전체 문장"
-
  -
checkpoint : 2500
-
16m 71.6000%
4/20 -
"# \ entity01개체명 \ entity01 # [SEP] @ ^ entity02 개체명 ^ entity02 @"
+
"#,@,\,^ 전체 문장"
-

  -
epoch : 5
checkpoint : 1500
-
12m  74.5000%
           

 

 

1) pororo 사용

pororo의 NER 기능은 정말 강력한 것 같습니다.

더 많이 사용할 수 있는 방향을 생각해보아야 할 것 같습니다.

 

2) pororo 사용한 tokenizer dataset 수정

논문에서 이미 tokenizer의 여러 방향에 대해서 연구했고, 이 부분을 따라하는 것이 좋다고 생각합니다.

하지만 논문에서는 roberta를 사용했기 때문에 저도 차후에 roberta나 xlm-roberta로 성능을 평가해 보려고 합니다.

 

4) 차후 목표

  • roberta 사용
  • xlm-roberta 사용
  • entity layer 추가 (추가 작성)
    model.bert.BertEmbeddings.set_entity_embeddings(entity) # 이렇게 수정해보기
  • 형태소 -> wordpiece tokenizer 사용해보기
  • 음절 단위로 tokenizer 나눠보기

 

Comments