Hugging Face PEFT로 LoRA 미세 조정
LoRA의 순위, 알파, 대상 모듈을 구성하고 TRL SFTTrainer로 지도 미세 조정을 실행하며, 학습 손실을 모니터링하고 병합된 체크포인트와 어댑터 전용 체크포인트를 저장합니다.
Hugging Face PEFT로 LoRA 미세 조정은(는) CoddyKit의 무료 AI Engineering Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Engineering Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
전체 미세 조정 대신 LoRA를 사용하는 이유
전체 미세 조정은 모델의 모든 매개변수를 업데이트합니다. float32 정밀도의 70억 매개변수 모델은 가중치에만 약 28GB의 GPU 메모리가 필요하며, 옵티마이저 상태, 그래디언트, 활성값까지 포함하면 총 80~120GB가 쉽게 필요합니다. LoRA(저랭크 적응)는 대신 전체 매개변수의 일반적으로 0.1~1%에 해당하는 매우 적은 수의 훈련 가능한 매개변수를 저랭크 행렬 쌍으로 추가하여 선택한 계층에 적용합니다. 이를 통해 GPU 요구량을 10~50배 줄이면서도 비슷한 결과를 얻을 수 있습니다.
# LoRA math intuition:
# Full fine-tuning: update W (large matrix, e.g., 4096 x 4096 = 16.7M parameters)
# LoRA: instead train W = W_0 + A @ B where:
# A has shape (4096, r) - only r*4096 params
# B has shape (r, 4096) - only r*4096 params
# r (rank) is typically 4, 8, or 16 - much smaller than 4096
# Memory comparison for 7B model:
# Full fine-tuning: ~80GB GPU RAM
# LoRA (rank=8): ~12GB GPU RAM - fits on a single A100 or 3090
print('LoRA makes fine-tuning accessible without massive GPU clusters')필수 라이브러리 설치
Hugging Face로 LoRA 미세 조정을 수행하려면 세 가지 라이브러리가 필요합니다. transformers(모델 로드 및 토큰화), peft(LoRA를 구현하는 매개변수 효율적 미세 조정), trl(지도 미세 조정을 위한 SFTTrainer를 제공하는 트랜스포머 강화 학습)입니다. 이들을 함께 사용하면 높은 수준의 프로덕션 준비형 미세 조정 작업 흐름을 구성할 수 있습니다.
# pip install transformers peft trl accelerate bitsandbytes datasets
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, TaskType
from trl import SFTTrainer, SFTConfig
from datasets import Dataset
import torch
print('Libraries imported successfully')
print(f'GPU available: {torch.cuda.is_available()}')
if torch.cuda.is_available():
print(f'GPU: {torch.cuda.get_device_name(0)}')
print(f'GPU memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB')양자화를 적용한 기본 모델 로드
대부분의 LoRA 미세 조정에서는 bitsandbytes를 사용해 기본 모델을 4비트 양자화로 로드합니다. 이렇게 하면 모델의 메모리 사용량이 75% 줄어듭니다(7B 모델의 경우 약 14GB에서 약 4GB로 감소). 그러면서도 모델의 성능 대부분을 유지할 수 있습니다. LoRA 어댑터 계층만 전체 정밀도로 훈련합니다. 4비트 양자화와 LoRA의 조합을 QLoRA라고 하며, 소비자용 GPU에서도 7B 모델을 미세 조정할 수 있게 해 줍니다.
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch
MODEL_NAME = 'mistralai/Mistral-7B-Instruct-v0.2' # or 'meta-llama/Llama-3.2-3B-Instruct'
# 4-bit quantization config (QLoRA)
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # quantize base model to 4-bit
bnb_4bit_quant_type='nf4', # NF4 quantization type
bnb_4bit_compute_dtype=torch.float16, # compute in float16
bnb_4bit_use_double_quant=True # double quantization for extra savings
)
# Load quantized model
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
quantization_config=bnb_config,
device_map='auto', # automatically distribute across GPUs
trust_remote_code=True
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
tokenizer.pad_token = tokenizer.eos_token # required for training batches
print(f'Model loaded. Parameters: {model.num_parameters():,}')LoRA 하이퍼파라미터 설정
가장 중요한 LoRA 하이퍼파라미터는 세 가지입니다. r(랭크)은 저랭크 행렬의 차원입니다. 랭크가 높을수록 훈련 가능한 매개변수가 많아지고 적응 표현력도 커지지만, 메모리 사용량과 과적합 위험도 증가합니다. lora_alpha는 일반적으로 랭크의 2배로 설정하는 스케일링 계수입니다. target_modules는 LoRA를 적용할 가중치 행렬을 지정합니다. 어텐션 계층(q_proj, v_proj)이 가장 일반적인 선택입니다. r=8에서 시작해 조정해 보세요.
from peft import LoraConfig, TaskType
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # causal language modeling
r=8, # rank: 4, 8, 16, 32 — higher = more params
lora_alpha=16, # scaling: usually 2*r
lora_dropout=0.1, # dropout on LoRA layers for regularization
target_modules=['q_proj', 'v_proj', # which weight matrices to adapt
'k_proj', 'o_proj', # common to target all attention projections
'gate_proj', 'up_proj', 'down_proj'], # and FFN layers
bias='none', # do not adapt bias parameters
)
# Wrap the model with LoRA adapters
from peft import get_peft_model, prepare_model_for_kbit_training
model = prepare_model_for_kbit_training(model) # prepares quantized model for training
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# Output: trainable params: 4,194,304 || all params: 3,752,071,168 || trainable%: 0.11%데이터셋 준비
SFTTrainer는 특정 형식의 데이터셋을 요구합니다. 가장 간단한 형식은 완전히 형식화된 프롬프트 + 응답 문자열을 포함하는 단일 text 열이 있는 데이터셋입니다. 토크나이저의 대화 템플릿을 사용해 대화 예시를 일관된 형식으로 지정하세요. SFTTrainer는 토큰화, 배치 구성, 손실 마스킹을 처리합니다. 손실 마스킹은 입력 프롬프트가 아니라 어시스턴트의 응답에 대해서만 손실을 계산하는 방식입니다.
from datasets import Dataset
import json
def load_and_format_dataset(jsonl_path: str, tokenizer) -> Dataset:
examples = []
with open(jsonl_path) as f:
for line in f:
ex = json.loads(line.strip())
# Apply chat template to format as expected by the model
formatted = tokenizer.apply_chat_template(
ex['messages'],
tokenize=False,
add_generation_prompt=False
)
examples.append({'text': formatted})
return Dataset.from_list(examples)
# Load training and validation datasets
train_dataset = load_and_format_dataset('train.jsonl', tokenizer)
val_dataset = load_and_format_dataset('validation.jsonl', tokenizer)
print(f'Train examples: {len(train_dataset)}')
print(f'Validation examples: {len(val_dataset)}')
print('Sample formatted text:')
print(train_dataset[0]['text'][:300])SFTTrainer로 훈련
TRL의 SFTTrainer는 지도 미세 조정 기본값이 설정된 Hugging Face Trainer 래퍼입니다. 훈련 하이퍼파라미터를 지정해 구성하세요. 여기에는 에포크 수(명령 미세 조정에는 보통 1~3회면 충분), 배치 크기, 그래디언트 누적 단계(메모리가 제한된 상황에서 더 큰 배치를 시뮬레이션), 학습률(2e-4가 일반적인 시작값), 체크포인트를 저장할 출력 디렉터리가 포함됩니다.
from trl import SFTTrainer, SFTConfig
training_args = SFTConfig(
output_dir='./fine-tuned-model',
num_train_epochs=2, # 2-3 epochs for instruction fine-tuning
per_device_train_batch_size=4, # increase if GPU memory allows
gradient_accumulation_steps=4, # effective batch size = 4*4 = 16
learning_rate=2e-4, # typical LoRA learning rate
warmup_ratio=0.05, # warmup for 5% of steps
lr_scheduler_type='cosine', # cosine decay learning rate schedule
logging_steps=10,
eval_strategy='steps',
eval_steps=50, # evaluate on validation set every 50 steps
save_steps=100,
max_seq_length=2048, # max token length per example
fp16=True, # mixed precision training
report_to='none' # or 'wandb' for experiment tracking
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=val_dataset,
)
print('Starting LoRA fine-tuning...')
trainer.train()훈련 진행 상황 모니터링
훈련 중에는 두 가지 핵심 지표를 확인하세요. 훈련 손실은 꾸준히 감소해야 합니다. 검증 손실은 처음에는 감소하다가 정체되거나 약간 증가해야 합니다(과적합). 훈련 손실은 계속 감소하는데 검증 손실이 크게 증가한다면 훈련을 조기에 중단하세요. 모델이 일반화하지 못하고 훈련 예시를 암기하고 있다는 뜻입니다. 최적의 중단 지점은 검증 손실이 상승하기 직전입니다.
# Reading training logs
# Training step logs look like:
# {'loss': 1.4523, 'grad_norm': 0.85, 'learning_rate': 0.0002, 'epoch': 0.2, 'step': 20}
# {'loss': 1.2341, 'grad_norm': 0.72, 'learning_rate': 0.00018, 'epoch': 0.4, 'step': 40}
# Validation results look like:
# {'eval_loss': 1.1823, 'eval_runtime': 12.3, 'eval_samples_per_second': 8.1, 'step': 50}
# {'eval_loss': 1.0923, 'eval_runtime': 12.1, 'eval_samples_per_second': 8.3, 'step': 100}
# {'eval_loss': 1.1234, 'eval_runtime': 12.4, 'eval_samples_per_second': 8.2, 'step': 150}
# ^ validation loss went UP at step 150 - overfitting starting
# Load the best checkpoint (lowest validation loss)
from transformers import TrainerCallback
print('Best model checkpoint is saved automatically by SFTTrainer (load_best_model_at_end=True)')LoRA 어댑터 저장 및 병합
훈련 후에는 LoRA 어댑터 가중치를 기본 모델과 별도로 저장하세요. 어댑터는 매우 작으며(몇 MB에서 수백 MB) 추론 시 기본 모델에 적용할 수 있습니다. 프로덕션 배포를 위해 LoRA 가중치를 기본 모델에 병합하여 추론 시 PEFT 라이브러리가 필요 없는 단일 모델 파일을 만들 수도 있습니다. 이렇게 하면 추론 오버헤드가 줄어듭니다.
# Save only the LoRA adapter (tiny - typically 10-100MB)
model.save_pretrained('./lora-adapter-only')
tokenizer.save_pretrained('./lora-adapter-only')
# Load the adapter for inference (requires base model + peft)
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, torch_dtype=torch.float16, device_map='auto')
model_with_adapter = PeftModel.from_pretrained(base_model, './lora-adapter-only')
# Alternative: Merge adapter into base model (no PEFT needed at inference)
print('Merging LoRA weights into base model...')
merged_model = model_with_adapter.merge_and_unload() # creates a regular model
merged_model.save_pretrained('./merged-model')
print('Merged model saved - can be used with standard transformers, no PEFT needed')미세 조정한 모델로 추론 실행
성공했다고 판단하기 전에 보류해 둔 프롬프트 집합으로 미세 조정한 모델을 테스트하세요. 동일한 프롬프트에 대한 기본 모델과의 출력을 나란히 비교하여 미세 조정이 목표를 달성했는지 확인하세요. 모델이 더 잘 처리해야 하는 사례(대상 작업)와 여전히 잘 처리해야 하는 사례(성능이 저하되면 안 되는 일반 작업)를 모두 점검하세요.
def generate(model, tokenizer, prompt: str, max_new_tokens=512) -> str:
inputs = tokenizer(prompt, return_tensors='pt').to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
temperature=0.1,
do_sample=True,
pad_token_id=tokenizer.eos_token_id
)
# Decode only the new tokens (not the input prompt)
new_tokens = outputs[0][inputs['input_ids'].shape[1]:]
return tokenizer.decode(new_tokens, skip_special_tokens=True)
# Compare base vs fine-tuned
test_prompt = 'Extract JSON from: "Alice Johnson, 28, software engineer in NYC since 2021"'
print('=== BASE MODEL ===')
print(generate(base_model, tokenizer, test_prompt))
print('\n=== FINE-TUNED MODEL ===')
print(generate(merged_model, tokenizer, test_prompt))LoRA 핵심 하이퍼파라미터 요약
사용 사례에 맞게 LoRA를 조정할 때는 다음 기본값에서 시작하고 한 번에 하나씩 변경하세요. r=8은 안전한 시작점입니다. 모델에 더 큰 표현력이 필요하면 16 또는 32로 높이세요. lora_alpha = 2*r는 안정적인 선택입니다. 학습률 2e-4는 대부분의 명령 미세 조정에 적합하며, 훈련 손실이 불안정하면 1e-4로 낮추세요. 에포크 1~3회: 검증 손실이 더 이상 감소하지 않으면 중단하세요.
대신 OpenAI 미세 조정을 사용해야 하는 경우
Hugging Face PEFT LoRA를 사용하려면 GPU가 필요합니다. GPU 인프라가 없다면 OpenAI의 미세 조정 API가 훈련 인프라를 대신 관리해 주는 대안입니다. JSONL 파일을 업로드하고 API를 호출해 훈련을 시작한 다음, API 호출에 사용할 수 있는 미세 조정 모델 ID를 받습니다. OpenAI 미세 조정은 GPT-4o-mini와 GPT-3.5-turbo를 지원합니다. 토큰당 비용은 더 높지만 인프라 관리를 완전히 없앨 수 있습니다.
from openai import OpenAI
client = OpenAI()
# Upload training file
train_file = client.files.create(
file=open('train.jsonl', 'rb'),
purpose='fine-tune'
)
val_file = client.files.create(
file=open('validation.jsonl', 'rb'),
purpose='fine-tune'
)
# Create fine-tuning job
job = client.fine_tuning.jobs.create(
training_file=train_file.id,
validation_file=val_file.id,
model='gpt-4o-mini', # base model to fine-tune
hyperparameters={
'n_epochs': 3,
'batch_size': 'auto',
'learning_rate_multiplier': 'auto'
}
)
print(f'Fine-tuning job created: {job.id}')
# Monitor: client.fine_tuning.jobs.retrieve(job.id)
# Use: client.chat.completions.create(model=job.fine_tuned_model, ...)빠른 확인
이 레슨에서 배운 LoRA 미세 조정을 이해했는지 테스트해 보세요.
레슨 요약
이 레슨에서는 다음을 배웠습니다. LoRA는 모든 모델 매개변수 대신 작은 저랭크 어댑터 행렬만 훈련하여 미세 조정에 필요한 GPU를 10~50배 줄입니다. QLoRA(4비트 양자화 + LoRA)는 약 12GB의 VRAM을 갖춘 소비자용 GPU에서도 7B 모델을 미세 조정할 수 있게 합니다. 또한 TRL의 SFTTrainer는 토큰화, 배치 구성, 손실 마스킹, 체크포인트 저장을 처리하는 높은 수준의 API를 제공합니다. 다음으로 미세 조정한 모델을 평가하고 배포합니다.
AI 튜터와 함께 Python을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 30
- 레슨
- 120
자주 묻는 질문
“Hugging Face PEFT로 LoRA 미세 조정” 강의는 무료인가요?
네 — “Hugging Face PEFT로 LoRA 미세 조정” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Engineering Academy 강의 전체를 잠금 해제할 수 있습니다. AI Engineering Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“Hugging Face PEFT로 LoRA 미세 조정”에서 뭘 배우나요?
LoRA의 순위, 알파, 대상 모듈을 구성하고 TRL SFTTrainer로 지도 미세 조정을 실행하며, 학습 손실을 모니터링하고 병합된 체크포인트와 어댑터 전용 체크포인트를 저장합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Engineering Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
AI Engineering Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 AI Engineering Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“Hugging Face PEFT로 LoRA 미세 조정” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 AI Engineering Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 AI Engineering Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 프롬프트보다 미세 조정이 뛰어난 경우
- 고품질 학습 데이터셋 준비
- Hugging Face PEFT로 LoRA 미세 조정
- 미세 조정 모델 평가 및 배포