https://product.kyobobook.co.kr/detail/S000214934825
한 권으로 끝내는 실전 LLM 파인튜닝 | 강다솔 - 교보문고
한 권으로 끝내는 실전 LLM 파인튜닝 | 실무 현장에서 꼭 필요한 파인튜닝, PEFT, vLLM 서빙 기술을 직접 실습하면서 배워 보자!AI 기술의 최전선에서 배우는 LLM 파인튜닝의 모든 것! 이론적 토대부터
product.kyobobook.co.kr
"한 권으로 끝내는 실전 LLM 파인튜닝" 교재를 활용해 3주(주말 제외) 동안 진행 되는 온라인 스터디
다중 GPU를 활용한 Llama3.1-8B-intstruct 파인튜닝
Llama3.1-8B-instruct 모델은 대규모 언어 모델로, 다양한 자연어 처리 작업에서 강력한 성능을 제공한다. 하지만 이러한 대규모 모델의 파인튜닝은 단일 GPU로 처리하기 어려운 경우가 많다. 이를 해결하기 위해 다중 GPU를 활용한 학습 방법과 효율적인 파이프라인 구성이 필요하다.
실습 파일 구성
- 0_full_fine_tuning_config.yaml
- 파인튜닝 과정에서 필요한 설정 정보를 정의
- 다중 GPU 환경 설정, 학습 파라미터, 데이터 경로 등이 포함
- 1_train_full_fine_tuning.py
- 다중 GPU를 활용한 모델 학습 코드를 포함
- 2_inference_notebook.py
- 학습된 모델이 실제 결과를 생성하는지 확인할 수 있는 노트북 파일
- 3_test.py
- 학습된 모델을 불러와 테스트 데이터셋에서 질문에 대한 응답을 생성
- 모델 출력과 정답을 함께 저장하여 후속 평가에 활용
- 4_openai_test.py
- 학습된 모델이 생성한 결과를 평가하기 위해 OpenAI API를 활용
- OpenAI GPT 모델과 비교하여 결과 품질을 채점하고, 학습된 모델의 성능을 정량적으로 파악
- 5_score_notebook.ipynb
- OpenAI가 제공한 점수를 분석하고, 모델 성능을 종합적으로 평가
1. Llama 3.1 학습 파라미터 설정(0_full_fine_tuning_config.yaml)
### 3.5.2. Llama3 학습 파라미터 설정
model_name: "meta-llama/Meta-Llama-3.1-8B-Instruct"
dataset_path: "."
max_seq_length: 512
output_dir: "./llama-3.1-korean-8b-hf-20-epoch"
report_to: "wandb"
learning_rate: 0.00005
lr_scheduler_type: "linear"
num_train_epochs: 5
per_device_train_batch_size: 2
per_device_eval_batch_size: 2
gradient_accumulation_steps: 4
optim: "adamw_torch_fused"
logging_steps: 10
save_strategy: "epoch"
weight_decay: 0.01
max_grad_norm: 0.5
warmup_ratio: 0.03
bf16: true
tf32: true
gradient_checkpointing: true
fsdp: "full_shard auto_wrap"
fsdp_config:
backward_prefetch: "backward_pre"
forward_prefetch: "false"
use_orig_params: "false"
2. 다중 GPU 활용 학습 (1_train_full_fine_tuning.py)
해당 코드는 Llama3.1-8B-instruct 모델을 다중 GPU 환경에서 파인튜닝하기 위한 전체적인 구조와 구현 내용을 담고 있다. 주요 기능을 단계별로 살펴보자.
필요한 라이브러리 및 모듈 불러오기
- Hugging Face의 transformers, datasets와 PyTorch 기반의 학습 도구를 사용
- trl 라이브러리를 사용하여 SFT(Instruction Fine-Tuning) 관련 도구와 템플릿을 지원
- peft를 통해 LoRA(Low-Rank Adaptation) 기법을 적용할 수 있도록 준비
- huggingface_hub로 Hugging Face Hub에 로그인하여 모델과 데이터셋을 관리
import logging
from dataclasses import dataclass, field
import os
import random
import torch
from datasets import load_dataset
from transformers import AutoTokenizer, TrainingArguments
from trl.commands.cli_utils import TrlParser
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
set_seed,
)
from trl import setup_chat_format
from peft import LoraConfig
from trl import (
SFTTrainer)
from sklearn.model_selection import train_test_split
# Load dataset from the hub
from huggingface_hub import login
login(
token="YOUR_API_TOKEN",
add_to_git_credential=True
)
데이터셋 준비 (1) : 데이터셋 로드
이준범(beomi) 님이 만든 KoAlpaca-v1.la 데이터셋 사용
네이버 지식인의 베스트 질문들을 크롤링해 수집된 데이터로, 질문 제목, 질문 본문, 그리고 채택된 답변 본문을 포함하고 있다.
dataset = load_dataset("beomi/KoAlpaca-v1.1a")
데이터셋 준비 (2) : 시스템 프롬프트 정의
모델이 답변을 생성할 때 사용할 기본 시스템 프롬프트를 설정
이는 학습 데이터의 messages 필드에 추가
system_prompt = "당신은 다양한 분야의 전문가들이 제공한 지식과 정보를 바탕으로 만들어진 AI 어시스턴트입니다. 사용자들의 질문에 대해 정확하고 유용한 답변을 제공하는 것이 당신의 주요 목표입니다. 복잡한 주제에 대해서도 이해하기 쉽게 설명할 수 있으며, 필요한 경우 추가 정보나 관련 예시를 제공할 수 있습니다. 항상 객관적이고 중립적인 입장을 유지하면서, 최신 정보를 반영하여 답변해 주세요. 사용자의 질문이 불분명한 경우 추가 설명을 요청하고, 당신이 확실하지 않은 정보에 대해서는 솔직히 모른다고 말해주세요."
데이터셋 준비 (3) : 데이터셋 변환
각 샘플을 시스템 프롬프트, 사용자 질문(instruction), 그리고 정답(output)으로 구성된 대화 형태로 변환
train_dataset = dataset.map(
lambda sample:
{ 'messages' : [
{"role": "system", "content": system_prompt},
{"role": "user", "content": sample['instruction']},
{"role": "assistant", "content": sample['output']}]
},
)
데이터셋 준비 (4) : 불필요한 열 제거 및 데이터셋 분리
학습에 필요하지 않은 열을 제거, 데이터셋을 학습용(train)과 테스트용(test)으로 9:1 비율로 분리
columns_to_remove = list(dataset["train"].features)
train_dataset = train_dataset.map(remove_columns=columns_to_remove, batched=False)
train_dataset = train_dataset["train"].train_test_split(test_size=0.1, seed=42)
데이터셋 준비 (5) : JSON 형식으로 저장
변환된 데이터셋을 JSON 파일로 저장하여 재사용성을 확보
train_dataset["train"].to_json("train_dataset.json", orient="records", force_ascii=False)
train_dataset["test"].to_json("test_dataset.json", orient="records", force_ascii=False)
Llama3 대화 템플릿 설정
- 대화 데이터를 텍스트 형식으로 변환하기 위한 템플릿
- system, user, assistant 역할별로 메시지를 구성하여 학습 데이터에 적용
LLAMA_3_CHAT_TEMPLATE = (
"{% for message in messages %}"
"{% if message['role'] == 'system' %}"
"{{ message['content'] }}"
"{% elif message['role'] == 'user' %}"
"{{ '\n\nHuman: ' + message['content'] + eos_token }}"
"{% elif message['role'] == 'assistant' %}"
"{{ '\n\nAssistant: ' + message['content'] + eos_token }}"
"{% endif %}"
"{% endfor %}"
"{% if add_generation_prompt %}"
"{{ '\n\nAssistant: ' }}"
"{% endif %}"
)
학습 파라미터 설정 (ScriptArguments 데이터 클래스)
학습에 필요한 주요 설정들을 인자로 받아 CLI(Command Line Interfaces) 실행 시 유연하게 조정할 수 있도록 구성
@dataclass
class ScriptArguments:
dataset_path: str = field(
default=None,
metadata={
"help": "데이터셋 파일 경로"
},
)
model_name: str = field(
default=None, metadata={"help": "SFT 학습에 사용할 모델 ID"}
)
max_seq_length: int = field(
default=512, metadata={"help": "SFT Trainer에 사용할 최대 시퀀스 길이"}
)
question_key: str = field(
default=None, metadata={"help": "지시사항 데이터셋의 질문 키"}
)
answer_key: str = field(
default=None, metadata={"help": "지시사항 데이터셋의 답변 키"}
)
모델 학습 함수
training_function은 실제 학습을 수행하는 핵심 함수
- 학습 파라미터에서 입력받은 데이터셋을 불러오기
- 대화형 데이터셋으로 변경하는 전처리를 진행
- 모델과 Trainer를 설정
def training_function(script_args, training_args):
# 데이터셋 불러오기
train_dataset = load_dataset(
"json",
data_files=os.path.join(script_args.dataset_path, "train_dataset.json"),
split="train",
)
test_dataset = load_dataset(
"json",
data_files=os.path.join(script_args.dataset_path, "test_dataset.json"),
split="train",
)
# 토크나이저 및 데이터셋 chat_template으로 변경하기
tokenizer = AutoTokenizer.from_pretrained(script_args.model_name, use_fast=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.chat_template = LLAMA_3_CHAT_TEMPLATE
tokenizer.padding_side = 'right'
def template_dataset(examples):
return{"text": tokenizer.apply_chat_template(examples["messages"], tokenize=False)}
train_dataset = train_dataset.map(template_dataset, remove_columns=["messages"])
test_dataset = test_dataset.map(template_dataset, remove_columns=["messages"])
# 데이터가 변화되었는지 확인하기 위해 2개만 출력하기
with training_args.main_process_first(
desc="Log a few random samples from the processed training set"
):
for index in random.sample(range(len(train_dataset)), 2):
print(train_dataset[index]["text"])
# Model 및 파라미터 설정하기
model = AutoModelForCausalLM.from_pretrained(
script_args.model_name,
attn_implementation="sdpa",
torch_dtype=torch.bfloat16,
use_cache=False if training_args.gradient_checkpointing else True,
)
if training_args.gradient_checkpointing:
model.gradient_checkpointing_enable()
# Train 설정
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=train_dataset,
dataset_text_field="text",
eval_dataset=test_dataset,
max_seq_length=script_args.max_seq_length,
tokenizer=tokenizer,
packing=True,
dataset_kwargs={
"add_special_tokens": False,
"append_concat_token": False,
},
)
checkpoint = None
if training_args.resume_from_checkpoint is not None:
checkpoint = training_args.resume_from_checkpoint
trainer.train(resume_from_checkpoint=checkpoint)
if trainer.is_fsdp_enabled:
trainer.accelerator.state.fsdp_plugin.set_state_dict_type("FULL_STATE_DICT")
trainer.save_model()
메인 블록(전체 실행)
- TrlParser를 사용해 스크립트 인자와 학습 인자를 파싱 :
커맨드 라인에서 입력된 다양한 설정값들을 처리하는 역할을 한다. 이 후, gradient checkpointing 옵션이 활성화 되어 있다면, 재진입(reentrant) 모드를 사용하도록 설정 - set_seed 함수로 시드 설정을 통해 실험의 재현성을 보장
- training_function을 호출해 실제 학습을 시작
if __name__ == "__main__":
parser = TrlParser((ScriptArguments, TrainingArguments))
script_args, training_args = parser.parse_args_and_config()
if training_args.gradient_checkpointing:
training_args.gradient_checkpointing_kwargs = {"use_reentrant": True}
# set seed
set_seed(training_args.seed)
# launch training
training_function(script_args, training_args)
4. Llama 3.1 모델 학습 실행
ACCELERATE_USE_FSDP=1 FSDP_CPU_RAM_EFFICIENT_LOADING=1 \
torchrun --nproc_per_node=4 \
./1_train_full_fine_tuning.py \
--config 0_full_fine_tuning_config.yaml
- ACCELERATE_USE_FSDP = 1 : 허깅페이스의 Accelerate 라이브러리에서 FSDP를 사용하겠다는 명령어
- FSDP_CPU_RAM_EFFICIENT_LOADING=1 : FSDP를 사용할 때 CPU RAM을 효율적으로 사용해 모델을 로딩하도록 설정
- torchrun --nproc_per_node=4 : torchrun은 Pytorch의 분산 학습을 위한 실행 도구
각 노드(컴퓨터)에서 4개의 프로세스를 실행하라는 의미(4개의 GPU를 사용한다는 뜻) - ./1_train_full_fine_tuning.py : 실행할 파이썬 스크립트의 경로
- --config full_fine_tuning_config.yaml : 파인튜닝에 사용할 설정 파일을 지정
5. 학습한 Llama 3.1 모델 테스트
LLM 모델 평가 및 테스트를 위한 스크립트
- 모델 로드
- llama-3.1-korean-8b-hf 모델을 bfloat16 형식으로 로드하고 GPU/CPU 자동 할당 설정
- 테스트 데이터셋 로드
- test_dataset.json에서 JSON 데이터를 로드하고 랜덤 메시지 샘플링
- 토크나이저 설정
- eos_token을 패딩 토큰으로 설정하고 텍스트 정렬
- 응답 생성
- temperature=0.7, top_p=0.95 설정으로 답변 생성
- 질문, 참조 답변, 모델 생성 응답 출력
- 평가 시스템
- Pydantic으로 평가 기준(관련성, 정확성, 완전성, 명확성, 유사성)과 평균 점수 계산
- 평가 함수
- OpenAI API를 통해 질문/답변을 비교 평가 후 결과 반환
- 실행 예시
- 질문/참조/모델 답변을 평가하고 결과 출력
import os
import torch
from random import randint
from datasets import load_dataset
from tqdm.auto import tqdm
from transformers import (
AutoModelForCausalLM,
AutoTokenizer
)
model_name = "./llama-3.1-korean-8b-hf-20-epoch/checkpoint-4740"
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
use_cache=False,
device_map="auto"
)
test_dataset = load_dataset(
"json",
data_files=os.path.join("", "./test_dataset.json"),
split="train",
)
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = 'right'
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
## 최종모델
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from datasets import load_dataset
from random import randint
# Load our test dataset
test_dataset = load_dataset("json",
split="train",
data_files="test_dataset.json")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
random_index = randint(0, len(test_dataset))
messages = test_dataset[random_index]["messages"][:2]
terminators = [
tokenizer.eos_token_id,
]
# Test on sample
input_ids = tokenizer.apply_chat_template(messages,
add_generation_prompt=True,
return_tensors="pt").to(model.device)
outputs = model.generate(
input_ids,
max_new_tokens=512,
eos_token_id=terminators,
do_sample=True,
temperature=0.7,
top_p=0.95,
)
response = outputs[0][input_ids.shape[-1]:]
print(f"질문:\n{test_dataset[random_index]['messages'][1]['content']}")
print(f"정답:\n{test_dataset[random_index]['messages'][2]['content']}")
print(f"생성:\n{tokenizer.decode(response,skip_special_tokens=True)}")
from pydantic import BaseModel
from openai import OpenAI
import os
# OpenAI 클라이언트 초기화
client = OpenAI(api_key="Your_OpenAI_API_KEY")
class Criterion(BaseModel):
score: int
explanation: str
class Evaluation(BaseModel):
relevance: Criterion
accuracy: Criterion
completeness: Criterion
clarity: Criterion
similarity: Criterion
average_score: float
def evaluate_qa_model(question: str, reference_answer: str, model_answer: str) -> Evaluation:
prompt = f"""
질문: {question}
참조 답변: {reference_answer}
모델 생성 답변: {model_answer}
위의 질문에 대한 두 답변을 비교 평가해주세요. 다음 기준에 따라 1-10점 사이의 점수를 매겨주세요:
1. 관련성: 모델의 답변이 질문과 얼마나 관련이 있는가?
2. 정확성: 모델이 제공한 정보가 참조 답변과 비교하여 얼마나 정확한가?
3. 완전성: 모델의 답변이 질문에 대해 얼마나 포괄적인가?
4. 명확성: 모델의 답변이 얼마나 명확하고 이해하기 쉬운가?
5. 유사성: 모델의 답변이 참조 답변과 얼마나 유사한가?
각 기준에 대한 점수와 간단한 설명을 제공해주세요. 마지막으로 전체 평균 점수를 계산해주세요.
"""
completion = client.beta.chat.completions.parse(
model="gpt-4o-mini", # 또는 사용 가능한 최신 모델
messages=[
{"role": "system", "content": "귀하는 QA 모델 응답을 평가하는 임무를 맡은 AI 어시스턴트입니다."},
{"role": "user", "content": prompt}
],
response_format=Evaluation
)
return completion
# 사용 예시
if __name__ == "__main__":
question = "인공지능의 윤리적 고려사항은 무엇인가요?"
reference_answer = "인공지능의 주요 윤리적 고려사항에는 1) 프라이버시 보호: 개인 정보의 수집, 처리, 저장에 관한 문제, 2) 알고리즘 편향성 방지: 인종, 성별, 연령 등에 대한 차별 방지, 3) 투명성 확보: AI 의사결정 과정의 설명 가능성, 4) 책임성 명확화: AI 시스템의 오류나 해악에 대한 책임 소재, 5) 안전성과 보안: AI 시스템의 안전한 작동과 외부 공격으로부터의 보호, 6) 인간 통제: AI가 인간의 통제를 벗어나지 않도록 하는 것 등이 있습니다. 이러한 요소들은 AI 기술이 사회에 미치는 영향을 고려하여 신중하게 다루어져야 하며, 법적, 제도적 장치를 통해 관리되어야 합니다."
model_answer = "인공지능의 윤리적 고려사항에는 프라이버시 보호, 알고리즘 편향성 방지, 투명성 확보, 책임성 명확화 등이 있습니다. 이러한 요소들은 AI 기술이 사회에 미치는 영향을 고려하여 신중하게 다루어져야 합니다."
evaluation = evaluate_qa_model(question, reference_answer, model_answer)
print(evaluation)