この記事で学べること

  • 巨大なモデルを一般家庭用GPU(VRAM 12GB〜)で再学習させるLoRAの仕組み
  • Hugging Face peft ライブラリを用いた実践的な実装コード
  • 学習を失敗させないためのハイパーパラメータ選定とメモリ節約術

前提条件

  • GPU環境: NVIDIA製GPU(VRAM 12GB以上推奨。RTX 3060/4060 Ti 16GB等)
  • OS: Linux (Ubuntu推奨) または WSL2
  • Python: 3.10以上
  • ライブラリ: transformers, peft, bitsandbytes, accelerate

「とりあえず動けばいい」という考えは捨ててください。なぜそのパラメータを設定するのか、技術者なら裏側を意識しましょう。

Step 1: 環境準備

まずは依存ライブラリのインストールです。LoRAを効率よく行うには、モデルを4-bit量子化してロードするための bitsandbytes が必須です。

# 仮想環境の作成(推奨)
python -m venv venv
source venv/bin/activate

# 必須ライブラリのインストール
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install -U transformers peft accelerate bitsandbytes datasets

GPUが正しく認識されているか、以下のコマンドで確認してください。

python -c "import torch; print(torch.cuda.is_available())"

ここで False が出るようなら、環境構築以前の問題です。ドライバを入れ直してください。

Step 2: 基本設定

LoRAの本質は、元の重みを固定し、小さな差分行列(Adapter)だけを学習することにあります。この「差分」のサイズを決めるのが r (rank) です。

以下のコードは、Llama-3やMistralなどのデコーダーモデルを対象とした設定例です。

from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
import torch

model_id = "meta-llama/Meta-Llama-3-8B" # またはローカルパス

# 1. メモリ節約のための4-bit量子化設定
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16
)

# 2. ベースモデルのロード
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=bnb_config,
    device_map="auto"
)

# 3. LoRA設定
lora_config = LoraConfig(
    r=16,                         # ランク数。8〜32が一般的。上げすぎるとメモリを食う
    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"
)

# 4. モデルにLoRAを適用
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()

target_modules はモデルのアーキテクチャによって異なります。model を print して、線形層の名前を確認する癖をつけてください。

Step 3: 実行と確認

学習には Hugging Face の SFTTrainer (trlライブラリ) を使うのが現代の定石です。

from trl import SFTTrainer
from transformers import TrainingArguments
from datasets import load_dataset

# データセットの準備(jsonl形式を想定)
# dataset = load_dataset("json", data_files="train_data.jsonl", split="train")

training_args = TrainingArguments(
    output_dir="./lora-llama3-results",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    logging_steps=10,
    num_train_epochs=3,
    save_strategy="epoch",
    bf16=True, # GPUが対応していれば必ずTrueに
    optim="paged_adamw_32bit"
)

trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=1024,
    args=training_args,
)

trainer.train()

# アダプターのみ保存
model.save_pretrained("./final_lora_adapter")

学習が終わると、adapter_model.bin という非常に小さなファイルが生成されます。これがあなたの成果物です。

よくあるエラーと対処法

エラー1: CUDA Out of Memory (OOM)

torch.cuda.OutOfMemoryError: CUDA out of memory.
Tried to allocate 256.00 MiB (GPU 0; 12.00 GiB total capacity; ...)

解決策:

  • per_device_train_batch_size を 1 に下げ、gradient_accumulation_steps を上げてください。
  • max_seq_length を短く設定(512など)してください。
  • それでもダメなら、もっと高いGPUを買うか、クラウド(PaperspaceやColab)に金を払ってください。

エラー2: ValueError: Target modules not found

ValueError: Target modules {'q_proj'} not found in the base model.

解決策: モデルによって層の名前が違います。Mistral系は q_proj, v_proj ですが、他のカスタムモデルでは query_key_value などになっている場合があります。print(model) で構造を叩き出してください。

まとめと次のステップ

LoRAは魔法ではありません。適切なデータセットとパラメータ選定があって初めて機能します。

  1. 次は推論を試す: 学習したアダプターをベースモデルに merge_and_unload() して統合し、推論速度を最適化しましょう。
  2. 評価指標を入れる: Lossが下がっているからといって、賢くなっているとは限りません。ベンチマークセットを用意しましょう。

「動いた」だけで満足するのは素人です。なぜその設定で精度が出たのか、ログを執筆するまでが研究員の仕事です。



📚 さらに学習を深めるためのリソース

この記事の内容をより深く理解するために、以下の書籍・教材がおすすめです:

🔍 Amazonで「NVIDIA RTX 4090」を検索 🔍 楽天で検索

※上記リンクはアフィリエイトリンクです。