- Authors
- Name
- はじめに
- Full Fine-tuning vs Parameter-Efficient Fine-tuning
- LoRA: Low-Rank Adaptation
- QLoRA: 4-bit量子化 + LoRA
- データ準備と学習
- ハイパーパラメータチューニングガイド
- 高度なテクニック
- まとめ
- クイズ

はじめに
7B、13B、70BパラメータのLLMをゼロから学習するには、数十〜数百のGPUと数百万ドルが必要です。しかし、ファインチューニングを活用すれば、コンシューマー向けGPU1枚でも自分だけの特化モデルを作ることができます。
この記事では、LoRA、QLoRA、PEFTライブラリを活用した実践的なファインチューニング方法を解説します。
Full Fine-tuning vs Parameter-Efficient Fine-tuning
Full Fine-tuningの問題点
7BモデルをFull Fine-tuningするには:
- モデルパラメータ: 7B × 4バイト (FP32) = 28GB
- Optimizer状態: Adamはパラメータの2倍 = 56GB
- 勾配: パラメータと同じ = 28GB
- 合計VRAM: 約112GB以上が必要
A100 80GB 1枚でも不足します。
PEFTの登場
Parameter-Efficient Fine-tuning(PEFT)は全パラメータの0.1〜1%のみを学習します:
| 方法 | 学習パラメータ比率 | VRAM(7B基準) |
|---|---|---|
| Full Fine-tuning | 100% | 約112GB |
| LoRA | 約0.1-1% | 約16GB |
| QLoRA | 約0.1-1% | 約6GB |
LoRA: Low-Rank Adaptation
数学的原理
LoRAの核心的アイデア:重み更新行列ΔWは低ランク(low-rank)である。
元の線形変換:
LoRA適用後:
ここで:
- : 元の重み(凍結)
- : 低ランク行列(学習対象)
- : 低ランク行列(学習対象)
- : ランク(通常4〜64、元の次元に比べて非常に小さい)
- : スケーリングファクター
元のW (4096 × 4096) = 16Mパラメータ [凍結]
LoRA:
A (r × 4096) + B (4096 × r) = r × 8192パラメータ
r=8の場合: 65,536パラメータ (0.4%)
コードで実装する
from peft import LoraConfig, get_peft_model, TaskType
from transformers import AutoModelForCausalLM, AutoTokenizer
# 1. ベースモデルのロード
model_name = "meta-llama/Llama-3.1-8B"
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# 2. LoRA設定
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # ランク
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"
)
# 3. PEFTモデルの作成
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 41,943,040 || all params: 8,072,204,288 || trainable%: 0.5194
target_modules選択ガイド
# モデルの全Linearレイヤーを確認
for name, module in model.named_modules():
if isinstance(module, torch.nn.Linear):
print(name, module.in_features, module.out_features)
# 一般的な選択肢:
# - Attentionのみ: ["q_proj", "v_proj"] — 最小VRAM
# - Attention全体: ["q_proj", "k_proj", "v_proj", "o_proj"] — 推奨
# - MLP含む: 上記 + ["gate_proj", "up_proj", "down_proj"] — 最大性能
QLoRA: 4-bit量子化 + LoRA
QLoRAが特別な理由
QLoRAは3つのイノベーションにより、コンシューマーGPUでの大規模モデルファインチューニングを可能にします:
- 4-bit NormalFloat(NF4): 正規分布の重みに最適化された量子化
- Double Quantization: 量子化定数自体も量子化してメモリをさらに節約
- Paged Optimizers: GPUメモリ不足時にCPUへ自動ページング
実装
from transformers import BitsAndBytesConfig
import torch
# 4-bit量子化設定
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NormalFloat4
bnb_4bit_compute_dtype=torch.bfloat16, # 演算はbf16で
bnb_4bit_use_double_quant=True, # Double Quantization
)
# 量子化モデルのロード
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantization_config=bnb_config,
device_map="auto"
)
# LoRA適用 (QLoRA = 4bit量子化モデル + LoRA)
model = get_peft_model(model, lora_config)
VRAM使用量の比較
| モデル | Full FP16 | LoRA FP16 | QLoRA 4-bit |
|---|---|---|---|
| 7B | 約28GB | 約16GB | 約6GB |
| 13B | 約52GB | 約30GB | 約10GB |
| 70B | 約280GB | 約160GB | 約48GB |
QLoRAを使えば、**RTX 3090/4090(24GB)**1枚で13Bモデルまでファインチューニングできます。
データ準備と学習
データセットフォーマット
Instructionファインチューニング用のデータフォーマット:
from datasets import load_dataset
# Alpacaスタイルデータセット
dataset = load_dataset("json", data_files="train_data.json")
# データ例
# {
# "instruction": "次のテキストを要約してください。",
# "input": "Kubernetesはコンテナ化されたワークロードとサービスを...",
# "output": "Kubernetesはコンテナオーケストレーションプラットフォームです。"
# }
# プロンプトテンプレートの適用
def format_instruction(sample):
if sample["input"]:
text = f"""### Instruction:
{sample["instruction"]}
### Input:
{sample["input"]}
### Response:
{sample["output"]}"""
else:
text = f"""### Instruction:
{sample["instruction"]}
### Response:
{sample["output"]}"""
return {"text": text}
dataset = dataset.map(format_instruction)
SFTTrainerによる学習
from trl import SFTTrainer, SFTConfig
training_args = SFTConfig(
output_dir="./output",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # 実効バッチ = 4 × 4 = 16
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.03,
max_seq_length=2048,
bf16=True,
logging_steps=10,
save_strategy="epoch",
optim="paged_adamw_8bit", # QLoRA用ページングオプティマイザー
gradient_checkpointing=True, # VRAMのさらなる節約
)
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset["train"],
args=training_args,
)
trainer.train()
学習後のモデル保存とマージ
# LoRAアダプターのみ保存(数十MB)
model.save_pretrained("./lora-adapter")
# 後でアダプターをロード
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B")
model = PeftModel.from_pretrained(base_model, "./lora-adapter")
# ベースモデルとアダプターのマージ(デプロイ用)
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./merged-model")
ハイパーパラメータチューニングガイド
LoRAランク(r)の選択
# ランク別の特性
# r=4: 最少パラメータ、シンプルなドメイン適応に適する
# r=8: 一般的な出発点
# r=16: 良いバランス(推奨)
# r=32: 複雑なタスク、より多くのVRAMが必要
# r=64+: Full Fine-tuningに近い性能、それだけ非効率
# 経験的に、r=16 + alpha=32がほとんどのケースで良好に動作
学習率
# LoRA/QLoRAの学習率はFull FTより高く設定
# Full FT: 1e-5 ~ 5e-5
# LoRA: 1e-4 ~ 3e-4
# QLoRA: 2e-4(一般的)
高度なテクニック
DoRA: Weight-Decomposed Low-Rank Adaptation
LoRAの発展形で、重みを大きさ(magnitude)と方向(direction)に分解します:
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
use_dora=True, # DoRAを有効化
)
複数のLoRAアダプターの組み合わせ
from peft import PeftModel
# ベースモデルに複数のアダプターをロード
model = PeftModel.from_pretrained(base_model, "./adapter-korean")
model.load_adapter("./adapter-code", adapter_name="code")
# アダプターの切り替え
model.set_adapter("code")
# またはアダプターの重みを組み合わせ
model.add_weighted_adapter(
adapters=["default", "code"],
weights=[0.7, 0.3],
adapter_name="merged"
)
まとめ
LoRAとQLoRAは、LLMファインチューニングのアクセシビリティを革命的に変えました。コンシューマーGPU1枚で数十億パラメータのモデルをカスタマイズできることは、AI民主化の核心です。
要点まとめ:
- LoRA: 低ランク分解で学習パラメータを0.1〜1%に削減
- QLoRA: 4-bit量子化でVRAMをさらに約4倍節約
- PEFT: Hugging Faceライブラリで数行のコードで適用可能
ぜひご自身でデータを準備し、学習し、デプロイしてみてください。思っている以上に簡単です。
クイズ
Q1: LoRAにおけるランク(r)が意味するものは?
重み更新行列ΔWを分解する際の低次元サイズです。rが小さいほど学習パラメータが少なくVRAM消費が減りますが、モデルの表現力も制限されます。
Q2: 7BモデルをFull Fine-tuningするのに必要なVRAMはおよそどのくらい?
約112GB以上。モデルパラメータ(28GB)+ Optimizer状態(56GB)+ 勾配(28GB)が必要です。
Q3: QLoRAの3つの核心的イノベーションは?
- 4-bit NormalFloat(NF4)量子化、2) Double Quantization(量子化定数の量子化)、3) Paged Optimizers(GPUからCPUへの自動ページング)
Q4: LoRAのlora_alphaパラメータの役割は?
LoRA更新のスケーリングファクターです。実際のスケールはalpha/rで計算され、通常rの2倍に設定します(r=16ならalpha=32)。
Q5: QLoRAで使用されるNF4量子化が通常のINT4より優れている理由は?
ニューラルネットワークの重みはおおよそ正規分布に従うため、正規分布に最適化されたNF4量子化は、均一分布を仮定するINT4よりも情報損失が少なくなります。
Q6: LoRAアダプターをベースモデルとマージする理由は?
推論時の追加的な計算オーバーヘッドをなくすためです。マージすると元のモデルと同じ構造になり、アダプターを分離した状態よりも推論速度が速くなります。
Q7: gradient_checkpointing=Trueの効果は?
順伝播の中間活性値をメモリに保存せず、逆伝播で再計算します。VRAMを節約しますが、学習時間は約20〜30%増加します。
Q8: LoRAのtarget_modulesの選択が性能に与える影響は?
より多くのモジュールにLoRAを適用するほど性能は向上しますが、VRAMと学習時間が増加します。Attentionのq_proj、v_projのみの適用が最小構成で、MLPまで含めると最大の性能が得られます。