LoRA(Low-Rank Adaptation、低ランク適応)は、事前学習済みモデルの重みを固定し、各層に加える更新差分だけを小さな行列で学習するPEFT(Parameter-Efficient Fine-Tuning、少数パラメータだけを更新する追加学習)手法です。学習対象、勾配、optimizer state、タスク別checkpointを小さくできる一方、ベースモデルの読み込みやactivation(順伝播の中間値)は残ります。LoRAを正しく使うには、rankだけでなく、どのmoduleへ挿入するか、更新のscaleをどう決めるか、何を保存・評価するかまで設計する必要があります。
3文要約

- LoRAは元の重み \(W_0\) を圧縮するのではなく、更新差分 \(\Delta W\) を \(BA\) という低ランク積で表します。
- \(d\times k\) 行列の更新対象は、rankを \(r\) とすると \(dk\) 個から \(r(d+k)\) 個へ減りますが、ベース重みとactivationのメモリは消えません。
- 実運用では、rank、alpha、target modules、学習率、保存するbase revision、merge方法、生成品質の評価を一つの設計として扱います。
LoRAは「何を変え、何を変えない」のか
LoRA原論文は、追加学習で必要な重み更新には低いintrinsic rank(本質的な次元)があるという仮説に基づきます。巨大な重み行列全体を書き換える代わりに、更新を二つの細い行列へ分解します。

重要なのは、低ランクにする対象がベースモデルの重みそのものではなく、追加する更新差分だという点です。元の知識を保持したベースモデルはそのまま読み込み、横に小さな学習経路を足します。
| 項目 | LoRAでの扱い | 実務上の意味 |
|---|---|---|
| 事前学習済み重み \(W_0\) | 凍結 | gradientとoptimizer stateを持たない |
| 更新差分 \(\Delta W\) | \(BA\) として学習 | 保存・切替対象を小さくできる |
| forward | \(W_0x\) とadapter出力を加算 | 未mergeなら追加演算がある |
| activation | 通常どおり保持 | sequence length由来のメモリは残る |
| 学習目的 | LoRA自体は規定しない | SFT、Instruction Tuning、DPOなどと組み合わせる |
LoRAは「何を更新するか」を制限する方法であり、「どのlossで学ぶか」を決める方法ではありません。教師ありデータでSFTする場合も、選好pairでDPOする場合も、更新対象としてLoRAを選べます。
更新式を行列の形から理解する
入力 \(x\in\mathbb{R}^{k}\) を重み \(W_0\in\mathbb{R}^{d\times k}\) へ通す線形層を考えます。Full Fine-tuningでは \(W_0\) 自体を更新しますが、LoRAでは \(W_0\) を凍結して次の出力を計算します。
ここで、二つの学習行列の形は次のとおりです。
したがって、\(A\) は入力を \(k\) 次元からrank \(r\) の小さな空間へ写し、\(B\) はそれを出力側の \(d\) 次元へ戻します。積の形は次になります。
元の重みと同じ形なので、更新差分として加算できます。\(s\) はscaling(更新量を調整する係数)で、原論文の標準形では \(s=\alpha/r\) です。

計算順序としては、巨大な \(BA\) を毎回明示的に作る必要はありません。未mergeの学習中は \(x\) を \(A\)、次に \(B\) へ通し、その結果へscaleを掛けて \(W_0x\) に足します。この構造によって、学習対象を小さく保てます。
パラメータ数はrankと行列形状から計算する
Full Fine-tuningで一つの \(d\times k\) 行列を更新すると、学習対象は \(dk\) 個です。LoRAの学習対象は \(A\) と \(B\) なので、次の数になります。
削減率は次の式で見積もれます。
4096×4096、rank 8の例
元の行列が4096×4096なら、Full Fine-tuningの更新対象は16,777,216個です。rank 8では次のようになります。
一行列に限れば、元行列の約0.39%です。
| 更新方法 | 一行列の学習パラメータ | 元行列比 |
|---|---|---|
| Full Fine-tuning | 16,777,216 | 100% |
| LoRA rank 8 | 65,536 | 約0.39% |
| LoRA rank 64 | 524,288 | 約3.13% |

ただし「LoRAなら常に全モデルの0.39%」ではありません。Transformer blockのqueryとvalueだけへ入れる場合と、attentionの全projectionやMLPまで含める場合では、対象行列の個数と形が変わります。全体のtrainable parameterは、対象moduleごとに \(r(d+k)\) を足して求めます。
例えば同じ4096×4096行列へrank 8のLoRAを32層、各層2個ずつ入れる単純化した例では、次の計算になります。
このように、rankだけでなく「何層の何行列へ入れたか」を記録しないと、adapterの規模を再現できません。
初期化時にベースモデルの出力を変えない仕組み
LoRAでは、学習開始時に \(BA=0\) となるよう一方の行列をゼロ初期化します。原論文では \(A\) をrandom Gaussian、\(B\) をゼロで初期化します。これによりstep 0では次が成立します。
したがって、LoRAを挿入した直後の出力はベースモデルと一致します。ランダムなadapter出力で、学習前からモデルの挙動を壊すのを避けられます。
ここには、最初のbackwardで起きる非対称性があります。\(B=0\) なら、最初は \(B\) には勾配が流れますが、\(A\) の勾配は0になります。\(B\) が更新されて0でなくなると、次のstep以降は両方が学習されます。

| 時点 | \(A\) | \(B\) | adapter出力 | 主な勾配 |
|---|---|---|---|---|
| 初期化直後 | random | 0 | 0 | まず \(B\) に流れる |
| 数step後 | 更新対象 | 0ではない | 0ではない | \(A\)、\(B\) の両方 |
現在のlibraryには複数の初期化方式があります。初期化名を変えた場合は「LoRA一般の性質」と思い込まず、その方式がstep 0でno-op(出力を変えない状態)か、追加のデータ依存処理を必要とするかを公式文書で確認します。
rankとalphaは何を調整しているのか
rank \(r\) は、更新 \(\Delta W\) が表現できる部分空間の上限を決めます。rankを増やすほど複雑な更新を表現できますが、パラメータ、gradient、optimizer state、保存容量、計算量もほぼ線形に増えます。
alpha \(\alpha\) はadapter出力のscaleを調整します。元のLoRAでは次の係数を使います。
このため、rankだけを変えてalphaを固定すると、係数 \(\alpha/r\) も変わります。rank、alpha、learning rateは別々の名前を持ちますが、実際の更新量へ相互に影響します。
Rank-Stabilized LoRAの論文は、高rankでのscale挙動を改善するため、次の形を提案しています。
これは元のLoRAと同じ規則ではなく、rsLoRAという派生設定です。利用しているlibraryのoptionを有効にした場合だけ適用されます。

| 設定 | 大きくしたとき | 注意点 |
|---|---|---|
| rank \(r\) | 表現できる更新方向が増える | メモリと保存量も増える。高いほど必ず高品質ではない |
| alpha \(\alpha\) | 他条件が同じならadapterのscaleが増える | learning rateと合わせて検証する |
| dropout | adapter経路の過学習を抑える可能性 | 強すぎると学習不足になる |
| target modules | 適応できる場所が広がる | 対象数に応じてコストが増える |
最適値はモデル、dataset、loss、対象moduleで変わります。「rank 8が標準だから固定する」のではなく、小さな候補集合でvalidation lossと生成品質を比較します。
どのmoduleへLoRAを入れるか
Transformerには、attentionのquery、key、value、output projectionと、MLPのgate、up、down projectionなど複数の大きな線形層があります。LoRA原論文の実験ではattentionの重みを対象とし、多くの設定でqueryとvalueを用いました。ただし、これはすべてのモデル・タスクでの唯一の正解ではありません。

| 対象 | 長所 | トレードオフ |
|---|---|---|
| query・value中心 | 学習対象が小さく、原論文に近い比較を作りやすい | MLP側の適応力は増えない |
| attention全projection | attention全体へ変更を入れられる | adapter数と計算が増える |
| attention+MLP | 広い表現を適応できる | memory、保存量、過学習リスクが増える |
| all-linear指定 | architecture差を吸収しやすい実装もある | 出力headなど意図しない層を含まないか確認が必要 |
Hugging Face PEFTのLoRA設定には、target_modules、exclude_modules、modules_to_save、層ごとのrankやalpha指定などがあります。層名はモデル実装ごとに異なるため、文字列を設定しただけで安心せず、次を確認します。
- LoRAが挿入されたmodule名
- trainable parameter数と全parameterに占める比率
- 各adapter parameterに勾配が存在するか
- 出力headやembeddingも更新したい場合、保存対象に含まれるか
対象名が一致せずLoRAが一つも挿入されない事故と、広すぎる指定で意図しない層まで学習する事故は、どちらも起こり得ます。
LoRAで減るメモリと減らないメモリ
「学習パラメータが1%未満なら、必要VRAMも1%未満になる」という理解は誤りです。学習時メモリは複数の内訳に分かれます。

| メモリ要素 | LoRAでの変化 | 理由 |
|---|---|---|
| ベース重み | 原則残る | forwardに全層が必要 |
| LoRA重み | 追加されるが小さい | \(r(d+k)\) 個 |
| gradient | 大幅に減る | 凍結重みには通常保持しない |
| optimizer state | 大幅に減る | 学習対象parameter分だけ持つ |
| activation | 基本的に残る | adapterへgradientを流すためforward中間値が必要 |
| attention一時領域 | 基本的に残る | sequence lengthやkernelに依存 |
LoRAが特に効くのは、全parameterのgradientとAdam系optimizerのmomentを持たずに済む部分です。一方、長いcontextでactivationやattentionが支配的なら、rankを下げるだけではOut Of Memoryを解消できないことがあります。その場合は、micro batch、gradient accumulation、gradient checkpointing、sequence length、attention実装、量子化を別軸で検討します。
LoRA原論文はGPT-3 175Bの特定設定で、trainable parameterを最大10,000分の1、GPU memoryを約3分の1に減らしたと報告しています。これはその実験条件の結果であり、任意のモデルで同じ倍率になる保証ではありません。
一つのbatchが通る処理
LoRAを使った学習も、dataset、tokenization、loss、optimizerという基本構造は通常のFine-tuningと同じです。違うのは、backward後に更新されるparameterの集合です。
- 入力をtokenizeし、batchを作る。
- 各対象層で \(W_0x\) と \((\alpha/r)BAx\) を足す。
- SFTやDPOなど、選んだ目的関数でlossを計算する。
- backwardでLoRA行列や明示した追加moduleへ勾配を流す。
- optimizerが学習対象parameterだけを更新する。
- validationではadapterを有効にした生成も評価する。
凍結したベース重みへgradientを保存しないことと、入力までのgradient経路が不要になることは同じではありません。LoRAの \(A\)、\(B\) を更新するには、その入力activationを使って勾配を計算します。
実装前に固定する設定
再現可能なLoRA学習では、parameter数だけでなく次の設定を保存します。
| 分類 | 記録する項目 | なぜ必要か |
|---|---|---|
| ベース | model ID、revision、dtype | 同名modelでも重みが変わり得る |
| tokenizer | revision、special tokens、chat template | 入力列とlabel位置が変わる |
| adapter | rank、alpha、dropout、初期化 | 更新容量とscaleが変わる |
| 挿入先 | target/exclude modules、対象層 | parameter数と適応範囲が変わる |
| 追加学習 | bias、modules to save | adapter外に更新対象があるか決まる |
| optimization | learning rate、scheduler、batch、step数 | 学習の軌跡が変わる |
| data | dataset revision、split、最大長 | 比較可能性とleak防止に必要 |
設定後は、学習開始前にtrainable parameterを列挙し、期待値と照合します。例えば出力headを追加学習したのにadapterだけを保存すると、再読み込み後にその更新が失われます。逆にbiasまで学習した場合は、adapterを無効にしても元のベース出力と完全には一致しないことがあります。
最小の確認項目
- trainable parameterが0でない
- 対象moduleの名前と個数が想定どおり
- 全parameterに対するtrainable比率が計算と一致
- step 0で初期化方式どおりの出力になる
- 一つのbatchでLoRA parameterに有限なgradientが入る
- save後に別processでloadし、同じ入力のlogitsを比較できる
adapterを保存・読み込むときの落とし穴
adapter fileは単独で完全なモデルではありません。少なくとも、対応するベースモデル、LoRA設定、必要なら追加保存moduleと組み合わせて初めて同じ挙動を再現できます。

運用単位として、次をひとまとめに管理します。
- adapterの重みと設定
- base modelの正確なIDとrevision
- tokenizer、special token、chat template
- 学習時のprompt形式
- libraryと主要dependencyのversion
- 評価結果と想定用途
base revisionやtokenizerが違うと、shape errorで即座に失敗する場合だけでなく、読み込めても出力品質が変わる場合があります。adapterが小さいことと、互換性管理が不要なことは同じではありません。
複数adapterを一つのbaseへ切り替えて使う構成は、LoRAの大きな運用上の利点です。ただし同時適用や線形合成は、それぞれを単独評価した結果をそのまま保証しません。更新方向が干渉する可能性があるため、合成後を別モデルとして評価します。
mergeすると何が起きるか
古典的なLoRAでは、推論前に次の重みを計算できます。
これを通常の線形層として保存すれば、推論時にadapter経路を別計算する必要がなくなります。原論文が述べる「追加の推論latencyなし」は、このように重みへmergeできる構成を指します。
ただし、merge前に次を確認します。
| 条件 | 注意点 |
|---|---|
| 浮動小数点base | merge前後の誤差許容値を決め、logitsと生成を比較する |
| 量子化base | dequantize、加算、再量子化で丸め誤差やmemory増加が起き得る |
| 複数adapter | 適用順とweightを記録し、合成品質を再評価する |
| 運用で切替が必要 | mergeするとadapter単独切替の利点が薄れる |
| 配布 | base modelのlicenseと配布条件も確認する |
merge済みmodelだけを残すと、元adapterへの分離や別baseへの差し替えが難しくなります。少なくとも検証が終わるまでは、元のbase指定とadapter artifactを保持します。
よくある失敗と切り分け方
lossがほとんど変わらない
まずtrainable parameter数、対象module、gradient normを確認します。target名の不一致、全parameterのfreeze、label maskの誤り、学習率が小さすぎる問題を、rank不足より先に切り分けます。
train lossだけ急速に下がる
datasetが小さい、重複が多い、rankや対象moduleが大きすぎる、学習stepが長すぎる可能性があります。prompt単位の重複除去とvalidation分割を確認し、生成例を固定して過学習を追います。
adapterを再読み込みすると品質が変わる
base revision、tokenizer、chat template、dtype、adapterの有効状態、追加保存moduleを比較します。train modeとeval modeでdropoutの状態が違うことも確認します。
merge後に出力が一致しない
scale、dtype、transposeの規約、fan-in/fan-out形式、量子化の有無を確認します。完全なbit一致を前提にせず、数値誤差の許容範囲と生成品質の両方で判定します。
rankを上げたのに良くならない
rankは容量の上限であり、データ品質や目的関数を改善しません。target modules、学習率、data coverage、validation設計がボトルネックなら、高rankはparameterと過学習リスクだけを増やします。
Full Fine-tuning・LoRA・QLoRAの使い分け
QLoRAはLoRAと別のlossではありません。QLoRA論文が示すのは、凍結したbase weightを主に4-bitで保持し、その重みを使った計算を通じてLoRA adapterを学習する構成です。
| 比較軸 | Full Fine-tuning | LoRA | QLoRA |
|---|---|---|---|
| base weight | 更新 | 凍結、通常は浮動小数点 | 凍結、主に4-bit保存 |
| 学習対象 | 原則全parameter | LoRA adapter | LoRA adapter |
| gradient・optimizer | 大きい | 小さい | 小さい |
| base weight memory | 大きい | 残る | 量子化で小さくする |
| activation memory | 残る | 残る | 残る |
| 表現力 | 制約が最も少ない | rankと対象層に制約 | LoRA制約と量子化影響を評価 |
| 推論運用 | model全体を配布 | adapter切替やmerge | 量子化対応runtimeとmerge条件を確認 |
選択の目安は次のとおりです。
- 最大限の更新自由度が必要で、計算資源とmodel全体の保存を許容できるならFull Fine-tuning
- base modelは載るがoptimizer stateまで含めたFull FTが重いならLoRA
- base model自体を通常精度で載せるのが難しいならQLoRA
QLoRAのNF4、Double Quantization、Paged Optimizerは次の記事で詳しく扱います。LoRAの記事では「baseの保存精度」と「学習対象」を混同しないことが重要です。
評価はadapterのlossだけで終わらせない
LoRAの学習が成功したかは、train lossだけでは判断できません。少なくとも次の層に分けます。
- 実装検証: 対象module、trainable数、gradient、save/load、merge前後を確認する。
- 学習診断: train/validation loss、gradient norm、過学習、長さ別性能を追う。
- タスク評価: 未見promptで正解率、形式遵守、品質rubricを測る。
- 回帰評価: ベースモデルが持っていた一般能力、安全性、多言語性能の低下を測る。
- 運用評価: latency、throughput、VRAM、adapter切替、再現性を確認する。
比較では、base、LoRA候補、必要ならFull FTやQLoRAを、同じvalidation splitと生成設定で評価します。rankやtargetを変えた実験ではtrainable parameter数も併記し、品質改善がコスト増に見合うか判断します。
| 実験軸 | 最小候補 | 見る指標 |
|---|---|---|
| rank | 小・中・大 | 品質、過学習、adapter size |
| target modules | q/v、attention全体、attention+MLP | 品質とtrainable数 |
| alpha | alpha/rが異なる複数候補 | update norm、収束、生成品質 |
| learning rate | 低・中・高 | loss、発散、回帰 |
| merge | 未merge・merge | logits差、生成、latency |
実装・公開前チェックリスト
- [ ] LoRAが低ランク化するのは更新差分であると説明できる
- [ ] 行列形状からtrainable parameter数を計算した
- [ ] rank、alpha、scaling規則をセットで記録した
- [ ] target modulesと実際の挿入先を照合した
- [ ] base modelとactivationを含むmemory内訳を見積もった
- [ ] base revision、tokenizer、chat templateを固定した
- [ ] adapter外に学習したmoduleも保存した
- [ ] save/load後の出力を別processで検証した
- [ ] merge前後と量子化時の差を評価した
- [ ] validationと回帰評価をtrain lossから分けた
まとめ
LoRAは、巨大な重み行列を直接更新せず、更新差分を \(BA\) という低ランク積で学習する手法です。これにより、gradient、optimizer state、タスク別checkpointを大幅に小さくできます。
一方で、ベース重み、activation、attentionの一時メモリは残ります。実際の性能とコストは、rankだけでなく、alpha、scaling、target modules、dataset、loss、学習率によって決まります。
LoRAを「小さいadapterを付けるだけ」と考えず、更新範囲、memory内訳、保存互換性、merge、評価まで含む設計として扱うと、学習できたのに再現できない、VRAMが想定ほど減らない、rankを上げても品質が伸びないといった失敗を避けやすくなります。
次に読むべき記事
次回はQLoRAを扱います。凍結したbase modelを4-bitで保持しながらLoRAを学習する仕組みを、NF4、Double Quantization、Paged Optimizerに分けて説明します。



コメント