본문 바로가기
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' 카테고리의 다른 글

[논문 리뷰] BPE Tokenizer  (1) 2024.02.04
[논문 리뷰]attention 매커니즘  (0) 2024.01.31
워드 임베딩 시각화  (0) 2024.01.31
임베딩  (0) 2024.01.24
데이터 전처리 실습  (0) 2024.01.19