1s.xyz / LLM周辺用語 教科書 13 / 25

第13章. LoRA / QLoRA / Adapter

この章の目的

大規模言語モデル(LLM)の微調整(Fine-tuning)において、効率的な学習を実現するための主要な技術であるLoRA、QLoRA、そしてAdapterについて深く理解することを目的とします。これらの技術は、限られた計算資源でLLMを特定のタスクやデータセットに適応させるために不可欠です。

この章で覚えるべきこと

  • LoRAの基本的な仕組みと、なぜそれが効率的なのか。
  • QLoRAがLoRAをどのように進化させ、さらにメモリ効率を高めているか。
  • Adapterの概念とLoRAとの関係性。
  • mergeranktarget modulesといった関連用語の意味。
  • LoRA、QLoRA、そして他の学習手法や量子化手法との違い。

導入

大規模言語モデル(LLM)は、その名の通り膨大なパラメータを持つため、一から学習させたり、既存のモデル全体を微調整(Full Fine-tuning)したりするには、莫大な計算資源と時間が必要です。しかし、特定のタスクやドメインにモデルを適応させたい場合、毎回ゼロから学習するのは現実的ではありません。

そこで登場するのが、Parameter-Efficient Fine-tuning (PEFT) と呼ばれる技術群です。PEFTは、モデルの全パラメータを更新するのではなく、ごく一部のパラメータのみを学習することで、計算コストとメモリ使用量を大幅に削減しつつ、高い性能を維持することを目指します。本章で扱うLoRA、QLoRA、Adapterは、このPEFTの代表的な手法であり、今日のLLM微調整において最も広く利用されています。

これらの技術を理解することは、限られたリソースでLLMをカスタマイズし、実用的なアプリケーションを開発するために不可欠です。

基本概念

LoRA (Low-Rank Adaptation)

ひとことで言うと: 大規模モデルの全パラメータを更新する代わりに、ごく少数の追加パラメータ(アダプター)を学習することで、効率的にモデルを微調整する手法。 何のカテゴリか: Parameter-Efficient Fine-tuning (PEFT) 手法の一つ。 何に使うのか: 大規模言語モデルを特定のタスクやデータセットに効率的に適応させる。 代表例: Stable DiffusionやLLaMAなどのモデルの微調整。 よく混同される用語: full fine-tuning, continued pretraining, fine-tuning 初心者向け注意点: LoRAはモデルの「重み」そのものを変更するのではなく、既存の重みに行列の「差分」を適用するイメージです。学習するのはこの差分部分だけです。

LoRAは、既存の事前学習済みモデルの重み行列 $W_0 \in \mathbb{R}^{d \times k}$ に対して、低ランク分解された2つの小さな行列 $A \in \mathbb{R}^{d \times r}$ と $B \in \mathbb{R}^{r \times k}$ を導入し、その積 $BA$ を元の重み行列に加算することで微調整を行います。ここで、$r$ は「ランク(rank)」と呼ばれ、$d, k$ に比べて非常に小さい値(通常は数〜数十)が設定されます。

$$ W = W_0 + BA $$ この式は、元の重み行列 $W_0$ に、低ランク行列 $B$ と $A$ の積 $BA$ を加算することで、新しい重み行列 $W$ を生成することを示しています。学習時には $W_0$ は固定され、$A$ と $B$ のみが更新されます。

学習時には、$W_0$ は固定され、$A$ と $B$ のパラメータのみが更新されます。これにより、学習対象のパラメータ数を $d \times k$ から $d \times r + r \times k$ に大幅に削減できます。例えば、$d=k=1024$、 $r=8$ の場合、元のパラメータ数は約100万ですが、LoRAでは約1万6千となり、約1/60に削減されます。

rank

ひとことで言うと: LoRAにおいて、追加する低ランク行列の次元数を決定するハイパーパラメータ。 何のカテゴリか: LoRAのハイパーパラメータ。 何に使うのか: LoRAアダプターの表現能力とパラメータ数を調整する。 代表例: LoRAの学習設定で r=8r=16 などと指定する。 よく混同される用語: なし 初心者向け注意点: rankの値が大きいほど表現能力は高まりますが、学習パラメータ数とメモリ使用量も増加します。小さすぎるとモデルの性能が十分に向上しない可能性があります。

target modules

ひとことで言うと: LoRAを適用する対象となる、モデル内の特定の層(モジュール)。 何のカテゴリか: LoRAの学習設定。 何に使うのか: LoRAを適用する層を限定することで、学習効率を高め、不要な層への変更を避ける。 代表例: LLMのAttention層(例: q_proj, k_proj, v_proj, o_proj)やFeed-forward層。 よく混同される用語: なし 初心者向け注意点: どのモジュールにLoRAを適用するかは、モデルのアーキテクチャとタスクによって最適なものが異なります。一般的には、Attention層の線形変換層が効果的とされています。

QLoRA (Quantized LoRA)

ひとことで言うと: LoRAをさらに進化させ、事前学習済みモデルの重みを4ビット量子化することで、メモリ使用量を劇的に削減しつつ、LoRAによる微調整を可能にする手法。 何のカテゴリか: Parameter-Efficient Fine-tuning (PEFT) 手法の一つ、かつ量子化技術の応用。 何に使うのか: 非常に大きなLLMを、限られたGPUメモリ(例: 8GBや12GBのGPU)で微調整する。 代表例: LLaMA 2 70Bのような巨大モデルを、消費者向けGPUで微調整する。 よく混同される用語: GGUF quantization 初心者向け注意点: QLoRAは、元のモデルを量子化してメモリを節約しつつ、LoRAアダプターは通常の精度で学習します。これにより、量子化されたモデルでも高い性能を維持できます。

QLoRAは、LoRAの効率性をさらに一歩進めます。具体的には、以下の技術を組み合わせることで、メモリ使用量を大幅に削減します。

  1. 4-bit NormalFloat (NF4) 量子化: 事前学習済みモデルの重みを4ビット精度に量子化します。これは、従来の浮動小数点数よりもはるかに少ないメモリでモデルを表現できることを意味します。
  2. 二重量子化 (Double Quantization): 量子化定数(量子化のスケールを決定する値)自体も量子化することで、さらにわずかながらメモリを節約します。
  3. Paged Optimizers: GPUメモリが不足した場合に、CPUメモリに一時的にデータを退避させることで、大規模なモデルでも安定して学習できるようにします。

これらの技術により、例えば65Bパラメータのモデルを、わずか48GBのGPUメモリで微調整することが可能になります。学習時には、4ビット量子化された重みを動的に逆量子化(dequantize)して計算に使用し、勾配はLoRAアダプターにのみ適用されます。

Adapter

ひとことで言うと: 事前学習済みモデルの各層に、タスク固有の小さなニューラルネットワーク(アダプターモジュール)を挿入し、そのアダプターのみを学習させることでモデルを微調整する手法。 何のカテゴリか: Parameter-Efficient Fine-tuning (PEFT) 手法の一つ。 何に使うのか: 複数のタスクに対応するモデルを効率的に作成する。 代表例: BERTなどのTransformerモデルの微調整。 よく混同される用語: LoRA 初心者向け注意点: AdapterはLoRAよりも歴史が古く、LoRAはAdapterの一種と見なされることもあります。LoRAはAdapterの特定の形式(低ランク分解)を採用することで、より効率的な学習を実現しています。

Adapterは、Transformerモデルの各層(例えば、Attention層やFeed-forward層の間)に、小さなボトルネック構造を持つニューラルネットワークを挿入します。このアダプターモジュールは、入力次元を一度小さな次元に圧縮し、その後元の次元に戻すという構造を持ちます。

$$ x \rightarrow W_{down} \rightarrow \text{ReLU} \rightarrow W_{up} \rightarrow x' $$ この式は、Adapterモジュールの内部構造を示しています。入力 $x$ がまずダウンサンプリング行列 $W_{down}$ で次元削減され、ReLU活性化関数を適用した後、アップサンプリング行列 $W_{up}$ で元の次元に戻され、出力 $x'$ を生成します。

学習時には、事前学習済みモデルの重みは固定され、このアダプターモジュール内のパラメータのみが更新されます。これにより、タスクごとに異なるアダプターを学習し、必要に応じて切り替えることで、複数のタスクに対応するモデルを効率的に管理できます。

merge

ひとことで言うと: LoRAアダプターの重みを、元の事前学習済みモデルの重みに統合(結合)する操作。 何のカテゴリか: LoRAの運用フェーズにおける操作。 何に使うのか: LoRAアダプターを適用せずに、微調整済みモデルとして単体で推論できるようにする。 代表例: 学習済みのLoRAアダプターとベースモデルを結合して、新しいモデルファイル(例: safetensors)を作成する。 よく混同される用語: なし 初心者向け注意点: merge されたモデルは、LoRAアダプターなしで推論できるため、デプロイが容易になります。ただし、一度マージすると、LoRAアダプターの分離はできません。

LoRAで学習されたアダプターは、通常、元のモデルとは別のファイルとして保存されます。推論時には、ベースモデルとLoRAアダプターの両方をロードし、推論時に動的にLoRAの重みを適用する必要があります。merge 操作は、このLoRAアダプターの重み $BA$ を、元のモデルの重み $W_0$ に直接加算し、$W = W_0 + BA$ という新しい重み $W$ を持つモデルを作成します。

これにより、LoRAアダプターを別途管理する必要がなくなり、通常のモデルと同様に推論エンジンにロードして使用できるようになります。これは、特にモデルをデプロイする際に非常に便利です。

具体例

LoRAによる微調整のワークフロー

以下は、Hugging Faceのpeftライブラリとtransformersライブラリを使ったLoRA微調整の一般的な流れです。

  1. ベースモデルとトークナイザのロード:

    from transformers import AutoModelForCausalLM, AutoTokenizer
    model_name = "mistralai/Mistral-7B-v0.1"
    model = AutoModelForCausalLM.from_pretrained(model_name)
    tokenizer = AutoTokenizer.from_pretrained(model_name)
  2. LoRA設定の定義: ranktarget_modules を指定します。

    from peft import LoraConfig, get_peft_model
    
    lora_config = LoraConfig(
        r=8,  # rank
        lora_alpha=16, # LoRAのスケールファクター
        target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], # target modules
        lora_dropout=0.05,
        bias="none",
        task_type="CAUSAL_LM",
    )
  3. PEFTモデルの作成: ベースモデルにLoRAアダプターを適用します。

    model = get_peft_model(model, lora_config)
    model.print_trainable_parameters()
    # 出力例: trainable params: 4,194,304 || all params: 7,247,433,728 || trainable%: 0.05787265814524491

    この出力から、学習対象のパラメータが全体の0.05%程度であることがわかります。

  4. データセットの準備と学習: (データセットの準備コードは省略) Trainer を使って学習を実行します。

  5. LoRAアダプターの保存:

    model.save_pretrained("my_lora_adapter")

    これにより、my_lora_adapter ディレクトリにLoRAアダプターの重み(例: adapter_model.safetensors)と設定ファイルが保存されます。

  6. LoRAアダプターのロードとマージ:

    from peft import PeftModel, PeftConfig
    
    # ベースモデルを再度ロード
    base_model = AutoModelForCausalLM.from_pretrained(model_name)
    
    # LoRAアダプターをロード
    peft_model = PeftModel.from_pretrained(base_model, "my_lora_adapter")
    
    # マージ
    merged_model = peft_model.merge_and_unload()
    
    # マージされたモデルを保存
    merged_model.save_pretrained("my_merged_model")
    tokenizer.save_pretrained("my_merged_model")

    これで、my_merged_model ディレクトリには、LoRAアダプターが適用された単一のモデルが保存されます。

QLoRAによる微調整のワークフロー

QLoRAは、LoRAの学習設定に加えて、モデルの量子化設定を追加します。

  1. ベースモデルとトークナイザのロード(量子化設定付き):

    from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
    import torch
    
    model_name = "mistralai/Mistral-7B-v0.1"
    
    # 4ビット量子化設定
    bnb_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_quant_type="nf4", # 4-bit NormalFloat
        bnb_4bit_compute_dtype=torch.bfloat16, # 計算時のデータ型
        bnb_4bit_use_double_quant=True, # 二重量子化
    )
    
    model = AutoModelForCausalLM.from_pretrained(
        model_name,
        quantization_config=bnb_config,
        device_map="auto"
    )
    tokenizer = AutoTokenizer.from_pretrained(model_name)

    load_in_4bit=Truequantization_config を指定することで、モデルが4ビット量子化されてロードされます。

  2. LoRA設定の定義とPEFTモデルの作成: LoRAの設定自体はLoRAの場合と同じですが、量子化されたモデルに適用されます。

    from peft import LoraConfig, get_peft_model
    
    lora_config = LoraConfig(
        r=8,
        lora_alpha=16,
        target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
        lora_dropout=0.05,
        bias="none",
        task_type="CAUSAL_LM",
    )
    
    model = get_peft_model(model, lora_config)
    model.print_trainable_parameters()
    # 出力例: trainable params: 4,194,304 || all params: 7,247,433,728 || trainable%: 0.05787265814524491

    学習対象のパラメータ数はLoRAと同じですが、ベースモデルのメモリ使用量が大幅に削減されています。

  3. データセットの準備と学習: (データセットの準備コードは省略) Trainer を使って学習を実行します。この際、量子化されたモデルでの学習をサポートするために、bitsandbytesライブラリのAdamW8bitなどのオプティマイザを使用することが推奨されます。

  4. LoRAアダプターの保存とマージ: LoRAの場合と同様に、アダプターを保存し、必要であればマージします。マージされたモデルは、元の4ビット量子化されたベースモデルとLoRAアダプターが結合されたものになります。

よく混同される用語との比較

LoRA vs full fine-tuning

特徴 LoRA Full Fine-tuning
学習パラメータ数 非常に少ない(全体の0.1%以下) 全てのパラメータ
メモリ使用量 少ない 非常に多い
計算コスト 少ない 非常に多い
学習時間 短い 長い
保存ファイルサイズ アダプターのみ(小さい) モデル全体(大きい)
性能 多くのタスクでFull Fine-tuningに匹敵 最も高い性能を達成する可能性
柔軟性 複数のタスクアダプターを容易に切り替え タスクごとにモデル全体を保存・ロードが必要
適用シナリオ 限られたリソースでの微調整、タスク特化 最高の性能を追求、ドメイン適応

LoRA vs continued pretraining

特徴 LoRA (Fine-tuning) Continued Pretraining (継続事前学習)
目的 特定のタスクやデータセットへの適応 新しいドメインや知識の獲得、モデルの汎化能力向上
データ タスク固有の少量のデータ(指示データなど) 大規模なドメイン固有のデータセット
学習パラメータ LoRAアダプターのみ モデル全体(または大部分)
学習率 比較的高い 比較的低い
エポック数 少ない(数エポック) 多い(数十〜数百エポック)
出力 特定タスクに特化したモデル 新しいドメイン知識を持つ汎用モデル
計算コスト 少ない 多い

QLoRA vs GGUF quantization

特徴 QLoRA GGUF Quantization
目的 微調整時のメモリ削減と効率化 推論時のメモリ削減と高速化
学習の可否 可能(LoRAアダプターを学習) 不可能(推論専用の形式)
量子化対象 ベースモデルの重み(4ビットNF4など) モデル全体の重み(2, 3, 4, 5, 6, 8ビットなど)
量子化手法 4-bit NormalFloat (NF4) k-quant (GGML/GGUF独自の量子化)
推論ランタイム Hugging Face transformers + bitsandbytes llama.cpp、Ollama、LM Studioなど
メモリ使用量 微調整時に大幅削減 推論時に大幅削減
性能 微調整後も高い性能を維持 量子化レベルに応じて性能劣化の可能性あり
ファイル形式 safetensors (ベースモデル) + safetensors (LoRAアダプター) .gguf
利用シーン 限られたGPUでLLMを微調整したい場合 CPUや低スペックGPUでLLMを推論したい場合

実務での位置づけ

LoRAとQLoRAは、今日のLLM開発において、特定のタスクやドメインにモデルを適応させるためのデファクトスタンダードとも言える技術です。

  • 研究開発: 新しいタスクやデータセットでのLLMの性能評価において、効率的な微調整手法として利用されます。
  • 企業での利用: 企業固有のデータ(社内文書、顧客対応ログなど)を用いてLLMをカスタマイズし、業務効率化や顧客サービス向上に役立てる際に不可欠です。特に、機密性の高いデータをクラウドにアップロードできない場合でも、オンプレミス環境の限られたGPUリソースで微調整を行うことが可能になります。
  • 個人開発者: 消費者向けGPU(例: RTX 3090, RTX 4090)でも、数兆パラメータを持つモデルを微調整できるようになり、LLMのカスタマイズがより身近なものになりました。
  • モデルの配布: LoRAアダプターは非常にファイルサイズが小さいため、ベースモデルを共有しつつ、タスク固有のアダプターのみを配布することで、モデルの共有と管理が容易になります。

これらの技術は、LLMの「民主化」を大きく推進し、より多くの人々がLLMをカスタマイズして活用できる道を拓きました。

関係性図 (Mermaid)

graph TD
    A[事前学習済みLLM] --> B{PEFT手法}
    B --> C[LoRA]
    C --> D[QLoRA]
    B --> E[Adapter]
    C --> F[学習済みLoRAアダプター]
    F --> G[ベースモデルにマージ]
    G --> H[微調整済みモデル]
    D --> I[4ビット量子化ベースモデル]
    I --> F
    subgraph "LoRAの内部構造"
            J
            W0
            J
            K
            L
            M
            N
    end
    subgraph "QLoRAの主要技術"
            P
            W0
            Q
            R
            S
    end

まとめ

3行まとめ

  1. LoRAは、大規模モデルの全パラメータではなく、ごく少数の追加パラメータ(低ランク行列)のみを学習することで、効率的に微調整を行うPEFT手法です。
  2. QLoRAは、LoRAに4ビット量子化を組み合わせることで、ベースモデルのメモリ使用量を劇的に削減し、限られたGPUメモリでの微調整を可能にします。
  3. Adapterは、モデルの各層に小さなモジュールを挿入して学習するPEFT手法で、LoRAはその一種であり、特に効率的な低ランク分解を利用します。

混同しやすい用語

  • LoRA vs Full Fine-tuning: LoRAは一部のパラメータのみを学習し、メモリ効率が高い。Full Fine-tuningは全パラメータを学習し、最高の性能を目指すがコストが高い。
  • LoRA vs Continued Pretraining: LoRAはタスク特化の微調整、Continued Pretrainingはドメイン知識獲得のための汎用モデル学習。
  • QLoRA vs GGUF Quantization: QLoRAは微調整時のメモリ削減、GGUF Quantizationは推論時のメモリ削減と高速化が主な目的。

次に読むべき章

  • 第14章: プロンプトエンジニアリングの基礎
  • 第15章: RAG (Retrieval-Augmented Generation)
  • 第16章: エージェントとツール利用