
第7部 学習と微調整第13章
LoRA / QLoRA / Adapter
数十億の重みを全部書き換えなくても、モデルは新しいことを覚えられます。重みに小さな差分を足すLoRA、4bitの土台と組み合わせるQLoRA、Adapterやその仲間たち、そして学習したアダプタの結合や複数同時配信までを整理します。
このページの内容(11項目)
70億個の数字を、全部書き換えないといけないの?
手元の7Bモデルに、自社の問い合わせ対応の口調を覚えさせたいとします。素直にモデル全体を学習させると、学習用のメモリだけで100GBを超え、家庭用GPUではまず無理です。しかも出来上がるのは、元と同じ大きさのモデルがもう1つ。
ところがLoRAを使うと、学習するのは全体の1%にも満たない小さな部品だけ。保存するファイルも数十MB〜数百MB程度で済みます。この章では「元のモデルはそのまま、差分だけを学ぶ」という発想を、しくみから実際の配信まで追いかけます。
全部を学習するのは、なぜ重い?
モデル全体を更新する方法をフルファインチューニング(full fine-tuning)と呼びます。重いのは、重みそのものに加えて、学習には「勾配」と「オプティマイザの状態」が必要だからです。
大規模学習のメモリを分析したZeROの論文は、混合精度でAdamを使う場合、1パラメータあたり約16バイト(16bitの重み2・勾配2、オプティマイザが持つ32bitの重みのコピー・1次モーメント・2次モーメントで計12)が必要だと見積もっています。7Bモデルなら 70億 × 16 ≒ 112GB。ここに学習途中の値(活性化)の分が加わります。
ひとことで言うと
PEFT(Parameter-Efficient Fine-Tuning、パラメータ効率のよい微調整)は、元の重みを凍結し、ごく一部の追加パラメータだけを学習する方法の総称です。LoRAはその代表選手です。
LoRA:重みに「低ランクの差分」を足す
LoRA(Low-Rank Adaptation)は2021年にMicrosoftの研究者らが提案した方法です。モデルの中の大きな行列 W(たとえば 4096×4096)をそのまま凍結し、学習で生じる変化 ΔW を、細長い2つの行列の積 B×A で表します。
flowchart TD X["入力 x"] --> W["元の重み W
凍結・学習しない"] X --> A["A
r × 4096"] A --> B["B
4096 × r"] W --> S["足し合わせる"] B --> S S --> Y["出力 Wx + BAx"]
r はランク(rank)と呼ばれ、8〜64程度の小さな数にします。4096×4096の行列は約1,678万個の数字ですが、r=16なら A と B を合わせて 16×4096×2 ≒ 13万個。学習する量は約0.8%で済みます。
LoRAは、分厚い教科書(元の重み)に直接書き込むのではなく、付箋を貼っていくようなものです。教科書はきれいなまま、付箋をはがせば元に戻り、別の用途には別の付箋セットを用意できます。
論文では、GPT-3 175Bを例に、Adamでのフルファインチューニングと比べて学習するパラメータを1万分の1に、GPUメモリを3分の1に減らせたと報告しています。しかも品質は同等以上でした。さらに学習後は B×A を元の W に足し込めるので、推論が遅くならないのも大きな利点です。
lora_alpha ローラ・アルファ
差分 B×A をどれくらい強く効かせるかの係数。実際には alpha ÷ r を掛けて使います。r を変えるときに alpha も合わせて調整するのが一般的で、「alpha = r」や「alpha = 2r」がよく見かける出発点です。
target_modules ターゲットモジュール
LoRAを付ける場所。アテンションの q_proj・k_proj・v_proj・o_proj だけに付ける方法から、MLP(gate_proj・up_proj・down_proj)まで全部の線形層に付ける方法まであります。付ける場所が多いほど表現力は上がり、学習量も増えます。
QLoRA:土台を4bitに縮めてLoRAを学ぶ
LoRAで学習するパラメータは減っても、凍結した元の重みはGPUメモリに載せる必要があります。7Bモデルを16bitで持つと、それだけで約14GBです。そこで、土台の重みを4bitに量子化したまま凍結し、その上でLoRAを学習するのがQLoRA(2023年)です。
QLoRAの論文は、3つの工夫を紹介しています。
- NF4(4-bit NormalFloat): 正規分布に近い重みに合わせて目盛りを配置した4bit形式
- 二重量子化(double quantization): 量子化に使うスケール自体も量子化して、さらにメモリを削る
- ページドオプティマイザ(paged optimizers): メモリが一時的に足りなくなったとき、オプティマイザの状態をCPU側に逃がす
論文では、65Bパラメータのモデルを48GBのGPU 1枚で微調整でき、16bitでのフルファインチューニングと同等のタスク性能を保てたと報告しています。量子化そのものについては第10章を参照してください。
もう一歩深く: QLoRAの「代償」
QLoRAはメモリを大きく減らせますが、計算のたびに4bitの重みを16bitに戻すので、同じ条件のLoRAより学習は遅くなりがちです。メモリに余裕があるなら、16bitの土台でLoRAを学習するほうが速いこともあります。
メモリはどれくらい減る?
7Bモデルを例に、学習時に必要なメモリのうち「重み・勾配・オプティマイザ状態」の部分をざっくり比べてみます(学習途中の値=活性化は含みません)。
| 方式 | 土台の重み | 学習用の追加分 | 合計の目安 |
|---|---|---|---|
| フル(16bit+Adam) | すべて学習 | 勾配・状態すべて | 約112GB |
| LoRA(16bitの土台) | 約14GB(凍結) | LoRA部分だけ | 15GB前後〜 |
| QLoRA(4bitの土台) | 約4GB(凍結) | LoRA部分だけ | 5GB前後〜 |
LoRA部分は全体の1%未満なので、その勾配とオプティマイザ状態は数百MB程度に収まります。実際には活性化の分が文脈の長さやバッチの大きさに応じて加わるので、表の数字は「最低限これくらい」の目安と考えてください。活性化は、途中の値を保存せずに計算し直す勾配チェックポイント(gradient checkpointing)で減らせます。
Adapterとその仲間たち
「元の重みを凍結して小さな部品だけ学ぶ」という発想は、LoRAより前からありました。2019年のHoulsbyらの論文は、Transformerの各層の間に小さなネットワーク(Adapter)を差し込み、そこだけを学習する方法を提案しました。
| 方式 | 何を学習する? | 推論時の追加コスト |
|---|---|---|
| Adapter | 層の間に挟んだ小さなネットワーク | 挟んだ分だけ計算が増える |
| LoRA | 重みに足す低ランクの差分 | 結合すればゼロ |
| Prompt / Prefix tuning | 入力の前に付ける「学習可能なトークン」 | 文脈が少し長くなる |
| IA3 | 活性化に掛ける小さなベクトル | ごくわずか |
現在の言語モデルの微調整では、LoRA系がほぼ標準になっています。結合すれば推論コストが増えない点と、ツールの対応が厚い点が大きな理由です。なお、文脈によっては「アダプタ」がLoRAの重みファイルを指す一般名詞として使われることもあるので、どちらの意味か注意しましょう。
LoRAの派生:DoRA・rsLoRA・初期化の工夫
LoRAには多くの改良版があります。Hugging FaceのPEFTライブラリは、2026年10月時点で数十種類の手法を収録しています。よく見かけるものを挙げます。
DoRA Weight-Decomposed Low-Rank Adaptation
2024年にNVIDIAの研究者らが提案。重みを「大きさ(magnitude)」と「向き(direction)」に分け、向きの更新にLoRAを使います。論文ではLLaMAなどでLoRAより一貫して良い結果を報告しています。PEFTでは use_dora=True で使えますが、LoRAより計算の上乗せが大きいので、推論前に重みを結合することが推奨されています。
- rsLoRA: 係数を alpha ÷ r ではなく alpha ÷ √r にする工夫。ランクを大きくしたときの学習を安定させる(PEFTでは
use_rslora=True)。 - PiSSA・OLoRA・EVAなどの初期化: A と B の初期値を、元の重みの特異値分解やデータから決めて、収束を速める。
- LoftQ: QLoRA向けの初期化。量子化で生じた誤差を打ち消すようにLoRAの初期値を決める。
- LoRA+: A と B で学習率を変えると効率が上がる、という提案。
まずは素のLoRAで始め、うまくいかないときに試すくらいの位置づけで十分です。なお2024年の論文「LoRA Learns Less and Forgets Less」は、LoRAはフルファインチューニングほど新しいことを学ばない一方、元の能力も忘れにくいと報告しています。どちらを選ぶかは「何を優先するか」次第です。
学習したLoRAの使い方:結合とマージ
学習が終わると、手元にはBaseモデルと、小さなアダプタのファイル(PEFTなら adapter_model.safetensors と adapter_config.json)が残ります。使い方は大きく2通りです。
- そのまま載せる: Baseモデルを読み込み、その上にアダプタを載せて使う。差し替えや取り外しが自由。
- 結合する(merge): B×A を元の重みに足し込み、普通のモデルとして保存する。PEFTの
merge_and_unload()がこれにあたり、推論時の遅延がなくなる。GGUFに変換して配りたいときもこの形にすることが多い。
注意: 量子化したモデルへの結合
QLoRAで学習したアダプタを4bitの土台にそのまま足し込むと、誤差が生じます。PEFTのドキュメントも、量子化モデルでの結合・解除は厳密ではないと注意しています。16bitの土台を読み込んで結合し、そのあとで改めて量子化するのが安全です。
さらに、別々に学習した複数のアダプタを1つに合成することもできます。PEFTの add_weighted_adapter は、重み付きの足し算(linear)のほか、TIES や DARE といったモデルマージの手法を選べます。TIESは「符号がぶつかる更新を整理してから足す」、DAREは「差分の一部をランダムに捨てて残りを拡大してから足す」工夫です。
「敬語の付箋」と「法律用語の付箋」を1枚にまとめるイメージです。ただし、まとめた結果が両方の良さを保つとは限りません。必ず評価してから使いましょう(評価は第30章)。
たくさんのLoRAを1台で配る
アダプタが小さいことは、配信でも大きな武器になります。顧客ごと・用途ごとにLoRAを用意しても、Baseモデルは1つをGPUに載せておけば済むからです。
flowchart TD R1["リクエスト
model=営業用"] --> S["推論サーバー"] R2["リクエスト
model=法務用"] --> S R3["リクエスト
Baseのまま"] --> S S --> M["共通のBaseモデル
GPUに1つ"] S --> L["小さなLoRA群
必要な分だけ載せ替え"]
- vLLM:
--enable-loraで起動し、--lora-modules 名前=パスでアダプタを登録。リクエストのmodel欄でアダプタを選べ、Baseモデルへのリクエストと混ぜて処理できます。同時に扱う数はmax_loras、最大ランクはmax_lora_rankで指定します。 - llama.cpp(llama-server):
--loraでGGUF形式のアダプタを複数読み込み、リクエストごとにlora欄で強さ(scale)を指定できます。ただしLoRAの設定が違うリクエストどうしはまとめて処理(バッチ化)されないため、性能が落ちることがあると説明されています。
研究では、2023年の「S-LoRA」が、アダプタをCPUメモリに置いて必要なものだけGPUに載せる工夫などで、数千個のLoRAを同時に配信できることを示しました。vLLMとサーバー型ランタイムについては第9章も参照してください。
はじめてのLoRA:設定の目安
| 設定 | よくある出発点 | メモ |
|---|---|---|
| r(ランク) | 8〜32 | 大きいほど表現力と学習量が増える |
| lora_alpha | r と同じか2倍 | r を変えたら一緒に見直す |
| target_modules | 全線形層 | メモリが厳しければアテンションのみ |
| 学習率 | 1e-4 前後 | フルファインチューニングより高めにする |
数字はあくまで目安です。TRLのドキュメントも、アダプタの学習では新しいパラメータだけを学ぶため、1e-4程度の高めの学習率を使うのが一般的だとしています。データの質と量のほうが結果に効くことが多いので、まずは小さなデータで試し、評価しながら調整しましょう。ツールの選び方は第14章で扱います。
よくある誤解
LoRAを使うと推論が遅くなる
結合(merge)すれば元のモデルと同じ速さです。載せたまま使う場合も、多くの実装でオーバーヘッドは小さく抑えられています
LoRAのファイルだけ配れば、誰でもそのまま使える
アダプタは特定のBaseモデル専用の差分です。同じBaseモデル(同じバージョン)と組み合わせないと意味をなしません
QLoRAで作ったモデルは4bit精度でしか使えない
学習したアダプタ自体は16bitです。16bitの土台に結合して使うことも、あとで別の形式に量子化することもできます
確認クイズ
Q2. QLoRAの「Q」は何を量子化している?
凍結した土台(Baseモデル)の重みです。NF4という4bit形式で持ち、学習するLoRA部分は16bitのままです。
Q4. 100社分のLoRAを1台のGPUサーバーで配りたい。なぜ現実的なの?
Baseモデルは1つを共有し、小さなアダプタだけを切り替えればよいからです。vLLMの --enable-lora や llama.cpp の --lora など、複数アダプタを扱う仕組みが用意されています。
この章のまとめ
- フルファインチューニングは重み・勾配・オプティマイザ状態で1パラメータ約16バイトかかり重い
- LoRAは元の重みを凍結し、低ランクの差分 B×A だけを学ぶ。結合すれば推論コストは増えない
- QLoRAは土台を4bit(NF4)にしてLoRAを学ぶ。メモリは大きく減るが、学習は遅くなりがち
- AdapterやDoRA・rsLoRA・PiSSAなど派生は多いが、まずは素のLoRAから
- アダプタは結合・合成(TIES・DARE)ができ、Baseを共有して複数LoRAを同時配信できる
さらに深く学ぶ
この章の内容をもう一歩掘り下げるための原典です。
- LoRA: Low-Rank Adaptation of Large Language Models元の重みを固定し、小さな低ランク行列だけを学習するLoRAを提案。微調整を一気に身近にした論文です。
- QLoRA: Efficient Finetuning of Quantized LLMs4bit(NF4)に量子化したモデルの上でLoRAを学習するQLoRAを提案。大きなモデルを1枚のGPUで微調整できるようにしました。
- Parameter-Efficient Transfer Learning for NLPTransformerの層の間に小さな「アダプター」を差し込んで学習する手法。省パラメータ微調整(PEFT)の原点の一つです。
- LoRA Learns Less and Forgets LessLoRAはフル微調整より新しい知識の習得が少ない一方、元の能力も忘れにくいことを示した実証研究。LoRAに何を期待すべきかが分かります。
出典・参考
- Hu ほか「LoRA: Low-Rank Adaptation of Large Language Models」(arXiv:2106.09685) — 学習パラメータ1万分の1、GPUメモリ3分の1
- Dettmers ほか「QLoRA: Efficient Finetuning of Quantized LLMs」(arXiv:2305.14314) — NF4・二重量子化・ページドオプティマイザ、65Bを48GB GPU 1枚で
- Rajbhandari ほか「ZeRO: Memory Optimizations Toward Training Trillion Parameter Models」(arXiv:1910.02054) — 混合精度Adamで1パラメータ16バイトの見積もり
- Houlsby ほか「Parameter-Efficient Transfer Learning for NLP」(Adapter、arXiv:1902.00751)
- Liu ほか「DoRA: Weight-Decomposed Low-Rank Adaptation」(arXiv:2402.09353)
- Biderman ほか「LoRA Learns Less and Forgets Less」(arXiv:2405.09673)、「LoRA+」(arXiv:2402.12354)、「PiSSA」(arXiv:2404.02948)
- PEFT ドキュメント「LoRA」 — 初期化オプション、use_dora、use_rslora、merge_and_unload、add_weighted_adapter(2026年10月時点で確認)
- Yadav ほか「TIES-Merging」(arXiv:2306.01708)、Yu ほか「Language Models are Super Mario」(DARE、arXiv:2311.03099)
- vLLM ドキュメント「LoRA Adapters」 — --enable-lora、--lora-modules、max_loras
- llama.cpp server README — --lora、リクエストごとのlora指定
- Sheng ほか「S-LoRA: Serving Thousands of Concurrent LoRA Adapters」(arXiv:2311.03285)
- TRL ドキュメント「SFT Trainer」 — アダプタ学習での学習率の目安