- Authors
- Name
- 들어가며
- Fine-tuning 패러다임 변화
- LoRA 수학적 원리와 구현
- QLoRA 4비트 양자화
- PEFT 라이브러리 활용
- 데이터셋 구성 전략
- 하이퍼파라미터 튜닝
- 트러블슈팅
- 운영 체크리스트
- 참고자료

들어가며
사전 학습된 대규모 언어 모델(LLM)을 특정 도메인이나 태스크에 맞게 적응시키는 Fine-tuning은 LLM 활용의 핵심 기술이다. 그러나 수십억 개의 파라미터를 가진 모델을 전체 파인튜닝(Full Fine-tuning)하려면 막대한 GPU 메모리와 연산 비용이 필요하다. GPT-3 175B 모델의 경우 Adam 옵티마이저 기준으로 약 1.2TB의 GPU 메모리가 필요하며, 이는 대부분의 조직에서 현실적이지 않다.
이 문제를 해결하기 위해 등장한 것이 Parameter-Efficient Fine-Tuning(PEFT) 기법이다. 특히 LoRA(Low-Rank Adaptation)와 QLoRA(Quantized LoRA)는 학습 가능한 파라미터 수를 원본 모델의 0.1% 미만으로 줄이면서도 전체 파인튜닝에 준하는 성능을 달성한다. 본 글에서는 이러한 효율적 파인튜닝 기법의 이론적 배경부터 프로덕션 수준의 실전 구현까지 체계적으로 다룬다.
Fine-tuning 패러다임 변화
전체 파인튜닝의 한계
전통적인 Fine-tuning은 사전 학습된 모델의 모든 파라미터를 업데이트한다. 이 방식은 아래와 같은 근본적인 문제를 안고 있다.
- 메모리 비용: 모델 가중치 + 그래디언트 + 옵티마이저 상태를 모두 GPU 메모리에 적재해야 한다
- 저장 비용: 태스크별로 전체 모델 사본을 저장해야 하므로, 10개 태스크에 대해 70B 모델을 사용하면 약 1.4TB의 저장 공간이 필요하다
- Catastrophic Forgetting: 소규모 데이터셋에 과적합되면서 사전 학습에서 획득한 일반 지식을 상실한다
PEFT 기법의 분류
Parameter-Efficient Fine-Tuning 기법은 크게 세 가지 접근법으로 분류된다.
| 방법 | 대표 기법 | 원리 | 학습 파라미터 비율 | GPU 메모리 (7B 기준) | 성능 (Full FT 대비) |
|---|---|---|---|---|---|
| Full Fine-tuning | - | 전체 파라미터 업데이트 | 100% | 약 120GB | 기준선 |
| Additive (어댑터) | Adapter, Prefix Tuning | 소규모 모듈 삽입 | 0.5-3% | 약 30GB | 95-98% |
| Reparameterization | LoRA, QLoRA | 저랭크 행렬 분해 | 0.01-0.5% | 약 16-28GB | 97-100% |
| Selective | BitFit, Diff Pruning | 일부 파라미터만 선택 학습 | 0.05-1% | 약 25GB | 90-95% |
LoRA 수학적 원리와 구현
저랭크 분해의 핵심 아이디어
LoRA(Low-Rank Adaptation)는 Hu et al.(2021)이 제안한 기법으로, 사전 학습된 가중치 행렬의 업데이트를 저랭크 행렬의 곱으로 근사한다는 핵심 아이디어에 기반한다.
기존 가중치 행렬 W0 (d x k 차원)에 대해, 업데이트 delta_W를 두 개의 저랭크 행렬 B (d x r)와 A (r x k)의 곱으로 분해한다. 여기서 r은 랭크로, d나 k보다 훨씬 작은 값이다.
순전파 시 출력은 다음과 같이 계산된다: h = W0 _ x + (B _ A) _ x. 학습 시에는 W0는 동결(freeze)하고 B와 A만 학습한다. 학습 가능한 파라미터 수는 d _ k에서 r * (d + k)로 대폭 줄어든다.
LoRA 구현 코드
from peft import LoraConfig, get_peft_model, TaskType
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# 베이스 모델 로드
model_name = "meta-llama/Llama-2-7b-hf"
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
# LoRA 설정
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # 랭크: 일반적으로 8-64 사이
lora_alpha=32, # 스케일링 팩터: 보통 r의 2배
lora_dropout=0.05, # 드롭아웃: 과적합 방지
target_modules=[ # LoRA를 적용할 모듈
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
bias="none", # bias 학습 여부
)
# PEFT 모델 생성
peft_model = get_peft_model(model, lora_config)
# 학습 가능한 파라미터 확인
peft_model.print_trainable_parameters()
# 출력 예시: trainable params: 33,554,432 || all params: 6,771,970,048
# || trainable%: 0.4956
랭크(r) 선택 가이드
랭크 r은 LoRA의 핵심 하이퍼파라미터다.
- r=4-8: 간단한 분류 태스크, 감정 분석 등에 적합. 메모리 최소화가 목표일 때
- r=16-32: 일반적인 instruction tuning, 대화형 모델에 권장되는 범위
- r=64-128: 복잡한 도메인 적응(의료, 법률 등)이나 대규모 데이터셋에서 사용
alpha 값은 일반적으로 r의 2배로 설정한다. 실제 스케일링 팩터는 alpha/r이므로, alpha=32, r=16이면 스케일링은 2가 된다.
QLoRA 4비트 양자화
QLoRA의 혁신
QLoRA(Dettmers et al., 2023)는 LoRA에 4비트 양자화를 결합하여 메모리 사용량을 극적으로 줄인 기법이다. 65B 파라미터 모델을 단일 48GB GPU에서 파인튜닝할 수 있게 만들었으며, 세 가지 핵심 기술을 도입했다.
- 4-bit NormalFloat (NF4): 정규분포를 따르는 가중치에 최적화된 정보 이론적 데이터 타입
- Double Quantization: 양자화 상수 자체를 재양자화하여 파라미터당 평균 0.37비트를 추가 절약
- Paged Optimizers: GPU 메모리 스파이크 시 CPU RAM으로 자동 페이징하는 옵티마이저
QLoRA 학습 스크립트
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
)
from peft import LoraConfig, prepare_model_for_kbit_training, get_peft_model
from trl import SFTTrainer
import torch
# 4비트 양자화 설정
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NormalFloat4 양자화
bnb_4bit_compute_dtype=torch.bfloat16, # 연산 시 bfloat16 사용
bnb_4bit_use_double_quant=True, # Double Quantization 활성화
)
# 4비트 양자화 모델 로드
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True,
)
# k-bit 학습 준비 (gradient checkpointing 등)
model = prepare_model_for_kbit_training(model)
# LoRA 설정
lora_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
bias="none",
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
# 학습 인자 설정
training_args = TrainingArguments(
output_dir="./qlora-output",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
weight_decay=0.01,
warmup_ratio=0.03,
lr_scheduler_type="cosine",
logging_steps=10,
save_strategy="steps",
save_steps=100,
fp16=False,
bf16=True,
optim="paged_adamw_8bit", # Paged Optimizer 사용
gradient_checkpointing=True,
max_grad_norm=0.3,
report_to="wandb",
)
# SFTTrainer로 학습
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
tokenizer.pad_token = tokenizer.eos_token
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=train_dataset,
tokenizer=tokenizer,
max_seq_length=2048,
)
trainer.train()
메모리 사용량 비교
QLoRA의 메모리 절감 효과는 극적이다.
| 모델 크기 | Full FT (FP16) | LoRA (FP16) | QLoRA (NF4) |
|---|---|---|---|
| 7B | 약 120GB | 약 28GB | 약 6GB |
| 13B | 약 220GB | 약 52GB | 약 10GB |
| 70B | 약 1.2TB | 약 280GB | 약 48GB |
PEFT 라이브러리 활용
Hugging Face PEFT 라이브러리 개요
Hugging Face PEFT 라이브러리는 다양한 파라미터 효율적 파인튜닝 기법을 통합된 인터페이스로 제공한다. Transformers, Accelerate, TRL 라이브러리와 긴밀하게 통합되어 있어 기존 워크플로우에 최소한의 코드 변경으로 적용할 수 있다.
# PEFT 설치
# pip install peft transformers accelerate bitsandbytes trl
# 다양한 PEFT 기법을 동일한 인터페이스로 사용
from peft import (
LoraConfig,
PrefixTuningConfig,
PromptTuningConfig,
IA3Config,
get_peft_model,
)
# LoRA
lora_config = LoraConfig(r=16, lora_alpha=32, task_type="CAUSAL_LM")
# Prefix Tuning
prefix_config = PrefixTuningConfig(
task_type="CAUSAL_LM",
num_virtual_tokens=20,
)
# Prompt Tuning
prompt_config = PromptTuningConfig(
task_type="CAUSAL_LM",
num_virtual_tokens=20,
prompt_tuning_init="TEXT",
prompt_tuning_init_text="Classify the following text:",
tokenizer_name_or_path="meta-llama/Llama-2-7b-hf",
)
# IA3 (Infused Adapter by Inhibiting and Amplifying Inner Activations)
ia3_config = IA3Config(
task_type="CAUSAL_LM",
target_modules=["k_proj", "v_proj", "down_proj"],
feedforward_modules=["down_proj"],
)
학습된 어댑터 저장과 로드
PEFT의 큰 장점은 어댑터만 별도로 저장하고 로드할 수 있다는 것이다. 7B 모델의 LoRA 어댑터는 약 30-100MB에 불과하다.
from peft import PeftModel, PeftConfig
# 어댑터 저장 (약 30-100MB)
peft_model.save_pretrained("./my-lora-adapter")
# 어댑터 로드: 베이스 모델 + 어댑터 결합
base_model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
torch_dtype=torch.bfloat16,
device_map="auto",
)
model = PeftModel.from_pretrained(base_model, "./my-lora-adapter")
# 추론 최적화: LoRA 가중치를 베이스 모델에 병합
model = model.merge_and_unload()
# 병합된 모델 저장 (추론 시 오버헤드 제거)
model.save_pretrained("./merged-model")
tokenizer.save_pretrained("./merged-model")
데이터셋 구성 전략
Instruction Tuning 데이터 포맷
Instruction tuning에서 데이터 품질은 모델 성능을 좌우하는 가장 중요한 요소다. 일반적으로 아래와 같은 포맷을 사용한다.
from datasets import Dataset
# Alpaca 형식 데이터셋 구성
def format_instruction(sample):
"""Alpaca 스타일의 프롬프트 템플릿"""
if sample.get("input"):
return f"""### Instruction:
{sample['instruction']}
### Input:
{sample['input']}
### Response:
{sample['output']}"""
else:
return f"""### Instruction:
{sample['instruction']}
### Response:
{sample['output']}"""
# 데이터셋 예시
raw_data = [
{
"instruction": "다음 텍스트의 감정을 분석하세요.",
"input": "이 제품 정말 훌륭합니다. 배송도 빠르고 품질도 최고예요!",
"output": "긍정적 감정입니다. 제품 품질과 배송 속도에 대한 만족감을 표현하고 있습니다.",
},
{
"instruction": "주어진 SQL 쿼리를 최적화하세요.",
"input": "SELECT * FROM users WHERE created_at > '2024-01-01' ORDER BY name",
"output": "SELECT id, name, email FROM users WHERE created_at > '2024-01-01' ORDER BY name LIMIT 100;\n\n최적화 포인트:\n1. SELECT *를 필요한 컬럼만 선택하도록 변경\n2. LIMIT 추가로 결과셋 제한\n3. created_at과 name에 복합 인덱스 생성 권장",
},
]
dataset = Dataset.from_list(raw_data)
formatted = dataset.map(lambda x: {"text": format_instruction(x)})
데이터 품질 관리 체크리스트
고품질 파인튜닝 데이터셋을 구축하기 위한 핵심 원칙은 다음과 같다.
- 다양성 확보: 동일한 패턴의 데이터가 편중되지 않도록 태스크 유형, 난이도, 도메인을 고르게 분포
- 품질 검증: 최소 2명 이상의 검수자가 교차 검증. LLM을 활용한 자동 품질 평가도 병행
- 적절한 규모: 1,000-10,000개의 고품질 샘플이 100,000개의 저품질 샘플보다 효과적
- 포맷 일관성: instruction, input, output의 구조가 전체 데이터셋에서 일관되게 유지
- 유해 콘텐츠 제거: 편향, 유해 표현, 개인정보가 포함된 샘플 사전 필터링
하이퍼파라미터 튜닝
핵심 하이퍼파라미터 가이드
파인튜닝 성능은 하이퍼파라미터 설정에 민감하다. 아래는 실전에서 검증된 권장값이다.
| 파라미터 | 권장 범위 | 설명 |
|---|---|---|
| Learning Rate | 1e-4 ~ 3e-4 | QLoRA의 경우 2e-4가 일반적 시작점 |
| Batch Size (effective) | 32-128 | gradient accumulation으로 조절 |
| Epochs | 1-5 | 데이터 규모에 따라 조절. 소규모 시 3-5, 대규모 시 1-2 |
| Warmup Ratio | 0.03-0.1 | 전체 스텝의 3-10% |
| Weight Decay | 0.01-0.1 | L2 정규화. 과적합 방지 |
| Max Grad Norm | 0.3-1.0 | 그래디언트 클리핑 임계값 |
| LR Scheduler | cosine | cosine annealing이 가장 안정적 |
| LoRA r | 8-64 | 태스크 복잡도에 비례하여 증가 |
| LoRA alpha | 2 * r | 스케일링 팩터 |
| LoRA dropout | 0.05-0.1 | 과적합 방지 |
학습 모니터링
# Weights and Biases를 활용한 학습 모니터링
import wandb
wandb.init(
project="llm-finetuning",
config={
"model": "Llama-2-7b",
"method": "QLoRA",
"r": 16,
"alpha": 32,
"lr": 2e-4,
"epochs": 3,
},
)
# 주요 모니터링 지표
# 1. Training Loss: 꾸준히 감소해야 함. 급격한 감소 후 정체는 과적합 신호
# 2. Validation Loss: training loss와 gap이 벌어지면 과적합
# 3. Learning Rate: 스케줄러가 의도대로 동작하는지 확인
# 4. Gradient Norm: 급격한 스파이크는 학습 불안정 신호
# 5. GPU Memory: OOM 방지를 위한 메모리 사용량 추적
트러블슈팅
Catastrophic Forgetting (치명적 망각)
파인튜닝 후 모델이 기본적인 일반 지식을 잃어버리는 현상이다.
- 원인: 소규모 도메인 데이터에 과도하게 적합되면서 사전 학습된 표현이 훼손됨
- 해결책 1: LoRA의 랭크를 낮추어 업데이트 범위를 제한 (r=8 이하)
- 해결책 2: 학습률을 1e-5 수준으로 낮추고 epoch 수를 줄임
- 해결책 3: 일반 지식 데이터를 학습 데이터에 10-20% 비율로 혼합
- 해결책 4: L2 정규화 (weight_decay) 강화
소규모 데이터셋 과적합
데이터가 1,000개 미만인 경우 과적합이 빈번하게 발생한다.
- 증상: training loss는 0에 수렴하지만 validation loss가 상승
- 해결책 1: 데이터 증강 - LLM을 활용한 paraphrasing으로 데이터 2-3배 확장
- 해결책 2: LoRA dropout을 0.1-0.2로 높이고 weight decay를 0.05 이상으로 설정
- 해결책 3: epoch을 1-2로 줄이고 early stopping 적용
- 해결책 4: 더 작은 베이스 모델 사용 (70B 대신 7B)
양자화 품질 저하
QLoRA 사용 시 양자화로 인한 정보 손실이 성능에 영향을 줄 수 있다.
- 증상: 동일 설정의 LoRA (FP16) 대비 성능이 2-5% 이상 하락
- 해결책 1: compute_dtype을 bfloat16으로 설정 (float16보다 안정적)
- 해결책 2: LoRA 랭크를 높여 표현력 보상 (r=32-64)
- 해결책 3: 학습 완료 후 merge_and_unload로 FP16 모델로 복원하여 서빙
- 해결책 4: IR-QLoRA, Q-BLoRA 등 개선된 양자화 파인튜닝 기법 검토
운영 체크리스트
프로덕션 수준의 LLM 파인튜닝을 위한 엔드투엔드 체크리스트다.
학습 전
- 베이스 모델 선정: 태스크 특성, 언어, 라이선스, 모델 크기 검토
- 데이터 파이프라인: 수집, 정제, 포매팅, 품질 검증, train/val/test 분할
- 환경 설정: GPU 사양 확인, 라이브러리 버전 호환성, CUDA 버전 점검
- 베이스라인 측정: 파인튜닝 전 모델의 태스크 성능 기록
학습 중
- 모니터링: loss curve, gradient norm, GPU 메모리 실시간 추적
- 체크포인트: 일정 간격으로 모델 저장, validation loss 기준 best model 관리
- Early stopping: validation loss가 3-5 스텝 이상 개선되지 않으면 중단
학습 후
- 정량 평가: 태스크별 벤치마크 점수 측정 (BLEU, ROUGE, accuracy 등)
- 정성 평가: 다양한 입력에 대한 출력 품질 수동 검수
- 일반 능력 검증: catastrophic forgetting 여부 확인
- 어댑터 병합: merge_and_unload 후 서빙 최적화
- A/B 테스트: 기존 모델 대비 실사용 환경에서 성능 비교
참고자료
- LoRA: Low-Rank Adaptation of Large Language Models (Hu et al., 2021)
- QLoRA: Efficient Finetuning of Quantized LLMs (Dettmers et al., 2023)
- Hugging Face PEFT Documentation
- Hugging Face PEFT GitHub Repository
- Instruction Tuning for Large Language Models: A Survey
- An Empirical Study of Catastrophic Forgetting in LLMs During Continual Fine-tuning
- Fine-tuning LLMs in 2025 - SuperAnnotate Guide
- Microsoft LoRA Implementation (loralib)