LLMLLM 파인튜닝 · 4중급

LoRA/QLoRA — 오픈소스 모델 저비용 파인튜닝

LLMLoRAQLoRAPEFTHuggingFace오픈소스

LoRA vs QLoRA

LoRAQLoRA
기본 모델FP16/BF164bit 양자화
VRAM 요구중간낮음
성능약간 높음약간 낮음
7B 모델~16GB~6GB
13B 모델~28GB~10GB

QLoRA = Quantized + Low-Rank Adaptation


환경 설정

pip install transformers peft bitsandbytes datasets accelerate trl

QLoRA 파인튜닝 (Llama/Mistral)

import torch
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    TrainingArguments,
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from trl import SFTTrainer
from datasets import load_dataset

# 1. 4bit 양자화 설정 (QLoRA)
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

# 2. 모델 로드
model_name = "mistralai/Mistral-7B-Instruct-v0.2"
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=bnb_config,
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# 3. LoRA 설정
lora_config = LoraConfig(
    r=16,                # Rank (낮을수록 파라미터 적음, 보통 4~64)
    lora_alpha=32,       # 스케일링 (보통 r의 2배)
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 6,815,744 || all params: 3,758,489,600 || trainable%: 0.18

학습 설정

# 4. 학습 파라미터
training_args = TrainingArguments(
    output_dir="./results",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,   # 유효 배치: 4×4=16
    learning_rate=2e-4,
    fp16=True,
    logging_steps=10,
    save_steps=100,
    eval_steps=100,
    warmup_ratio=0.05,
    lr_scheduler_type="cosine",
    report_to="none",  # "wandb"로 설정 시 실험 추적
)

# 5. 데이터셋 준비
dataset = load_dataset("json", data_files="training.jsonl")

def format_chat(sample):
    """ChatML 형식으로 텍스트 변환"""
    messages = sample["messages"]
    text = ""
    for msg in messages:
        if msg["role"] == "system":
            text += f"<|system|>\n{msg['content']}\n"
        elif msg["role"] == "user":
            text += f"<|user|>\n{msg['content']}\n"
        elif msg["role"] == "assistant":
            text += f"<|assistant|>\n{msg['content']}\n"
    return {"text": text}

formatted = dataset["train"].map(format_chat)

# 6. SFT 학습
trainer = SFTTrainer(
    model=model,
    train_dataset=formatted,
    args=training_args,
    tokenizer=tokenizer,
    max_seq_length=2048,
    dataset_text_field="text",
)

trainer.train()

모델 저장과 병합

# LoRA 어댑터만 저장 (작은 파일)
model.save_pretrained("./my-lora-adapter")
tokenizer.save_pretrained("./my-lora-adapter")

# 원본 모델에 LoRA 병합 (추론 최적화)
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.float16,
    device_map="auto",
)

merged_model = PeftModel.from_pretrained(base_model, "./my-lora-adapter")
merged_model = merged_model.merge_and_unload()  # 가중치 병합

merged_model.save_pretrained("./my-merged-model")

추론

from peft import PeftModel

# 방법 1: 어댑터 로드
base_model = AutoModelForCausalLM.from_pretrained(model_name, ...)
model = PeftModel.from_pretrained(base_model, "./my-lora-adapter")

# 방법 2: 병합된 모델 직접 로드
model = AutoModelForCausalLM.from_pretrained("./my-merged-model", ...)

def generate(prompt: str, max_new_tokens: int = 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.7,
            do_sample=True,
            pad_token_id=tokenizer.eos_token_id,
        )
    return tokenizer.decode(outputs[0], skip_special_tokens=True)

정리

하이퍼파라미터영향
r (rank)낮을수록 파라미터 적음, 성능 trade-off
lora_alpha보통 r의 2배
learning_rate1e-4 ~ 3e-4 (LoRA는 더 높게 설정 가능)
n_epochs3~5 (과적합 주의)
4bit 양자화VRAM 70% 절약, 성능 약간 저하

다음 편에서는 평가와 배포 — 파인튜닝 모델의 성능을 측정하고 서비스에 배포하는 방법을 배웁니다.

궁금한 점이 있으신가요?

협업·의뢰는 아래로, 가벼운 소통은 인스타그램 @bluefox._.hi도 환영이에요.