LLM 평가는 점수만 확인하는것이 아니라 항목을 함께 확인한다.
학습 지표 (Training Metrics)
학습 과정에서 모델이 제대로 학습되고 있는지 확인
Training Loss: HuggingFace의 Trainer trainer.train()로 로그확인 {'loss': 1.31} {'loss': 0.94}
Validation Loss: 학습하지 않은 Validation 데이터에서의 Loss 과적합 여부 확인 trainer.evaluate()
Perplexity (PPL): 모델이 다음 단어를 얼마나 헷갈리는지의 지표 낮을수록 좋다. exp()
자동 평가 (Automatic Evaluation)
사람 없이 자동으로 계산하는 평가
ROUGE: 요약, 번역, 생성형 AI에서 생성된 문장과 정답 문장이 얼마나 겹치는지 평가 rouge = load("rouge") rouge.compute(predictions=A, references=B)
BERTScore: ROUGE보다 최신 방법, 단어가 달라도 의미가 비슷하면 높은 점수 bertscore = load("bertscore") bertscore.compute(predictions=A, references=B, lang="ko")
정확도: sklearn.metrics의 accuracy_score(y_true,y_pred)
형식 준수율 (Format Compliance): LLM이 원하는 출력 형식을 얼마나 잘 지키는지 평가
비교 평가 (Comparison Evaluation)
파인튜닝 전 모델 Base 모델를 학습후 모델인 Fine-tuned 모델과 함께 동일한 질문을 입력해 승률 비교 (Win Rate)
사람 평가 (Human Evaluation)
사실이 맞는지에 대한 정확성
질문에 맞게 답했는지에 대한 관련성
필요한 내용을 빠짐없이 설명했는가에 따른 오나전성
문장이 자연스러운가의 한국어 자연스러움 (Fluency)
욕설, 개인정보 노출, 위험한 허위정보 등 유해하거나 잘못된 정보를 생성하지는 않는지에 대한 안정성
실세 서비스 환경에서의 성능평가.
응답 지연 시간 (Latency): 응답 완료 시각 - 요청 시각
처리량 (Throughput): 단위 시간당 처리 가능한 요청 또는 토큰 수
GPU 메모리 사용량: torch.cuda.memory_allocated(), torch.cuda.max_memory_allocated()
실패율 (Failure Rate): 실패 요청 수 / 전체 요청 수
최종 모델은 여러지표를 합쳐 판단하며 종합평가표를 작성한다.
모든 점수가 좋아야하는 것은 아니며 답변 품질이 크게 향상되고 응답속도가 10% 느려졌어도 서비스 목표에서 허용가능한 범위라면 배포 할 수 있다. 평가절차에 어떠한 모델인지 목적을 정의하고
자동평가 Loss, Perplexity, ROUGE, BERTScore, Exact Match, 형식 준수율, 응답시간, 처리속도
모델 이름을 숨기고 두 답변의 블라인드 사람평가,
전체 평균만 보지않고 개념질문, 고객상담, JSON 출력, 안전질문 등 카테고리별 오류 분석,
배포기준에 맞는지 확인 BERTScore F1, 사람 평가조정 승률, JSON 준수율, 환각률, 평균 응답시간, 치명적 안전 오류
실패 사례를 저장해 원인분석, 데이터 보완, 재학습, 동일평가 재실행을 하고
반복평가한다.
"""
LLM Evaluation Pipeline
"""
import math
import json
import time
import torch
from evaluate import load
from sklearn.metrics import accuracy_score
#####################################################
# HuggingFace Evaluate
#####################################################
rouge = load("rouge")
bertscore = load("bertscore")
bleu = load("bleu")
meteor = load("meteor")
exact_match = load("exact_match")
sacrebleu = load("sacrebleu")
# perplexity = load("perplexity") # 지원 모델 필요
#####################################################
# 1. Training Metrics
#####################################################
training_loss = 0.93
validation_loss = 0.88
perplexity = math.exp(validation_loss)
#####################################################
# 2. Automatic Evaluation
#####################################################
predictions = [
"고양이는 매우 귀여운 동물이다."
]
references = [
"고양이는 귀여운 동물이다."
]
print(rouge.compute(
predictions=predictions,
references=references
))
print(bertscore.compute(
predictions=predictions,
references=references,
lang="ko"
))
print(bleu.compute(
predictions=predictions,
references=[[references[0]]]
))
print(meteor.compute(
predictions=predictions,
references=references
))
print(exact_match.compute(
predictions=["서울"],
references=["서울"]
))
print(sacrebleu.compute(
predictions=predictions,
references=[[references[0]]]
))
#####################################################
# Accuracy
#####################################################
print(
accuracy_score(
[1,0,1,1],
[1,0,1,0]
)
)
#####################################################
# Format Compliance
#####################################################
outputs = [
'{"name":"홍길동"}',
'{"age":20}',
'홍길동입니다.'
]
success = 0
for output in outputs:
try:
json.loads(output)
success += 1
except:
pass
format_rate = success / len(outputs)
#####################################################
# Win Rate
#####################################################
winner = [
"fine",
"fine",
"base",
"fine",
"fine"
]
win_rate = winner.count("fine") / len(winner)
#####################################################
# Human Evaluation
#####################################################
human = {
"Correctness":4.8,
"Relevance":4.7,
"Completeness":4.8,
"Fluency":4.9,
"Safety":5.0
}
#####################################################
# Latency
#####################################################
start = time.time()
# model.generate(...)
time.sleep(0.7)
latency = time.time() - start
#####################################################
# Throughput
#####################################################
tokens = 512
throughput = tokens / latency
#####################################################
# GPU
#####################################################
if torch.cuda.is_available():
gpu = torch.cuda.max_memory_allocated() / 1024**2
#####################################################
# Failure Rate
#####################################################
failure_rate = 5 / 1000
#####################################################
# Hallucination Rate
#####################################################
hallucination_rate = 0.03
#####################################################
# Summary
#####################################################
summary = {
"Training Loss":training_loss,
"Validation Loss":validation_loss,
"Perplexity":perplexity,
"ROUGE-L":0.91,
"BERTScore F1":0.95,
"BLEU":0.73,
"METEOR":0.84,
"Exact Match":0.92,
"Format Compliance":format_rate,
"Win Rate":win_rate,
"Latency":latency,
"Throughput":throughput,
"Failure Rate":failure_rate,
"Hallucination Rate":hallucination_rate
}
for k,v in summary.items():
print(k,":",v)
모델이 사람의 의도에 맞는 답변을 하도록 지속적으로 개선하는 핵심과정
파인튜닝(Fine-tuning): 특정 업무를 잘하게 만들기 위해 기존 모델을 새로운 데이터로 추가 학습
강화학습(Reinforcement Learning): 사람이 선호하는 답변을 만들 때 보상(Reward)을 최대화하도록 학습, 현재질문 State, 모델이 생성한 답변 Action, 사람이 준 점수 Reward, 답변 생성 방법 Policy, 사용자와 서비스 환경 Environment으로 구성된다.
피드백 루프(Feedback Loop): 배포 후 지속적으로 성능을 개선할 때 서비스 데이터를 다시 학습에 활용하는 반복 과정
RLHF Reinforcement Learning from Human Feedback
사람 대신 점수를 주는 AI Reward Model를 활용한다.
Reward Model이 점수를 주고 PPO가 모델을 업데이트한다.
핵심은 reward = 0.95과 ppo_trainer.step(...)
from transformers import AutoTokenizer
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead
model_name = "gpt2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLMWithValueHead.from_pretrained(model_name)
config = PPOConfig(
learning_rate=1e-5
)
ppo_trainer = PPOTrainer(
config=config,
model=model,
tokenizer=tokenizer
)
query = "AI란 무엇인가?"
response = "AI는 인간의 지능을 모방하는 기술입니다."
# Reward Model이 계산했다고 가정
reward = 0.95
ppo_trainer.step(
[query],
[response],
[reward]
)
PPO (Proximal Policy Optimization : 근접 정책 최적화)
RLHF 에서 가장 많이 사용되었다.
기존 정책에서 너무 크게 변하지 않도록 제한하면서 정책을 최적화하는 강화학습 알고리즘
핵심은 ppo_trainer.step()
queries = [
"파이썬이란?"
]
responses = [
"파이썬은 프로그래밍 언어입니다."
]
rewards = [
0.92
]
ppo_trainer.step(
queries,
responses,
rewards
)
DPO (Direct Preference Optimization : 직접 선호도 최적화)
사람이 선호 데이터를 직접 이용하여 언어 모델을 최적화하는 학습 방법
최근에는 PPO대신 DPO가 많이 사용된다. PPO는 강화학습이 필요한 반면 DPO는 좋은 답 나쁜답만 있으면 됨으로.
성능은 모델보다 데이터 쌍의 품질에 크게 좌우됨으로 단순히 길고 친절한 답이 아니라 실제 서비스 정책과 정확성 기준을 만족해야한다.
sample = {
"prompt":"AI란?",
"chosen":"AI는 인간의 학습과 추론을 모방하는 기술입니다.",
"rejected":"AI는 컴퓨터입니다."
}
from trl import DPOTrainer
trainer = DPOTrainer(
model=model,
train_dataset=train_dataset
)
trainer.train()
피드백 루프(Feedback Loop)
서비스에서 수집된 사용자 반응을 다시 학습 데이터로 활용하여 모델을 지속적으로 개선하는 순환 구조
좋은 평가만 저장해 학습 데이터를 생성하고 다시 파인튜닝하는 과정.
feedback = {
"question":"환불해주세요.",
"answer":"회원가입 방법입니다.",
"rating":1
}
feedback_db.append(feedback)
good_data = []
for fb in feedback_db:
if fb["rating"] >= 4:
good_data.append(fb)
train_dataset = []
for data in good_data:
train_dataset.append({
"instruction":data["question"],
"output":data["answer"]
})
trainer.train()
runpod 실습
https://standout.tistory.com/1932
RunPod 사용해보기: 서비스 배포해 브라우저로 접속하기
runpod 로그인https://standout.tistory.com/1927 RunPod 사용해보기: ssh 키 등록, pod 만들기, workload 선택RunPodAI, 머신러닝 및 일반 컴퓨팅 요구 사항을 위해 구축된 클라우드 컴퓨팅 플랫폼시간당 0.29달러 (400
standout.tistory.com