Dende
[LLM] 파인튜닝 예제 - (2) AI 모형 학습 본문

위의 파인튜닝 파이프라인에 따라 코드 실습을 진행해보겠습니다.
Topic은 금융상품 추천사유 생성입니다. 대형 언어 모델(LLM)을 통해 고객 개개인의 상황과 니즈를 고려한 맞춤형 추천 사유를 제공하는 것을 목표로 해보겠습니다.

Supervised Fine Tuning?
Supervised Fine Tuning(이하 SFT)은 레이블이 지정된 데이터를 사용하여 사전 훈련된(기본) 대규모 언어 모델(LLM)을 특정 다운스트림 작업에 적응시키는 데 사용되는 기술입니다. 2024년에 사용되는 대부분의 LLM은 채팅 또는 지시 기반 상호 작용을 위해 미세 조정됩니다.

- 데이터 수집 및 준비: 모델을 학습시키기 위해 데이터가 수집됩니다. 여기에는 두 가지 유형의 데이터가 사용됩니다: **원시 텍스트(Raw text)**와 데모스트레이션 데이터(Demonstrations). 원시 텍스트는 저품질이지만 대량으로 수집되며, 데모스트레이션 데이터는 고품질이지만 소량으로 존재합니다.
- 사전학습(Pre-training): 원시 텍스트는 모델의 초기 학습 단계인 프리트레이닝에 사용됩니다. 이 단계에서는 모델이 다양한 텍스트 데이터를 기반으로 기본적인 언어 이해 능력을 습득합니다.
- SFT: 데이터는 사전학습을 거친 기본 언어 모델(Base LLM)을 더욱 정교하게 조정하는 데 사용됩니다. 이 단계에서 레이블러(Labeler)가 제공한 바람직한 출력을 기반으로 모델이 학습합니다. 이 과정을 통해 생성된 모델은 SFT 모델로, 특정 목적에 맞게 최적화된 성능을 발휘합니다.
이 프로세스를 통해 모델러가 특정 데이터 분포 및 작업 요구 사항에 따라 모델의 매개변수가 조정되어 원하는 패턴과 뉘앙스를 학습시킬 수 있습니다. SFT는 일반적으로 모델 사전 학습 후에 수행되며 모델에 사용자 지정 지침을 따르는 방법을 가르치는 데 사용됩니다. 비지도 미세 조정보다 계산 비용이 많이 들지만 더 나은 성능을 달성할 가능성도 더 높습니다.
SFT의 장점
SFT은 레이블이 지정된 데이터를 사용하여 사전 훈련된 대규모 언어 모델(LLM)을 특정 다운스트림 작업에 적응시키는 데 사용되는 강력한 기술입니다.
- 작업별 패턴 및 뉘앙스 - SFT를 사용하면 모델이 특정 데이터 분포 및 작업 요구 사항에 따라 매개변수를 조정하여 작업별 패턴 및 뉘앙스를 학습할 수 있습니다.
- 향상된 성능 - 사전 학습된 모델을 미세 조정하면 방대한 양의 데이터에서 학습한 지식과 표현을 활용하여 특정 작업에 대한 성능을 향상시킬 수 있습니다.
- 데이터 효율성 - SFT는 레이블이 지정된 예제의 수가 제한되어 있어도 다양한 실제 시나리오에 적용할 수 있으므로 데이터 효율성이 더 높습니다.
- 리소스 효율성 - 사전 훈련된 모델을 미세 조정하면 처음부터 모델을 훈련하는 데 필요한 상당한 시간과 계산 리소스를 절약할 수 있습니다.
- 맞춤화 — SFT는 LLM의 행동, 글쓰기 스타일 또는 도메인별 지식을 특정한 뉘앙스, 톤 또는 용어에 맞게 조정하여 특정 스타일이나 전문 분야와 긴밀하게 연계할 수 있도록 해줍니다.
- 과도한 적합 감소 - 조기 중단, 드롭아웃, 데이터 증가와 같은 기술은 미세 조정 중에 사용되어 소규모 데이터 세트에서 과도한 적합의 위험을 완화하고 새 데이터에 대한 일반화를 촉진할 수 있습니다.
Quick Start with Code Example
##############################################################################################################
# 패키지 선언
##############################################################################################################
import os
import pandas as pd
import os # os 모듈 운영체제와 상호 작용할 수 있는 기능을 제공
import torch # PyTorch 라이브러리로, 주로 딥러닝과 머신러닝 모델을 구축, 학습, 테스트하는 데 사용
from datasets import load_dataset # 데이터셋을 쉽게 불러오고 처리할 수 있는 기능을 제공
from transformers import (
AutoModelForCausalLM, # 인과적 언어 추론(예: GPT)을 위한 모델을 자동으로 불러오는 클래스
AutoTokenizer, # 입력 문장을 토큰 단위로 자동으로 잘라주는 역할
BitsAndBytesConfig, # 모델 구성
TrainingArguments, # 훈련 설정
pipeline
)
# 모델 튜닝을 위한 라이브러리
from peft import LoraConfig, PeftModel , get_peft_model
from trl import SFTTrainer
from datasets import Dataset
# CUDA 장치의 주요 버전과 부 버전을 가져옵니다.
major_version, minor_version = torch.cuda.get_device_capability()
print(major_version, minor_version)
print(torch.cuda.is_available)
1. 사전학습된 베이스모델과 토크나이저를 불러옵니다.
##############################################################################################################
# 베이스모델 로드
##############################################################################################################
# 로컬 저장된 모델이 아닐 경우, 주석 교체 필요
# BASE_MDL_LOC = "sh2orc/Llama-3.1-Korean-8B-Instruct" # 모델 이름을 설정합니다.
BASE_MDL_LOC = f'C:/Users/user/.cache/huggingface/hub/models--sh2orc--Llama-3.1-Korean-8B-Instruct/snapshots/05774d31bb13cde306f3282e9592b7da90e026a2'
# 양자화된 베이스모델 로드
base_mdl = AutoModelForCausalLM.from_pretrained(
BASE_MDL_LOC
, quantization_config = BitsAndBytesConfig(
load_in_4bit=True, # 모델 가중치를 4비트로 로드
bnb_4bit_quant_type="nf4", # 양자화 유형으로는 “nf4”를 사용한다.
bnb_4bit_compute_dtype=torch.bfloat16, # 양자화를 위한 컴퓨팅 타입은 직전에 정의 했던 torch_dtype으로 지정 해준다.
bnb_4bit_use_double_quant=False, # 이중 양자화는 사용하지 않는다.
) # 양자화
, device_map={"": 0} # 0번째 gpu 에 할당
# , torch_dtype=torch.float16
)
# 모델의 캐시 기능을 비활성화 한다. 캐시는 이전 계산 결과를 저장하기 때문에 추론 속도를 높이는 역할을 한다. 그러나 메모리 사용량을 증가시킬 수 있기 때문에, 메모리부족 문제가 발생하지 않도록 하기 위해 비활성화 해주는 것이 좋다.
base_mdl.config.use_cache = False
# 모델의 텐서 병렬화(Tensor Parallelism) 설정을 1로 지정한다. 설정값 1은 단일 GPU에서 실행되도록 설정 해주는 의미이다.
base_mdl.config.pretraining_tp = 1
##############################################################################################################
# 토크나이저 로드
##############################################################################################################
tokenizer = AutoTokenizer.from_pretrained(BASE_MDL_LOC, add_special_tokens=True, trust_remote_code=True)
# 시퀀스 길이를 맞추기 위해 문장 끝에 eos_token를 사용 : 문장의 끝을 나타내는 토큰. 패딩 토큰을 문장의 끝 토큰으로 설정하여 문장의 패딩을 수행할 것임을 의미
tokenizer.pad_token = tokenizer.eos_token
# # 패딩 토큰을 시퀀스의 어느 쪽에 추가할지 설정 : 토크나이저가 패딩 토큰을 문장의 끝에 추가할 것임을 나타냄. 즉, 오른쪽에 패딩을 적용
tokenizer.padding_side = "right"
2. 지도 학습을 위한 데이터를 불러옵니다. 이 때, 학습 데이터의 템플릿과 운영 단계에서의 템플릿이 상이할 경우 원하는 조정 효과를 보지 못할 수 있습니다.
※ 파인튜닝에 프롬프트 템플릿이 필요한 이유?
- 모델이 다양한 입력 형식을 처리해야 하는 혼란을 줄여주며, 학습 효율을 높입니다.
- 템플릿이 미리 정의된 문맥과 기대되는 응답 구조를 제공하므로, 모델의 출력 품질이 향상됩니다.
- 데이터 전처리 과정을 단순화하고, 모델 학습에 필요한 데이터를 보다 쉽게 준비할 수 있게 합니다.
- 다양한 프롬프트 템플릿을 통해 모델이 다양한 맥락에서 응답을 생성하는 방법을 학습할 수 있습니다. 이는 모델의 일반화 능력을 향상시켜, 훈련되지 않은 새로운 상황에서도 적절한 응답을 생성할 수 있도록 도와줍니다.
##############################################################################################################
# 전이학습 데이터셋 로드
##############################################################################################################
df = pd.read_pickle("df_train_base.pkl")
# Hugging Face Dataset으로 변환
dataset = Dataset.from_pandas(df)
dataset

3. SFT 수행 전, 파라미터 및 메모리 효율 파인튜닝을 위한 QLora를 반영합니다. 이후 지도 학습 수행합니다.
# LoRA 설정
peft_params = LoraConfig(
lora_alpha=16, # LoRA 스케일링 팩터
inference_mode=False,
lora_dropout=0.1, # LoRA 드롭아웃 비율
r=64, # LoRA 랭크
# bias="none",
task_type="CAUSAL_LM",
)
# `get_peft_model` 함수를 호출하여 모델을 초기화하고, 성능 향상을 위한 여러 파라미터를 설정합니다.
base_mdl = get_peft_model(
base_mdl,
peft_params)
# 훈련 파라미터 설정
training_params = TrainingArguments(
per_device_train_batch_size=2, # 각 디바이스당 훈련 배치 크기
gradient_accumulation_steps=4, # 그래디언트 누적 단계
warmup_steps=5, # 웜업 스텝 수
num_train_epochs=3, # 훈련 에폭 수
max_steps=100, # 최대 스텝 수
do_eval=True,
evaluation_strategy="steps",
logging_steps=1, # logging 스텝 수
learning_rate=2e-4, # 학습률
fp16=not torch.cuda.is_bf16_supported(), # fp16 사용 여부, bf16이 지원되지 않는 경우에만 사용
bf16=torch.cuda.is_bf16_supported(), # bf16 사용 여부, bf16이 지원되는 경우에만 사용
optim="adamw_8bit", # 최적화 알고리즘
weight_decay=0.01, # 가중치 감소
lr_scheduler_type="cosine", # 학습률 스케줄러 유형
seed=123, # 랜덤 시드
report_to='tensorboard', # TensorBoard에 결과 보고
output_dir="output", # 출력 디렉토리
)
# SFT(Supervised Fine-Tuning) 트레이너 설정
trainer = SFTTrainer(
model=base_mdl,
tokenizer=tokenizer,
eval_dataset=dataset,
train_dataset=dataset,
peft_config=peft_params,
dataset_text_field="입력", # 데이터셋의 텍스트 필드 이름
max_seq_length=256, # 최대 시퀀스 길이
dataset_num_proc=2, # 데이터 처리에 사용할 프로세스 수
args=training_params,
packing=False, # 시퀀스 패킹 비활성화
)
# 훈련 시작
trainer.train()
# 학습 모델 저장경로 선언
TRAIN_MDL = 'finetuned_mdl'
# only saves the incremental 🤗 PEFT weights (adapter_model.bin) that were trained, meaning it is super efficient to store, transfer, and load.
trainer.model.save_pretrained(TRAIN_MDL)
# save the full model and the training arguments
trainer.save_model(TRAIN_MDL)
trainer.model.config.save_pretrained(TRAIN_MDL)
4. SFT수행 후 생성된 Lora 가중치와 베이스모델을 통합합니다.
##############################################################################################################
# 기본 모델 재로딩 후 LoRA 가중치와의 통합
##############################################################################################################
# 통합모델(베이스+학습) 저장경로 선언
INTG_MDL = 'new_mdl'
TRAIN_MDL = 'finetuned_mdl'
# base_model과 new_model에 저장된 LoRA 가중치를 통합하여 새로운 모델을 생성
model_intg = PeftModel.from_pretrained(base_mdl, f'./{TRAIN_MDL}') # LoRA 가중치를 가져와 기본 모델에 통합
model_intg = model_intg.merge_and_unload() # merge the adapter weights with the base model
model_intg.save_pretrained(INTG_MDL)
# 통합모델 로드
mdl_finetuned = AutoModelForCausalLM.from_pretrained(
INTG_MDL,
quantization_config=peft_params,
device_map={"": 0}, # 0번째 gpu 에 할당
torch_dtype=torch.float16
)
5. 통합된 모델에 질의를 보내봅니다.
# 질의에 들어갈 입력정보
customer_info = """
- 고객은 예금상품 가입에 충분한 잔액을 가지고 있습니다.
- 고객은 추천상품의 금리 우대 조건을 충족했습니다.
- 고객은 사회초년생(20~30대초 직장인)입니다.
- 최근 예금금리가 상승하고 있습니다.
"""
# AlpacaPrompt를 사용하여 지시사항을 포맷팅
alpaca_prompt = """
**지시사항:**
당신은 은행에 방문한 고객에게 금융상품 추천 문구를 작성해주는 도우미입니다.
**질문:**
고객에게 예금 상품이 추천되었습니다.
아래의 문맥을 기반으로 은행이 고객에게 이 상품의 매력적인 추천 문구를 생성해주세요.
**문맥:**
- 고객은 예금상품 가입에 충분한 잔액을 가지고 있습니다.
- 고객은 추천상품의 금리 우대 조건을 충족했습니다.
- 고객은 사회초년생입니다.
- 최근 예금금리가 상승하고 있습니다.
**답변:**
다음 형식에 맞춰 답변을 작성해주세요
1. **문맥 분석:** "주어진 문맥을 기반으로 고객에게 예금 상품이 추천된 이유를 설명하세요."
2. **추천 문구:** "친절하지만 매력적인 추천 문구를 100자 이내로 작성하세요. 뒤에는 추천 문구에서 주요 키워드 1개를 추출하여 해시태그 형식으로 추가해주세요."
"""
pipe = pipeline("text-generation", model = mdl_finetuned, tokenizer=tokenizer, max_new_tokens=512)
outputs = pipe(
alpaca_prompt.format(
f"""{customer_info}""", # 지시사항
"" , # 출력 - 생성을 위해 이 부분을 비워둡니다!
),
# do_sample=True,
temperature = 0.1, # 다양성
top_k = 30, # Top-K 샘플링에서는 모델이 예측한 단어들 중 확률이 가장 높은 상위 K개의 단어만을 고려합니다
top_p = 0.1, # Top-P 샘플링에서는 단어들의 확률을 누적하여 특정 임계값에 도달할 때까지의 단어들만을 고려합니다.
repetition_penalty=1.2,
add_special_tokens=True
)
print(outputs[0]["generated_text"])
'LLM' 카테고리의 다른 글
| [LLM] MCP 서버로 여는 AI와 도구 연결의 새로운 패러다임 (0) | 2025.10.10 |
|---|---|
| [LLM] 파인튜닝 예제 - (3) DPO Training (2) | 2024.09.03 |
| [LLM] 파인튜닝 예제 - (1) 학습 데이터 준비 (2) | 2024.09.03 |
| [LLM] 파인튜닝 - PEFT(Parameter-Efficient Fine-Tuning) (0) | 2024.08.20 |
| [LLM] 파인튜닝 개념정리 (0) | 2024.08.20 |