Skip to content
Published on

UnslothでLLMファインチューニング完全ガイド2025:QLoRA、4bit量子化、2倍高速学習

Authors

はじめに:なぜUnslothなのか

LLMファインチューニングの最大(さいだい)の障壁(しょうへき)は**GPUメモリ(VRAM)**です。Llama 3.1 8BをFull Fine-tuningするには約(やく)60GB VRAMが必要(ひつよう)で、A100 80GB 1台(だい)でもギリギリです。QLoRAがこの問題(もんだい)を解決(かいけつ)しましたが、学習速度(がくしゅうそくど)は依然(いぜん)として遅(おそ)いままでした。

Unslothはこの2つの問題(もんだい)を同時(どうじ)に解決(かいけつ)します:

比較項目(ひかくこうもく)HuggingFace PEFTAxolotlUnsloth
学習速度1x(基準)1.1x2x
メモリ使用量100%95%40%
設定難易度中程度高い低い
対応モデル全体全体主要モデル
Flash Attention別途インストール内蔵内蔵
カスタムカーネルなしなしTritonカーネル

Unslothの核心(かくしん)の秘密(ひみつ)はカスタムTritonカーネルです。Attention、MLP、Cross-Entropy Lossなどの核心(かくしん)演算(えんざん)をGPU最適化(さいてきか)されたカスタムカーネルに置(お)き換(か)え、2倍高速(こうそく)な学習(がくしゅう)と60%のメモリ節約(せつやく)を実現(じつげん)しています。

対応(たいおう)モデル(2025年(ねん)時点(じてん)):

  • Llama 3 / 3.1 / 3.2 (8B, 70B)
  • Mistral / Mixtral
  • Phi-3 / Phi-3.5
  • Qwen 2 / 2.5
  • Gemma 2
  • Yi
  • DeepSeek V2

1. LoRA/QLoRA理論(りろん)

1.1 Full Fine-tuning vs LoRA vs QLoRA

Full Fine-tuning(全パラメータ更新)
+------------------------+
|   W (d x d)            |  <- 全体の重み更新
|: 4096 x 4096      |     = 16Mパラメータ
|   = 64MB (FP16)        |
+------------------------+

LoRA (Low-Rank Adaptation)
+------------------------+
|   W0(固定)+ B * A     |
|   W0: 4096 x 4096     |  <- 固定(更新なし)
|   B: 4096 x 16         |  <- 学習 (65Kパラメータ)
|   A: 16 x 4096         |  <- 学習 (65Kパラメータ)
|   = 0.25MB (FP16)      |     合計130Kパラメータ
+------------------------+

QLoRA (Quantized LoRA)
+------------------------+
|   W0 (4bit) + B * A   |
|   W0: 4096 x 4096     |  <- 4bit量子化 (8MB)
|   B: 4096 x 16         |  <- FP16学習
|   A: 16 x 4096         |  <- FP16学習
|   = 8.25MB 合計         |
+------------------------+

1.2 Low-Rank Decompositionの原理(げんり)

LoRAの核心(かくしん)アイデアは、重(おも)み更新行列(こうしんぎょうれつ)が実際(じっさい)には低(てい)ランク(low-rank)であるという観察(かんさつ)に基(もと)づいています。

元(もと)の重(おも)み更新(こうしん):

W_new = W_old + delta_W

LoRAはdelta_Wを2つの小(ちい)さな行列(ぎょうれつ)の積(せき)に分解(ぶんかい)します:

delta_W = B * A
ここで:
  Bは d x r 行列 (d=モデル次元, r=LoRAランク)
  Aは r x d 行列
  r << d (: r=16, d=4096)

パラメータ節約効果(せつやくこうか):

# Full Fine-tuningパラメータ数
d = 4096
full_params = d * d  # = 16,777,216 (16.7M)

# LoRAパラメータ数
r = 16
lora_params = d * r + r * d  # = 131,072 (131K)

# 節約率
savings = 1 - (lora_params / full_params)
print(f"パラメータ節約: {savings:.2%}")  # 99.22%

1.3 4-bit NormalFloat量子化(りょうしか)(NF4)

QLoRAで使用(しよう)するNF4量子化(りょうしか)は一般的(いっぱんてき)な4-bitとは異(こと)なります:

一般的(いっぱんてき)な4-bit INT量子化(りょうしか):

  • 均一(きんいつ)に16区間(くかん)に分割(ぶんかつ)
  • 値(あたい)の分布(ぶんぷ)を考慮(こうりょ)しない

NF4 (NormalFloat4):

  • 重(おも)みが正規分布(せいきぶんぷ)に従(したが)うという事実(じじつ)を活用(かつよう)
  • 正規分布(せいきぶんぷ)の分位数(ぶんいすう)に合(あ)わせて16個(こ)の値(あたい)を設定(せってい)
  • 情報理論的(じょうほうりろんてき)に最適(さいてき)に近(ちか)い量子化(りょうしか)

1.4 メモリ比較表(ひかくひょう)

モデルFull FT (FP16)LoRA (FP16)QLoRA (4bit)
Llama 3 8B約60GB約18GB約6GB
Llama 3 70B約500GB約160GB約40GB
Mistral 7B約52GB約16GB約5GB
Phi-3 3.8B約28GB約9GB約3GB
Qwen 2 7B約52GB約16GB約5GB

2. 環境設定(かんきょうせってい)

2.1 GPU要件(ようけん)

GPUVRAM学習(がくしゅう)可能(かのう)モデル(QLoRA)
T4 (Colab Free)16GB7B〜8B (seq_len 1024)
A10G24GB7B〜13B
RTX 409024GB7B〜13B
A100 40GB40GB7B〜70B
A100 80GB80GB70B+
Apple M2 Ultra192GBCPU学習(遅い)

2.2 Google Colabセットアップ

# ColabでのUnslothインストール(T4 GPU基準)
# ランタイム -> ランタイムのタイプを変更 -> T4 GPU選択

# 1. Unslothインストール
!pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
!pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes

# 2. GPU確認
import torch
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"VRAM: {torch.cuda.get_device_properties(0).total_mem / 1024**3:.1f} GB")

2.3 ローカル環境設定(かんきょうせってい)

# Conda環境作成
conda create -n unsloth python=3.11
conda activate unsloth

# PyTorchインストール (CUDA 12.1)
conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia

# Unslothインストール
pip install "unsloth[cu121] @ git+https://github.com/unslothai/unsloth.git"
pip install --no-deps trl peft accelerate bitsandbytes

# インストール確認
python -c "from unsloth import FastLanguageModel; print('Unsloth OK')"

3. Unslothファインチューニング ステップバイステップ

3.1 モデルローディング

from unsloth import FastLanguageModel
import torch

# モデルとトークナイザのロード
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/Meta-Llama-3.1-8B-bnb-4bit",  # 4bit事前量子化モデル
    max_seq_length=2048,    # 最大シーケンス長
    dtype=None,             # 自動検出 (A100: bfloat16, その他: float16)
    load_in_4bit=True,      # 4bit量子化ロード
)

# GPUメモリ確認
gpu_stats = torch.cuda.get_device_properties(0)
start_gpu_memory = round(torch.cuda.max_memory_reserved() / 1024 / 1024 / 1024, 3)
max_memory = round(gpu_stats.total_mem / 1024 / 1024 / 1024, 3)
print(f"GPU = {gpu_stats.name}. Max memory = {max_memory} GB.")
print(f"{start_gpu_memory} GB of memory reserved.")

推奨(すいしょう)事前量子化(りょうしか)モデル:

用途(ようと)モデルサイズ
一般韓国語unsloth/Meta-Llama-3.1-8B-bnb-4bit約5GB
韓国語特化beomi/Llama-3-Open-Ko-8B-bnb-4bit約5GB
コーディングunsloth/Mistral-7B-v0.3-bnb-4bit約4.5GB
軽量unsloth/Phi-3.5-mini-instruct-bnb-4bit約2.5GB
多言語unsloth/Qwen2.5-7B-bnb-4bit約4.5GB

3.2 LoRAアダプタ設定(せってい)

# LoRAアダプタ追加
model = FastLanguageModel.get_peft_model(
    model,
    r=16,                          # LoRAランク (8, 16, 32, 64)
    target_modules=[               # LoRAを適用するモジュール
        "q_proj", "k_proj", "v_proj", "o_proj",  # Attention
        "gate_proj", "up_proj", "down_proj",       # MLP
    ],
    lora_alpha=16,                 # LoRA alpha(通常rと同じ)
    lora_dropout=0,                # Unslothでは0が最適
    bias="none",                   # bias学習なし
    use_gradient_checkpointing="unsloth",  # Unsloth最適化チェックポインティング
    random_state=3407,
    use_rslora=False,
    loftq_config=None,
)

# 学習可能なパラメータ確認
def print_trainable_parameters(model):
    trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
    total = sum(p.numel() for p in model.parameters())
    print(f"学習可能: {trainable:,} / 全体: {total:,} = {trainable/total:.2%}")

print_trainable_parameters(model)
# 学習可能: 41,943,040 / 全体: 8,030,261,248 = 0.52%

LoRAランク選択(せんたく)ガイド:

LoRA rパラメータ数(すう)VRAM追加(ついか)推奨用途(すいしょうようと)
8約21M約80MB簡単なタスク、VRAM制限
16約42M約160MB一般的な推奨値
32約84M約320MB複雑なタスク
64約168M約640MB大規模データ、高い表現力
128約336M約1.3GB実験的、Full FTに近い

4. データ準備(じゅんび)

4.1 Chat Templateフォーマッティング

# Alpacaプロンプトテンプレート
alpaca_prompt = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.

### Instruction:
{}

### Input:
{}

### Response:
{}"""

# データセットフォーマッティング関数
EOS_TOKEN = tokenizer.eos_token

def formatting_prompts_func(examples):
    instructions = examples["instruction"]
    inputs = examples["input"]
    outputs = examples["output"]
    texts = []
    for instruction, input_text, output in zip(instructions, inputs, outputs):
        text = alpaca_prompt.format(instruction, input_text, output) + EOS_TOKEN
        texts.append(text)
    return {"text": texts}

4.2 データセットのロードと変換(へんかん)

from datasets import load_dataset

# KoAlpacaデータセットのロード
dataset = load_dataset("beomi/KoAlpaca-v1.1a", split="train")

# フォーマット変換
def format_koalpaca(examples):
    texts = []
    for instruction, output in zip(examples["instruction"], examples["output"]):
        text = alpaca_prompt.format(instruction, "", output) + EOS_TOKEN
        texts.append(text)
    return {"text": texts}

dataset = dataset.map(format_koalpaca, batched=True)

# OpenAI Messagesフォーマット(Llama 3 chat template使用)
def format_openai_messages(examples):
    texts = []
    for messages in examples["messages"]:
        text = tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=False,
        )
        texts.append(text)
    return {"text": texts}

5. 学習設定(がくしゅうせってい)

5.1 SFTTrainer設定(せってい)

from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=2048,
    dataset_num_proc=2,
    packing=False,
    args=TrainingArguments(
        # === 基本設定 ===
        output_dir="./outputs",
        num_train_epochs=3,

        # === バッチ & メモリ ===
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,  # 有効バッチ = 2 * 4 = 8

        # === 学習率 ===
        learning_rate=2e-4,             # QLoRA推奨学習率
        lr_scheduler_type="cosine",
        warmup_steps=5,

        # === 精度 ===
        fp16=not is_bfloat16_supported(),
        bf16=is_bfloat16_supported(),

        # === ロギング ===
        logging_steps=1,
        logging_dir="./logs",
        report_to="wandb",

        # === 保存 ===
        save_strategy="steps",
        save_steps=100,
        save_total_limit=3,

        # === 最適化 ===
        optim="adamw_8bit",
        weight_decay=0.01,
        max_grad_norm=0.3,
        seed=3407,
    ),
)

5.2 学習率(がくしゅうりつ)ガイド

シナリオ推奨学習率(すいしょうがくしゅうりつ)理由(りゆう)
QLoRA基本2e-4QLoRA論文推奨値
大規模データ (100K+)1e-4過学習防止
小規模データ (1K以下)5e-5〜1e-4細かい学習
ドメイン適応2e-5〜5e-5既存知識の保存
Continued Pre-training1e-5〜5e-5安定した学習

5.3 学習実行(がくしゅうじっこう)

# 学習開始
trainer_stats = trainer.train()

# 学習結果出力
print(f"学習時間: {trainer_stats.metrics['train_runtime']:.2f}秒")
print(f"最終Loss: {trainer_stats.metrics['train_loss']:.4f}")

# GPUメモリ使用量確認
used_memory = round(torch.cuda.max_memory_reserved() / 1024 / 1024 / 1024, 3)
print(f"最大VRAM使用量: {used_memory} GB")

6. VRAM最適化(さいてきか)テクニック

6.1 Gradient Checkpointing

# Unsloth最適化Gradient Checkpointing
model = FastLanguageModel.get_peft_model(
    model,
    r=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                     "gate_proj", "up_proj", "down_proj"],
    use_gradient_checkpointing="unsloth",  # 重要!30% VRAM節約
)

# Gradient Checkpointingオプション:
# "unsloth": Unsloth最適化版(より高速でメモリ効率的)
# True: 標準PyTorch gradient checkpointing
# False: 無効(最速だがメモリ最大使用)

6.2 シーケンスパッキング

# 短いシーケンスを1つにまとめてGPU活用率向上
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    packing=True,           # シーケンスパッキング有効化
    max_seq_length=2048,    # パッキング後の全体長
)

# パッキング効果:
# パッキングOFF: [トークンPAD PAD PAD] [トークンPAD PAD PAD]
# パッキングON:  [トークンSEPトークントークン] -> GPU活用率向上

6.3 VRAM使用量表(しようりょうひょう)(Unsloth QLoRA基準(きじゅん))

モデルBatch=1Batch=2Batch=4Batch=8
Llama 3 8B4.2GB5.8GB8.5GB14.2GB
Mistral 7B3.8GB5.2GB7.8GB13.0GB
Phi-3 3.8B2.4GB3.2GB4.8GB7.6GB
Qwen 2 7B3.8GB5.2GB7.8GB13.0GB
Llama 3 70B36GB42GB56GBOOM

* max_seq_length=2048, gradient_checkpointing="unsloth" 基準(きじゅん)


7. モデルエクスポートと変換(へんかん)

7.1 LoRAアダプタ保存(ほぞん)

# LoRAアダプタのみ保存(小さいサイズ)
model.save_pretrained("lora_adapter")
tokenizer.save_pretrained("lora_adapter")

# 保存ファイル確認
import os
for f in os.listdir("lora_adapter"):
    size = os.path.getsize(f"lora_adapter/{f}") / 1024 / 1024
    print(f"  {f}: {size:.1f} MB")

7.2 アダプタマージ

# LoRAアダプタをベースモデルとマージ
merged_model = model.merge_and_unload()

# マージされたモデルを保存
merged_model.save_pretrained("merged_model")
tokenizer.save_pretrained("merged_model")

7.3 GGUF変換(へんかん)(llama.cpp用(よう))

# Unslothの内蔵GGUF変換機能
# 様々な量子化レベルに対応

# Q4_K_M: 最も一般的(品質/サイズのバランス)
model.save_pretrained_gguf(
    "model_gguf",
    tokenizer,
    quantization_method="q4_k_m",
)

# Q5_K_M: より高品質
model.save_pretrained_gguf(
    "model_q5",
    tokenizer,
    quantization_method="q5_k_m",
)

# Q8_0: 最高品質(サイズ大)
model.save_pretrained_gguf(
    "model_q8",
    tokenizer,
    quantization_method="q8_0",
)

GGUF量子化(りょうしか)比較(ひかく):

量子化(りょうしか)ファイルサイズ(8B)品質(ひんしつ)推論速度(すいろんそくど)推奨(すいしょう)
Q4_K_M約4.5GB良好高速一般使用
Q5_K_M約5.5GB非常に良好普通品質重視
Q8_0約8.0GB優秀低速最高品質
F16約16GB原本最も遅い参考用

7.4 Hugging Face Hubアップロード

# モデルをHugging Face Hubにアップロード

# LoRAアダプタのみアップロード
model.push_to_hub(
    "my-org/llama3-8b-korean-lora",
    token="hf_xxxxx",
    private=True,
)
tokenizer.push_to_hub(
    "my-org/llama3-8b-korean-lora",
    token="hf_xxxxx",
    private=True,
)

# GGUFファイルアップロード
model.push_to_hub_gguf(
    "my-org/llama3-8b-korean-gguf",
    tokenizer,
    quantization_method="q4_k_m",
    token="hf_xxxxx",
)

8. 評価(ひょうか)とテスト

8.1 ファインチューニング済(ず)みモデルでの推論(すいろん)

# 推論モードに切り替え
FastLanguageModel.for_inference(model)

# 単一プロンプト推論
def generate_response(instruction, input_text=""):
    prompt = alpaca_prompt.format(instruction, input_text, "")
    inputs = tokenizer([prompt], return_tensors="pt").to("cuda")

    outputs = model.generate(
        **inputs,
        max_new_tokens=512,
        temperature=0.7,
        top_p=0.9,
        repetition_penalty=1.15,
        do_sample=True,
    )

    response = tokenizer.batch_decode(outputs)[0]
    response = response.split("### Response:\n")[-1]
    response = response.replace(tokenizer.eos_token, "").strip()
    return response

# テスト
test_questions = [
    "韓国の伝統的な祝日について説明してください。",
    "Pythonでデコレータの動作原理を説明してください。",
    "健康的な食習慣のためのアドバイスを教えてください。",
]

for q in test_questions:
    print(f"Q: {q}")
    print(f"A: {generate_response(q)}")
    print("-" * 80)

8.2 生成(せいせい)パラメータチューニング

# 生成パラメータ別の効果
generation_configs = {
    "正確な回答 (factual)": {
        "temperature": 0.1,
        "top_p": 0.9,
        "repetition_penalty": 1.0,
    },
    "創造的な回答 (creative)": {
        "temperature": 0.8,
        "top_p": 0.95,
        "repetition_penalty": 1.15,
    },
    "バランスの取れた回答 (balanced)": {
        "temperature": 0.5,
        "top_p": 0.9,
        "repetition_penalty": 1.1,
    },
}

8.3 lm-eval-harnessベンチマーク

# lm-eval-harnessでベンチマーク評価
pip install lm-eval

lm_eval --model hf \
    --model_args pretrained=./merged_model \
    --tasks kobest_boolq,kobest_copa,kobest_hellaswag,kobest_sentineg,kobest_wic \
    --batch_size 4 \
    --output_path ./eval_results

9. 高度(こうど)なテクニック

9.1 マルチGPU学習(がくしゅう)(DeepSpeed ZeRO)

# deepspeed_config.json
"""
{
    "zero_optimization": {
        "stage": 2,
        "offload_optimizer": {
            "device": "cpu",
            "pin_memory": true
        },
        "allgather_partitions": true,
        "reduce_scatter": true
    },
    "bf16": {
        "enabled": true
    },
    "train_batch_size": "auto",
    "train_micro_batch_size_per_gpu": "auto"
}
"""

# 実行
# deepspeed --num_gpus 4 train.py --deepspeed deepspeed_config.json

9.2 DPO学習(がくしゅう)

from trl import DPOTrainer, DPOConfig
from unsloth import FastLanguageModel, PatchDPOTrainer

# DPOパッチ適用
PatchDPOTrainer()

# DPOデータセット準備
dpo_dataset = load_dataset("argilla/ultrafeedback-binarized-preferences", split="train")

# DPO Trainer設定
dpo_trainer = DPOTrainer(
    model=model,
    ref_model=None,           # Unslothでは None(自動処理)
    args=DPOConfig(
        output_dir="./dpo_output",
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        learning_rate=5e-7,       # DPOは低い学習率
        num_train_epochs=1,
        beta=0.1,                 # DPO beta(KL divergence重み)
        fp16=not is_bfloat16_supported(),
        bf16=is_bfloat16_supported(),
        logging_steps=1,
    ),
    train_dataset=dpo_dataset,
    tokenizer=tokenizer,
)

dpo_trainer.train()

9.3 Continued Pre-training(ドメイン適応(てきおう))

# ドメイン特化テキストでのContinued Pre-training
from trl import SFTTrainer

domain_dataset = load_dataset("my-org/medical-korean-corpus", split="train")

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=domain_dataset,
    dataset_text_field="text",
    max_seq_length=4096,     # 長いドキュメント
    packing=True,            # 効率性のためパッキング使用
    args=TrainingArguments(
        output_dir="./cpt_output",
        learning_rate=2e-5,  # 非常に低い学習率
        num_train_epochs=1,  # 1 epochで十分
        per_device_train_batch_size=1,
        gradient_accumulation_steps=8,
        optim="adamw_8bit",
        warmup_ratio=0.1,
    ),
)

trainer.train()

10. よくある問題(もんだい)と解決法(かいけつほう)

10.1 OOM(Out of Memory)エラー

# 症状: CUDA out of memory
# 解決法の順序:
# 1. batch_sizeを減らす
per_device_train_batch_size = 1  # 最小値

# 2. gradient_accumulation_stepsを増やす
gradient_accumulation_steps = 8

# 3. max_seq_lengthを減らす
max_seq_length = 1024  # 2048 -> 1024

# 4. LoRA rankを減らす
r = 8  # 16 -> 8

# 5. gradient checkpointingを確認
use_gradient_checkpointing = "unsloth"

# 6. キャッシュクリア
torch.cuda.empty_cache()
import gc
gc.collect()

10.2 NaN Loss

# 症状: lossがNaNに発散
# 原因: 学習率が高すぎるかデータの問題

# 解決法:
# 1. 学習率を下げる
learning_rate = 1e-5  # 2e-4 -> 1e-5

# 2. max_grad_normを設定
max_grad_norm = 0.3  # gradient clipping

# 3. データ検証
def check_data_issues(dataset, tokenizer):
    """データの問題を検査"""
    issues = []
    for i, item in enumerate(dataset):
        text = item["text"]
        if not text.strip():
            issues.append(f"[{i}] 空テキスト")
        tokens = tokenizer.encode(text)
        if len(tokens) > 4096:
            issues.append(f"[{i}] テキストが長すぎる: {len(tokens)} tokens")
    return issues

10.3 Catastrophic Forgetting(破滅的忘却(はめつてきぼうきゃく))

# 症状: ファインチューニング後に既存知識が消える
# 解決法:

# 1. 低い学習率を使用
learning_rate = 5e-5

# 2. 少ないepoch (1-3)
num_train_epochs = 1

# 3. データに一般知識を混合
# オリジナルデータ 80% + 一般知識データ 20%

# 4. LoRA rankを下げる(変更幅を制限)
r = 8

# 5. 正則化を強化
weight_decay = 0.1

11. クイズ

Q1. LoRAでr=16の場合、元の重みに対して何%のパラメータだけ学習しますか?

正解(せいかい):約(やく)0.5%(99.5%節約(せつやく))

d=4096の場合(ばあい):

  • Full: 4096 x 4096 = 16,777,216
  • LoRA r=16: (4096 x 16) + (16 x 4096) = 131,072
  • 比率(ひりつ): 131,072 / 16,777,216 = 0.78%

実際(じっさい)には複数(ふくすう)のモジュール(q, k, v, o, gate, up, down)に適用(てきよう)するため、総(そう)パラメータ対比(たいひ)約(やく)0.5%レベルです。

Q2. QLoRAのNF4量子化が一般的なINT4より優れている理由は?

正解(せいかい):重(おも)みの正規分布(せいきぶんぷ)特性(とくせい)を活用(かつよう)した最適(さいてき)量子化(りょうしか)

NF4はニューラルネットワークの重(おも)みが概(おおむ)ね正規分布(せいきぶんぷ)に従(したが)うという点(てん)を利用(りよう)します。正規分布(せいきぶんぷ)の分位数(ぶんいすう)に合(あ)わせて16個(こ)の量子化値(りょうしかち)を配置(はいち)するため、均一分割(きんいつぶんかつ)のINT4より情報損失(じょうほうそんしつ)が少(すく)なくなります。

Q3. Unslothが既存のHuggingFace PEFTより2倍高速な核心的理由は?

正解(せいかい):カスタムTritonカーネル

UnslothはAttention、MLP、Cross-Entropy Lossなどの核心演算(かくしんえんざん)をTritonで記述(きじゅつ)したカスタムGPUカーネルに置(お)き換(か)えます。これらのカーネルはメモリアクセスパターンを最適化(さいてきか)し、不要(ふよう)な中間(ちゅうかん)テンソル生成(せいせい)を削減(さくげん)して、2倍高速(こうそく)な学習(がくしゅう)と60%のメモリ節約(せつやく)を達成(たっせい)します。

Q4. Gradient Checkpointingの原理とトレードオフは?

正解(せいかい):

原理(げんり): Forward passで中間(ちゅうかん)活性化値(かっせいかち)(activation)をメモリに保存(ほぞん)せず、Backward passで必要(ひつよう)な時(とき)に再計算(さいけいさん)します。

トレードオフ:

  • メリット:VRAM使用量(しようりょう)約(やく)30〜50%削減(さくげん)
  • デメリット:再計算(さいけいさん)により学習時間(がくしゅうじかん)約(やく)20〜30%増加(ぞうか)

Unslothのカスタムgradient checkpointingは標準(ひょうじゅん)PyTorch実装(じっそう)より効率的(こうりつてき)で、時間増加(じかんぞうか)が少(すく)ないです。

Q5. GGUF Q4_K_MとQ8_0の違いと、それぞれの推奨使用シナリオは?

正解(せいかい):

Q4_K_M(4-bit Mixed):

  • ファイルサイズ:原本(げんぽん)の約(やく)28%(8Bモデル基準(きじゅん)約(やく)4.5GB)
  • 品質(ひんしつ):原本(げんぽん)から若干(じゃっかん)の性能低下(せいのうていか)
  • 速度(そくど):高速(こうそく)
  • 推奨(すいしょう):日常使用(にちじょうしよう)、モバイル/エッジデプロイ、VRAM/RAM制限環境(せいげんかんきょう)

Q8_0(8-bit):

  • ファイルサイズ:原本(げんぽん)の約(やく)50%(8Bモデル基準(きじゅん)約(やく)8GB)
  • 品質(ひんしつ):原本(げんぽん)に非常(ひじょう)に近(ちか)い
  • 速度(そくど):Q4より低速(ていそく)
  • 推奨(すいしょう):品質最優先(ひんしつさいゆうせん)、十分(じゅうぶん)なメモリがある環境(かんきょう)、正確(せいかく)な推論(すいろん)が必要(ひつよう)なサービス

12. 参考資料(さんこうしりょう)

  1. LoRA: Low-Rank Adaptation of Large Language Models - Hu et al., 2021
  2. QLoRA: Efficient Finetuning of Quantized LLMs - Dettmers et al., 2023
  3. Unsloth Documentation - github.com/unslothai/unsloth
  4. PEFT: Parameter-Efficient Fine-Tuning - HuggingFace
  5. TRL: Transformer Reinforcement Learning - HuggingFace
  6. Flash Attention 2 - Dao et al., 2023
  7. LLM.int8(): 8-bit Matrix Multiplication - Dettmers et al., 2022
  8. llama.cpp - github.com/ggerganov/llama.cpp
  9. GPTQ: Accurate Post-Training Quantization - Frantar et al., 2022
  10. DeepSpeed ZeRO - Rajbhandari et al., 2020
  11. Direct Preference Optimization - Rafailov et al., 2023
  12. Scaling Data-Constrained Language Models - Muennighoff et al., 2023
  13. Training Compute-Optimal Large Language Models (Chinchilla) - Hoffmann et al., 2022
  14. The Llama 3 Herd of Models - Meta AI, 2024