はじめに: 迅速なエンジニアリングでは不十分な場合
迅速なエンジニアリングは強力ですが、限界もあります。従うべきモデルが必要な場合 特定のスタイルを一貫して実行する、独自の形式で応答する、または特定の分野で優れている ニッチな、 微調整 が解決策になります。微調整によりモデルの重みを調整します データに変換し、ドメインの要求に応じて「考える」特殊なバージョンを作成します。
しかし、数十億のパラメータを持つモデルを完全に微調整するには、法外な費用がかかります。 のようなテクニック LoRA, QLoRA e PEFT 彼らは革命を起こした このプロセスにより、700 億のパラメータ モデルを単一のパラメータに適合させることが可能になります。 コンシューマ GPU、総重量の 0.1% 未満の変更。
この記事で学べること
- 完全な微調整とパラメータ効率の高い手法の違い
- LoRA (低ランク適応) の仕組みとそれが非常に効率的である理由
- QLoRA: 限られた GPU 向けに量子化と LoRA を組み合わせる
- 微調整のためのデータセットの準備
- ハグフェイスとPEFTによる実用化
- 迅速なエンジニアリングよりも微調整の方が優れている場合
完全な微調整とパラメータ効率の高い微調整
Nel 完全な微調整、すべてのモデルパラメータはトレーニング中に更新されます。 Llama 3 70B のようなモデルの場合、これは 700 億のウェイトを更新することを意味し、 数百 GB の GPU メモリと多額のハードウェア コストが必要です。
テクニック PEFT (パラメータ効率の良い微調整) 彼らはこの問題を解決します パラメータのごく一部のみを更新し、完全なパラメータと同等の結果を得る リソースの一部を使用して微調整します。
リソースの比較: フル vs LoRA vs QLoRA
| 特性 | 完全な微調整 | LoRA | QLoRA |
|---|---|---|---|
| 更新されたパラメータ | 100% | 0.1~1% | 0.1~1% |
| GPU RAM (7B モデル) | ~60GB | ~16GB | ~6GB |
| GPU RAM (70B モデル) | ~500GB | ~160GB | ~48GB |
| 質の高い結果 | 改善する | 最大の 95 ~ 98% | 最大の 93 ~ 97% |
| トレーニング時間 | 時間/日数 | 分/時間 | 分/時間 |
| 推定コスト (7B) | 50~200ドル | 5ドルから20ドル | 2ドルから10ドル |
LoRA: 低ランクの適応
LoRA (低ランク適応) これは最も人気のある PEFT テクニックであり、直感に基づいています。 エレガントな計算: 微調整中にモデルの重みを変更すると、 下位。完全な重み行列 W (d x d 次元) を更新する代わりに、 LoRA は、更新をランク r の 2 つの小さな行列 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 分の 1 に削減されます。 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 アダプターは 2 つの方法で使用できます。 個別にロードする ベース モデルの上に配置するか (柔軟で、複数のアダプターを使用できます)、またはベース モデルと 1 つに結合します。 単一モデル (展開が簡単、推論オーバーヘッドなし)。
# 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))
意思決定の枠組み: 微調整 vs 迅速なエンジニアリング
微調整が常に正しい選択であるとは限りません。投資時期を決定するためのフレームワークは次のとおりです 微調整中、および迅速なエンジニアリングで十分な場合。
いつ何を選択するか
| シナリオ | おすすめ | 理由 |
|---|---|---|
| 特定の形式の一般的な割り当て | 迅速なエンジニアリング | 数発撃てば十分 |
| 特殊な用語を使用したニッチな領域 | 微調整 | モデルは語彙を学習する必要があります |
| 一貫した書き方 | 微調整 | プロンプトのみでは保守が困難 |
| 限られた予算、少ないデータ | 迅速なエンジニアリング | 微調整にはデータと計算が必要です |
| クリティカルなレイテンシー、トークンあたりのコストが高い | 微調整(小型モデル) | 小型の微調整モデルが大型の汎用モデルを上回る |
| データプライバシー要件 | 微調整 (オープンソース) | データは第三者に送信されません |
結論
LoRA と QLoRA による微調整により、言語モデルの適応が民主化されました。何 以前は高価な GPU クラスターが必要でしたが、現在は単一のコンシューマー GPU で可能です。 モデルパラメータ全体の 1% 未満です。
成功の鍵はここにあります データセットの品質: 手動で厳選された 500 個のサンプル 自動的に生成された 10,000 個の例よりも優れた結果が得られます。 ~に時間を投資する ハイパーパラメータだけでなく、データの準備も可能です。
次の記事では、LLM を導入する方法について説明します。 生産: OpenAI API Anthropic、オープンソース モデルの展開、キャッシュ戦略、レート制限、モニタリング そしてコスト管理。







