Bomb Kirby Running
본문 바로가기
AI

KLUE

by 코낄2 2024. 2. 2.

1. KLUE(Korea Language Understanding Evaluation)

KLUE(Korea Language Understanding Evaluation)는 한국어 자연어 이해 평가를 위한 데이터셋으로, 다양한 종류의 자연어 처리 과제를 포함하고 있습니다. 이 데이터셋은 한국어 언어모델을 공정하게 평가하기 위해 공개되었으며, 총 8가지 종류의 과제를 포함하고 있습니다. 이 중 일부 과제에 대해 간략한 소개를 해보겠습니다.

  1. 뉴스 헤드라인 분류: 주어진 뉴스 헤드라인을 분류하는 과제로, 주제나 카테고리를 정확하게 예측하는 능력을 평가합니다.
  2. 문장 유사도 비교: 두 문장 간의 유사도를 비교하는 과제로, 문장 간의 의미적 유사성을 평가합니다.
  3. 자연어 추론: 주어진 전제와 가설 사이의 관계를 추론하는 과제로, 문장 간의 논리적 관계를 이해하는 능력을 측정합니다.
  4. 개체명 인식: 주어진 텍스트에서 명명된 엔터티(개체)를 인식하는 과제로, 텍스트에서 중요한 정보를 추출하는 능력을 평가합니다.
  5. 관계 추출: 문장에서 다양한 엔터티 간의 관계를 추출하는 과제로, 정보 추출 및 관계 파악 능력을 평가합니다.
  6. 형태소 및 의존 구문 분석: 문장의 형태소 구조 및 의존 구문을 분석하는 과제로, 문장의 구조를 정확하게 이해하는 능력을 측정합니다.
  7. 기계 독해 이해: 주어진 텍스트에 대한 질문에 답하는 과제로, 기계 독해 능력을 평가합니다.
  8. 대화 상태 추적: 대화에서 발생하는 다양한 상태를 추적하는 과제로, 대화 이해 및 상태 추적 능력을 측정합니다.

KLUE의 학습 데이터는 광범위한 주제와 다양한 스타일을 포괄하기 위해 여러 출처에서 수집되었습니다. 약 62GB 크기의 최종 사전 학습 코퍼스는 MODU, CC-100-Kor, 나무위키, 뉴스 스크롤, 청원 등의 다양한 데이터셋으로 구성되어 있습니다. 이러한 다양한 데이터를 사용하여 한국어 언어모델의 성능을 향상시키고 평가하는 것이 KLUE의 목표입니다.

2. KLUE-TC Task

KLUE-TC(Task: Topic Classification)은 한국어 텍스트의 주제를 분류하는 과제를 다룹니다. 이 과제의 목적은 주어진 문장이나 텍스트가 어떤 주제에 속하는지를 정확하게 분류하는 것입니다.

!pip install -U transformers datasets scipy scikit-learn
!pip install accelerate -U
import datasets
import random
import pandas as pd
import numpy as np
from datasets import load_dataset, ClassLabel, load_metric
from IPython.display import display, HTML
from transformers import AutoTokenizer, pipeline, AutoModelForSequenceClassification, Trainer, TrainingArguments
# task = ['ynat', 'sts', 'nli', 'ner', 're', 'dp', 'mrc', 'wos']
# 감정분석(Yes/No Answering Task, YNAT) : 주어진 문장에 대해 '예','아니오'로 대답하는 작업
model_checkpoint = 'klue/roberta-base'
batch_size = 64
task = 'ynat'
datasets = load_dataset('klue', task)

DatasetDict({
    train: Dataset({
        features: ['guid', 'title', 'label', 'url', 'date'],
        num_rows: 45678
    })
    validation: Dataset({
        features: ['guid', 'title', 'label', 'url', 'date'],
        num_rows: 9107
    })
})
# datasets에 train 데이터 인덱스 0~9까지 출력
datasets['train'][:10]
{'guid': ['ynat-v1_train_00000',
  'ynat-v1_train_00001',
  'ynat-v1_train_00002',
  'ynat-v1_train_00003',
  'ynat-v1_train_00004',
  'ynat-v1_train_00005',
  'ynat-v1_train_00006',
  'ynat-v1_train_00007',
  'ynat-v1_train_00008',
  'ynat-v1_train_00009'],
 'title': ['유튜브 내달 2일까지 크리에이터 지원 공간 운영',
  '어버이날 맑다가 흐려져…남부지방 옅은 황사',
  '내년부터 국가RD 평가 때 논문건수는 반영 않는다',
  '김명자 신임 과총 회장 원로와 젊은 과학자 지혜 모을 것',
  '회색인간 작가 김동식 양심고백 등 새 소설집 2권 출간',
  '야외서 생방송 하세요…액션캠 전용 요금제 잇따라',
  '월드컵 태극전사 16강 전초기지 레오강 입성종합',
  '미세먼지 속 출근길',
  '왓츠앱稅 230원에 성난 레바논 민심…총리사퇴로 이어져종합2보',
  '베트남 경제 고성장 지속…2분기 GDP 6.71% 성장'],
 'label': [3, 3, 2, 2, 3, 0, 5, 3, 4, 4],
 'url': ['https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=105&sid2=227&oid=001&aid=0008508947',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=103&sid2=248&oid=001&aid=0008384783',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=105&sid2=228&oid=001&aid=0008254585',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=105&sid2=228&oid=001&aid=0009070646',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=103&sid2=243&oid=001&aid=0009999529',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=105&sid2=226&oid=001&aid=0008547867',
  'https://sports.news.naver.com/news.nhn?oid=001&aid=0010126131',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=103&sid2=248&oid=001&aid=0009817982',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=104&sid2=234&oid=001&aid=0011176999',
  'https://news.naver.com/main/read.nhn?mode=LS2D&mid=shm&sid1=104&sid2=231&oid=001&aid=0010921012'],
 'date': ['2016.06.30. 오전 10:36',
  '2016.05.08. 오전 5:25',
  '2016.03.15. 오후 12:00',
  '2017.02.28. 오전 9:54',
  '2018.04.03. 오전 7:05',
  '2016.07.18. 오전 9:46',
  '2018.06.04 08:15',
  '2018.01.17. 오전 10:14',
  '2019.10.30. 오전 4:17',
  '2019.06.28. 오후 5:42']}
# show_random_elmenets(dataset, num_examples=10)
# train에서 랜덤하게 매개변수에 전달된 갯수만큼 데이터프레임으로 변환하여 출력
def show_random_elmenets(dataset, num_examples):
    random_indices = random.sample(range(len(dataset)), num_examples)
    random_examples = [dataset[i] for i in random_indices]
    df = pd.DataFrame(random_examples)

    labels = dataset.features['label'].names

    df['label'] = df['label'].apply(lambda x: labels[x])
    return df
    
show_random_elmenets(datasets['train'], 10)

metric = load_metric('f1')

F1 스코어는 분류 모델의 성능을 측정하는 지표 중 하나로, 정밀도(Precision)와 재현율(Recall)의 조화 평균을 나타냅니다.

그런 다음 metric 객체를 사용하여 모델의 예측과 실제 레이블을 기반으로 F1 스코어를 계산할 수 있습니다.

# 가상의 예측과 정답을 만들어서 f1스코어 측정해보기

fake_preds = np.random.randint(0,2, size=(64,))
fake_labels = np.random.randint(0,2, size=(64,))
fake_preds, fake_labels

(array([1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0,
        1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,
        1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0]),
 array([1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1,
        1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1,
        0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]))
        
metric.compute(predictions=fake_preds, references=fake_labels)
//{'f1': 0.5753424657534246}
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, use_fast=True)
# use_fast=True 토큰 생성 속도 늘리기
tokenizer('테슬라 9주 개미, 세계 1위 부자 이겼다…머스크, 74조원 날릴판')

{'input_ids': [0, 20717, 29, 2223, 12646, 16, 3665, 21, 2090, 5741, 12320, 2062, 121, 28035, 16, 6946, 2446, 2252, 29527, 2025, 2], 
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
  1. input_ids: 이것은 토큰화된 입력 시퀀스에 대한 토큰 ID들의 리스트입니다. 이 리스트의 첫 번째 토큰은 일반적으로 [CLS] 토큰을 나타내고, 마지막 토큰은 [SEP] 토큰을 나타냅니다.
  2. token_type_ids: 주로 두 문장을 구분할 때 사용됩니다. 단일 문장의 경우 일반적으로 0으로 설정됩니다.
  3. attention_mask: 실제 단어의 위치를 나타내는 마스크입니다. 실제 단어에 대응하는 부분은 1로 표시되며, 패딩된 부분은 0으로 표시됩니다. 이것은 패딩된 부분이 모델에 의해 무시되도록 하기 위한 것입니다.
def preprocess_function(examples):
    return tokenizer(
        examples['title'],
        truncation=True,
        return_token_type_ids=False 
        # 토큰 타입 ID를 반환하지 않음. 단일 문장에서는 필요가 없음
    )
preprocess_function(datasets['train'][:5])

{'input_ids': [[0, 10637, 8474, 22, 2210, 2299, 2118, 28940, 3691, 4101, 3792, 2], 
[0, 24905, 1042, 4795, 19982, 2129, 121, 6904, 16311, 3, 14392, 2], 
[0, 4172, 3797, 3728, 2107, 2134, 3777, 904, 6022, 2332, 2113, 2259, 4523, 1380, 2259, 2062, 2], 
[0, 12417, 2155, 7840, 604, 2859, 3873, 11554, 2522, 1539, 2073, 8446, 6626, 18818, 575, 2], 
[0, 13203, 2179, 2366, 4197, 7551, 2096, 8542, 2088, 2353, 886, 1244, 4393, 2027, 22, 2207, 8189, 2]], 
'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}
encoded_datasets = datasets.map(preprocess_function, batched=True)
num_labels = 7
model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels = num_labels)
# average = 'macro' : macro는 평가하려는 매트릭
# 클래스마다 동일한 가중치를 적용하여 평균을 계산하는 방법
# 평균을 클래스별로 각각의 평균을 계산하고, 이들의 평균을 구함
def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    predictions = np.argmax(predictions, axis = 1)
    return metric.compute(predictions=predictions, references = labels, average='macro')
metric_name = 'f1'

# evaluation_strategy: 평가전략. epoch: 에폭이 끝날 때마다 평가를 수행
# save_strategy: 모델 체크포인트를 저장하는 전략. epoch: epoch 끝날 때마다 모델을 저장
# per_device_train_batch_size : 학습 시 배치 크기를 설정
# per_device_eval_batch_size : 평가 시 배치 크기를 설정
# num_train_epochs: 전체 학습 에폭의 수를 설정
# weight_decay : 가중치 감소의 설정
# load_best_model_at_end: 학습이 끝난 후 가장 좋은 성능을 보인 모델을 불러올지 여부를 지정
# metric_for_best_model: 최적의 모델을 결정할 때 사용할 메트릭을 지정, F1

args = TrainingArguments(
    'test-tc',
    evaluation_strategy = 'epoch',
    save_strategy='epoch',
    learning_rate=2e-5,
    per_device_train_batch_size= batch_size,
    per_device_eval_batch_size= batch_size,
    num_train_epochs = 5,
    weight_decay=0.01,
    load_best_model_at_end = True,
    metric_for_best_model = metric_name
)

weight_decay: 가중치 감소(Weight Decay)는 모델의 복잡도를 줄이고 오버피팅을 방지하는 데 사용됩니다. 이 항은 일반적으로 가중치의 크기에 비례하여 증가하고, 따라서 가중치를 줄이는 경향이 있습니다.

# Trainer: 모델의 학습과 평가를 관리하는 클래스
# 주어진 데이터셋으로부터 배치를 생성하고, 모델에 입력을 전달하여
# 손실을 계산하고 역전파를 수행함
trainer = Trainer(
    model,
    args,
    train_dataset = encoded_datasets['train'],
    eval_dataset = encoded_datasets['validation'],
    tokenizer = tokenizer,
    compute_metrics = compute_metrics
)

trainer.train()

classifier = pipeline(
    'text-classification',
    model = './test-tc/checkpoint-3570',
    return_all_scores=True
)
'''
0 (IT과학)
1 (경제)
2 (사회)
3 (생활문화)
4 (세계)
5 (스포츠)
6 (정치)
'''
classifier('주호민 아들 학대 특수교사, 벌금형 선고유예 "미필적 고의 인정"(종합)')

 

'AI' 카테고리의 다른 글

deep-text-recognition-benchmark 모델 ONNX 변환  (0) 2024.12.24
[논문 리뷰] BPE Tokenizer  (1) 2024.02.04
[논문 리뷰]attention 매커니즘  (0) 2024.01.31
워드 임베딩 시각화  (0) 2024.01.31
임베딩  (0) 2024.01.24