greatsangho의 이야기

캠프56일차 - 파인튜닝된 LLM 모델의 성능 평가 방법 본문

프로그래밍/SK AI 캠프

캠프56일차 - 파인튜닝된 LLM 모델의 성능 평가 방법

greatsangho 2024. 11. 14. 21:41

- 파인튜닝
  - LLM 모델에 소수의 데이터 또는 어떤 목적을 달성하기 위해서 기존 모델을 전체학습 하는게 아니라 해당 데이터만 학습해서 적용하는 방법
- 성능평가
  - 감정분석의 경우 분류문제 - Accuracy
  - 문장요약
    - 원본과 요약문의 유사도 측정과 같은 방법
    - 측정지표
      - ROUGE(Recall-Oriented Understudy for Gisting Evaluation)
        - 사용된 어휘 단어의 중복을 체크
        - n-gram의 겹치는 비율
        - Recall(재현율)에 중점을 둔 방법, 참조 텍스트의 중요한 내용을 얼마나 많이 포함하고 있는지 중점
        - 장점 : 문장의 유사성을 측정 가능
        - 단점 : 문맥상 맞지 않는 문장, 의미상 맞는 문장에 대한 오판 가능성
      - BLEU(Billingual Evaluation Understudy)
        - Precision(정밀도)에 중점을 둔 방식
          - 생성된 텍스트의 n-gram의 일치여부의 비율 측정
- n-gram
  - 연속된 n개의 단어 단위로 나누어진 텍스트 조각
  - 1-gram : 단어 하나로 이루어진 조각
  - 2-gram : 2개의 단어가 연속적으로 이루어진 조각
  - 'I love natural language processing'
  - 1-gram
    - "I" "love" "natural" ...
  - 2-gram
    - "I love" "love natural" ...
- Bench Marking
  - lm-eval-harness : 성능평가를 위한 벤치마킹 툴

 

이진 분류 모델의 평가

kogpt2 영화 리뷰

!pip install -q datasets
!pip install -q evaluate
!pip install -q rouge_score
!git clone https://github.com/e9t/nsmc nsmc

import torch
from transformers import GPT2LMHeadModel, TFGPT2Model, GPT2ForSequenceClassification

model_name = 'skt/kogpt2-base-v2'
model = GPT2ForSequenceClassification.from_pretrained(model_name,num_labels=2)
# 이진 분류를 위한 모델 로딩에 유의
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name, bos_token='</s>', eos_token='</s>', unk_token='<unk>',
  pad_token='<pad>', mask_token='<mask>')
import pandas as pd
train_data = pd.read_csv('nsmc/ratings_train.txt', sep='\t').loc[:,'document':].dropna()
test_data = pd.read_csv('nsmc/ratings_test.txt', sep='\t').loc[:,'document':].dropna()

train_data.drop_duplicates(inplace=True)
test_data.drop_duplicates(inplace=True)

# 전처리
# 정규식을 이요해서 한글만 추출
import re
def clean_text(text):
  text = re.sub('[^가-힣ㄱ-ㅎㅏ-ㅣ0-9a-zA-Z\\s]', '', text)
  return text

train_data['document'] = train_data['document'].apply(clean_text)
test_data['document'] = test_data['document'].apply(clean_text)

# 토큰의 길이를 결정
import numpy as np
MAX_LENGTH = int(np.percentile(train_data['document'].apply(lambda x: len(x.split())), 95))
MAX_LENGTH

# 데이터셋으로 변경
from datasets import Dataset
train_dataset = Dataset.from_pandas(train_data)
test_dataset = Dataset.from_pandas(test_data)
train_dataset = train_dataset.map(lambda x: tokenizer(x['document'], truncation=True, padding='max_length', max_length=MAX_LENGTH),batched=True)
test_dataset = test_dataset.map(lambda x: tokenizer(x['document'], truncation=True, padding='max_length', max_length=MAX_LENGTH),batched=False)

데이터를 불러와 전처리를 진행한 뒤 모델을 학습시키기 위한 데이터셋으로 변환한다.

# 학습
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
    output_dir='./results',          # output directory
    num_train_epochs=3,              # total number of training epochs
    per_device_train_batch_size=128,  # batch size per device during training
    per_device_eval_batch_size=128,   # batch size for evaluation
    warmup_steps=200,                # number of warmup steps for learning rate scheduler
    weight_decay=0.01,               # strength of weight decay
    logging_dir='./logs',            # directory for storing logs
    logging_steps=500,
    save_steps=1000,
    save_strategy='no',
    load_best_model_at_end=True,

)
def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return {"accuracy": (predictions == labels).mean()}
trainer = Trainer(
    model=model,                         # the instantiated 🤗 Transformers model to be trained
    args=training_args,                  # training arguments, defined above
    train_dataset=train_dataset,         # training dataset
    eval_dataset=test_dataset,            # evaluation dataset
    compute_metrics=compute_metrics,
)
#학습
trainer.train()

# 평가
results = trainer.evaluate()
print("Evaluation results:", results)

모델 학습은 다음과 같이 학습을 진행할 파라미터를 설정한 뒤, 모델을 학습 및 평가한다.

 

문장요약 평가
  - ROUGE : datasets load_metrix('rouge')

https://aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=realm&dataSetSn=90

 

AI-Hub

샘플 데이터 ? ※샘플데이터는 데이터의 이해를 돕기 위해 별도로 가공하여 제공하는 정보로써 원본 데이터와 차이가 있을 수 있으며, 데이터에 따라서 민감한 정보는 일부 마스킹(*) 처리가 되

aihub.or.kr

AI 허브에서 논문자료 요약 데이터를 받아 진행해본다.

파일 중 training_논문.zip과 validation_논문.zip을 사용한다.

import json
import pandas as pd
with open('/content/training_논문/논문요약20231006_0.json', 'r', encoding='utf-8') as f:
    train_data0 = json.load(f)

with open('/content/validation_논문/논문요약20231006_Validation.json', 'r', encoding='utf-8') as f:
    test_data = json.load(f)

def extract_data(data):
  summary_data = []
  for item in data[0]['data']:
      for section in item['summary_section']:
          summary_data.append({
              'original_text': section['orginal_text'],
              'summary_text': section['summary_text']
          })
  df = pd.DataFrame(summary_data)
  return df

train_df0 = extract_data(train_data0)
test_df = extract_data(test_data)

train_df0.to_csv('train0.csv', index=False)
test_df.to_csv('test.csv', index=False)

train_df = pd.read_csv('/content/train0.csv')
test_df = pd.read_csv('/content/test.csv')

train_df.dropna(inplace=True)
test_df.dropna(inplace=True)
train_df.drop_duplicates(inplace=True)
test_df.drop_duplicates(inplace=True)
train_df.reset_index(drop=True, inplace=True)
test_df.reset_index(drop=True, inplace=True)

import re
def remove_special_characters(text):
  pattern = r'[^\wㅏ-ㅣㄱ-ㅎ가-힣\s]'
  return re.sub(pattern, '', text)

train_df = train_df.map(remove_special_characters)
test_df = test_df.map(remove_special_characters)

train_df.shape, test_df.shape

json 형식이므로 다음과 같이 with open으로 불러온다. 불러온 데이터의 전처리를 진행한다. 데이터의 크기는 ((39998, 2), (17994, 2))이다.

import matplotlib.pyplot as plt
plt.figure(figsize=(12, 5))
train_df['original_text'].apply(lambda x: len(x.split())).hist(bins=50)
plt.xlabel('Length of Text')
plt.ylabel('Number of Text')
plt.title('Text Length Distribution')

# 데이터셋-문자길이
import numpy as np
MAX_LENGTH = int(np.percentile(train_df['original_text'].apply(lambda x: len(x.split())),90))
MAX_LENGTH # 189

해당 데이터를 시각화 하면 다음과 같다. 대략 80% 이상에 해당하는 범위에서 잘라준다.

# 모델로드
import torch
from transformers import GPT2LMHeadModel
model = GPT2LMHeadModel.from_pretrained('skt/kogpt2-base-v2')

# 토크나이져 로드
from transformers import PreTrainedTokenizerFast
tokenizer = PreTrainedTokenizerFast.from_pretrained("skt/kogpt2-base-v2",
  bos_token='</s>', eos_token='</s>', unk_token='<unk>',
  pad_token='<pad>', mask_token='<mask>')
  
# 평가지표 로드
import evaluate
import rouge_score
rouge = evaluate.load('rouge')

# 평가지표 함수
def complete_metrics(eval_pred):
  # 모델 예측과 실제 레이블을 받음
  predictions, labels = eval_pred
  # 예측값에서 가장 높은 확률을 가진 인덱스 선택 후, 리스트로 변환
  # 가장 높은 확률을 가진 인덱스를 선택하는 이유
    # 가능성이 가장 높은 단어를 선택해서 최종 예측값으로 사용
  predictions = np.argmax(predictions, axis=-1).tolist()
  labels = labels.tolist()
  # 예측과 레이블을 디코딩하여 텍스트로 변환
  decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)
  decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
  # ROUGE 점수계산
  result = rouge.compute(predictions=decoded_preds, references=decoded_labels, use_stemmer=True)
  return {
      "rouge1": result["rouge1"]*100,
      "rouge2": result["rouge2"]*100,
      "rougeL": result["rougeL"]*100,
      "rougeLsum": result["rougeLsum"]*100,
  }

# 입력 데이터에 labels 추가하는 함수
def preprocess_function(examples):
    # text를 토큰화하고 길이 맞추기
    inputs = tokenizer(examples['original_text'], truncation=True, padding='max_length', max_length=MAX_LENGTH)

    # labels에 input_ids를 그대로 복사
    inputs["labels"] = inputs["input_ids"].copy()
    return inputs


# dataset
from datasets import Dataset
train_dataset = Dataset.from_pandas(train_data)
test_dataset = Dataset.from_pandas(test_data)
train_dataset = train_dataset.map(preprocess_function, batched=True)
test_dataset = test_dataset.map(preprocess_function, batched=True)
# 학습
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
    output_dir='./results',          # output directory
    num_train_epochs=3,              # total number of training epochs
    per_device_train_batch_size=128,  # batch size per device during training
    per_device_eval_batch_size=128,   # batch size for evaluation
    warmup_steps=200,                # number of warmup steps for learning rate scheduler
    weight_decay=0.01,               # strength of weight decay
    logging_dir='./logs',            # directory for storing logs
    logging_steps=500,
    save_steps=1000,
    save_strategy='no',
    load_best_model_at_end=True,

)

trainer = Trainer(
    model=model,                         # the instantiated 🤗 Transformers model to be trained
    args=training_args,                  # training arguments, defined above
    train_dataset=train_dataset,         # training dataset
    eval_dataset=test_dataset,            # evaluation dataset
    compute_metrics=complete_metrics,
)
#학습
trainer.train()

# 평가
results = trainer.evaluate()
print(f'Evaluation results: {results}')

이와 같은 방법으로 평가할 수 있다.

반응형