소개: 신속한 엔지니어링이 충분하지 않은 경우
신속한 엔지니어링은 강력하지만 한계가 있습니다. 따라야 할 모델이 필요할 때 특정 스타일을 일관적으로 따르거나, 독자적인 형식으로 대응하거나, 특정 분야에서 탁월함 틈새 시장 미세 조정 솔루션이 됩니다. 미세 조정을 통해 모델 가중치를 조정합니다. 귀하의 데이터에 귀하의 도메인이 요구하는 대로 "생각"하는 특수 버전을 생성합니다.
그러나 수십억 개의 매개변수가 포함된 모델을 완벽하게 미세 조정하는 데는 엄청난 비용이 듭니다. 다음과 같은 기술 로라, QLoRA e PEFT 그들은 혁명을 일으켰다 이 프로세스를 통해 700억 개의 매개변수 모델을 단일 모델에 맞추는 것이 가능해졌습니다. 소비자 GPU는 총 가중치의 0.1% 미만을 변경합니다.
이 기사에서 배울 내용
- 완전 미세 조정과 매개변수 효율적인 기술의 차이점
- LoRA(Low-Rank Adaptation)의 작동 방식과 효율적인 이유
- QLoRA: 제한된 GPU를 위한 양자화와 LoRA 결합
- 미세 조정을 위한 데이터 세트 준비
- Hugging Face와 PEFT를 이용한 실제 구현
- 신속한 엔지니어링보다 미세 조정이 더 나은 경우
전체 미세 조정과 매개변수 효율적인 미세 조정
에서 완전한 미세 조정, 훈련 중에 모든 모델 매개변수가 업데이트됩니다. Llama 3 70B와 같은 모델의 경우 이는 700억 개의 가중치를 업데이트하는 것을 의미합니다. 수백 GB의 GPU 메모리와 상당한 하드웨어 비용.
기술 PEFT(매개변수 효율적인 미세 조정) 그들은 이 문제를 해결해 매개변수의 작은 부분만 업데이트하여 전체와 비슷한 결과를 얻습니다. 적은 자원으로 미세 조정.
리소스 비교: 전체 vs LoRA vs QLoRA
| 특성 | 전체 미세 조정 | 로라 | QLoRA |
|---|---|---|---|
| 업데이트된 매개변수 | 100% | 0.1-1% | 0.1-1% |
| GPU RAM(7B 모델) | ~60GB | ~16GB | ~6GB |
| GPU RAM(70B 모델) | ~500GB | ~160GB | ~48GB |
| 품질 결과 | 개선하다 | 전체의 ~95-98% | 전체의 ~93-97% |
| 훈련 시간 | 시간/일 | 분/시간 | 분/시간 |
| 예상 비용(70억) | $50-200 | $5-20 | $2-10 |
LoRA: 낮은 순위 적응
LoRA(낮은 순위 적응) 가장 널리 사용되는 PEFT 기술이며 직관을 기반으로 합니다. 우아한 수학: 미세 조정 중에 모델 가중치의 변경에는 낮은 순위. 전체 가중치 행렬 W(d x d 차원)를 업데이트하는 대신, LoRA는 업데이트를 랭크 r의 두 개의 작은 행렬 A와 B로 분해합니다. 여기서 r은 d보다 훨씬 작습니다.
실제로 LoRA는 모델의 모든 원래 무게를 "고정"하고 작은 어댑터 모듈을 추가합니다. 주의 레이어 옆에 있습니다. 훈련 중에는 이러한 모듈만 업데이트됩니다. 추론 중에 LoRA 가중치는 추가 비용 없이 원래 가중치와 융합될 수 있습니다.
# Configurazione LoRA con Hugging Face PEFT
from peft import LoraConfig, get_peft_model, TaskType
from transformers import AutoModelForCausalLM, AutoTokenizer
# Carica il modello base
model_name = "meta-llama/Llama-3.1-8B"
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype="auto",
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# Configura LoRA
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # Rango della decomposizione (più alto = più capacità)
lora_alpha=32, # Fattore di scala (tipicamente 2x r)
lora_dropout=0.05, # Dropout per regolarizzazione
target_modules=[ # Layer a cui applicare LoRA
"q_proj", "k_proj", # Query e Key nell'attention
"v_proj", "o_proj", # Value e Output projection
],
bias="none" # Non addestrare i bias
)
# Applica LoRA al modello
peft_model = get_peft_model(model, lora_config)
# Verifica parametri trainabili
peft_model.print_trainable_parameters()
# Output: trainable params: 6,553,600 || all params: 8,030,261,248
# Percentage: 0.082% dei parametri totali!
순위 r을 선택하는 방법
매개변수 r (순위)는 LoRA 적응의 표현 능력을 결정합니다.
- r = 4-8: 간단한 작업에 충분함(분류, 출력형식)
- r = 16-32: 대부분의 사용 사례에 적합한 균형
- r = 64-128: 행동에 상당한 변화가 필요한 복잡한 작업용
QLoRA: LoRA + 양자화
QLoRA LoRA와 결합 4비트 양자화 기본 모델의. 원래 패턴은 float16(가중치당 16비트)에서 int4(가중치당 4비트)로 압축됩니다. 필요한 메모리를 약 4배로 줄입니다. LoRA 모듈은 float16에 남아 있습니다. 미세 조정 정밀도를 유지합니다.
# QLoRA: fine-tuning con quantizzazione 4-bit
from transformers import BitsAndBytesConfig
import torch
# Configurazione quantizzazione 4-bit
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # Quantizza a 4 bit
bnb_4bit_quant_type="nf4", # NormalFloat4 (migliore per LLM)
bnb_4bit_compute_dtype=torch.bfloat16, # Compute in bfloat16
bnb_4bit_use_double_quant=True # Doppia quantizzazione per risparmiare RAM
)
# Carica modello quantizzato
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantization_config=bnb_config,
device_map="auto"
)
# Applica LoRA sopra il modello quantizzato
peft_model = get_peft_model(model, lora_config)
# Ora il modello 8B richiede solo ~6GB di VRAM!
print(f"Memoria GPU: ~{torch.cuda.memory_allocated() / 1e9:.1f} GB")
데이터 세트 준비
미세 조정의 품질은 데이터세트의 품질에 직접적으로 좌우됩니다. 잘 준비된 데이터 세트 완벽한 하이퍼파라미터보다 더 중요합니다. 표준 형식은 명령-응답 쌍.
# Preparazione dataset per fine-tuning
import json
# Formato instruction-following standard
training_examples = [
{
"instruction": "Analizza il sentiment di questa recensione del ristorante",
"input": "La pasta era fredda e il servizio lentissimo. Mai più.",
"output": "NEGATIVO. La recensione esprime insoddisfazione per due aspetti: qualità del cibo (pasta fredda) e servizio (lentissimo). L'espressione 'Mai più' indica un'esperienza fortemente negativa."
},
{
"instruction": "Analizza il sentiment di questa recensione del ristorante",
"input": "Ambiente carino, cibo nella media. Prezzi un po' alti per la zona.",
"output": "NEUTRO/MISTO. La recensione presenta aspetti positivi (ambiente carino), neutri (cibo nella media) e negativi (prezzi alti). Il giudizio complessivo e bilanciato con leggera tendenza negativa."
}
]
# Formattazione per il training
def format_for_training(example: dict) -> str:
"""Formatta un esempio nel template chat standard."""
prompt = f"""### Instruction:
{example['instruction']}
### Input:
{example['input']}
### Response:
{example['output']}"""
return prompt
# Salva dataset
with open("training_data.jsonl", "w") as f:
for ex in training_examples:
f.write(json.dumps({"text": format_for_training(ex)}) + "\n")
print(f"Dataset creato con {len(training_examples)} esempi")
데이터세트 모범 사례
- 질 > 양: 500개의 고품질 사례가 5,000개의 평범한 사례를 능가합니다.
- 다양성: 모델이 처리해야 하는 작업의 모든 변형을 포괄합니다.
- 일관성: 모든 예시에서 형식과 스타일을 일관되게 유지하세요.
- 밸런싱: 클래스를 균등하게 분배합니다(긍정적/부정적/중립).
- 확인: 평가를 위해 최소 10~20%의 데이터를 분리
- 청소: 중복, 문법 오류, 일관성 없는 답변 제거
교육 및 평가
미세 조정 훈련은 표준 훈련과 동일한 원칙을 따릅니다: 손실 최소화 훈련 예시에 대해 그러나 LoRA/QLoRA를 사용하면 프로세스가 훨씬 빠르고 까다로워집니다. 자원이 적습니다.
# Training con Hugging Face Trainer
from transformers import TrainingArguments, Trainer
from datasets import load_dataset
# Carica dataset
dataset = load_dataset("json", data_files="training_data.jsonl", split="train")
dataset = dataset.train_test_split(test_size=0.1)
# Tokenizza
def tokenize(example):
return tokenizer(
example["text"],
truncation=True,
max_length=512,
padding="max_length"
)
tokenized = dataset.map(tokenize, batched=True)
# Configura training
training_args = TrainingArguments(
output_dir="./fine-tuned-model",
num_train_epochs=3, # Numero di epoch (2-5 per LoRA)
per_device_train_batch_size=4, # Batch size per GPU
gradient_accumulation_steps=4, # Simula batch size più grande
learning_rate=2e-4, # Learning rate (1e-4 - 3e-4 per LoRA)
warmup_steps=100, # Warmup graduale
logging_steps=10, # Log ogni 10 step
save_strategy="epoch", # Salva a ogni epoch
evaluation_strategy="epoch", # Valuta a ogni epoch
fp16=True, # Mixed precision per velocità
)
# Avvia training
trainer = Trainer(
model=peft_model,
args=training_args,
train_dataset=tokenized["train"],
eval_dataset=tokenized["test"],
)
trainer.train()
# Salva il modello LoRA (solo gli adapter, pochi MB)
peft_model.save_pretrained("./lora-adapters")
print("Training completato! Adapter salvati.")
병합 및 배포
훈련 후 LoRA 어댑터는 두 가지 방법으로 사용할 수 있습니다. 별도로 로드됩니다. 기본 모델 위에 있거나(유연하며 여러 어댑터를 가질 수 있음) 기본 모델과 하나로 병합됩니다. 단일 모델(배포가 쉽고 추론 오버헤드 없음)
# Merge degli adapter LoRA con il modello base
from peft import PeftModel
# Carica modello base + adapter
base_model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
torch_dtype=torch.float16,
device_map="auto"
)
merged_model = PeftModel.from_pretrained(base_model, "./lora-adapters")
# Fondi adapter con modello base
merged_model = merged_model.merge_and_unload()
# Salva modello completo
merged_model.save_pretrained("./final-model")
tokenizer.save_pretrained("./final-model")
print("Modello finale salvato (base + LoRA fusi)")
# Test del modello fine-tuned
inputs = tokenizer("### Instruction:\nAnalizza il sentiment...", return_tensors="pt")
outputs = merged_model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
의사결정 프레임워크: 미세 조정과 신속한 엔지니어링
미세 조정이 항상 올바른 선택은 아닙니다. 투자 시기를 결정하는 프레임워크는 다음과 같습니다. 미세 조정 및 즉각적인 엔지니어링으로 충분할 때.
언제 무엇을 선택해야 하는가
| 대본 | 추천 | 이유 |
|---|---|---|
| 특정 형식의 일반 할당 | 신속한 엔지니어링 | 몇 번의 샷이면 충분합니다 |
| 특정 용어가 포함된 틈새 도메인 | 미세 조정 | 모델은 어휘를 배워야 합니다. |
| 일관된 글쓰기 스타일 | 미세 조정 | 프롬프트만으로는 유지 관리가 어려움 |
| 제한된 예산, 적은 데이터 | 신속한 엔지니어링 | 미세 조정에는 데이터와 컴퓨팅이 필요합니다. |
| 심각한 대기 시간, 토큰당 높은 비용 | 미세 조정(소형 모델) | 작은 미세 조정 모델이 큰 일반 모델을 능가합니다. |
| 데이터 개인 정보 보호 요구 사항 | 미세 조정(오픈 소스) | 제3자에게 데이터가 전송되지 않습니다. |
결론
LoRA 및 QLoRA를 통한 미세 조정은 언어 모델의 적응을 민주화했습니다. 무엇 지금은 값비싼 GPU 클러스터가 필요했고 단일 소비자 GPU에서도 가능했습니다. 전체 모델 매개변수의 1% 미만입니다.
성공의 열쇠는 데이터 세트의 품질: 수동으로 선별한 500개 예시 자동으로 생성된 10,000개의 예제보다 더 나은 결과를 생성합니다. 시간을 투자하세요 하이퍼파라미터뿐만 아니라 데이터 준비도 가능합니다.
다음 기사에서는 LLM을 도입하는 방법을 살펴 보겠습니다. 생산: OpenAI API 및 Anthropic, 오픈 소스 모델 배포, 캐싱 전략, 속도 제한, 모니터링 그리고 비용 관리.







