Gradience: LoRAアダプタのランクが本当に必要か、スペクトル監査で測定するツール
Gradienceとは
Gradienceは、LoRAファインチューニング後のアダプタ重み行列をスペクトル分析(特異値分解)して、割り当てたランクのうち実際にどれだけ使われているかを測定するツール。Apache 2.0ライセンス。
LoRAでrank=64を指定しても、訓練後の重み行列を分解してみると有効な次元が15しかないことがある。残りの49次元はノイズの記憶に使われている可能性がある。Gradienceはこれを数値で可視化する。
何を測っているのか
Gradienceは訓練中のロスカーブや学習速度ではなく、訓練済みアダプタの重み行列を事後分析する。測定メトリクスは主に3つ。
安定ランク(Stable Rank)
行列の「有効次元数」。特異値のエネルギー分布から、実質的に何次元が使われているかを算出する。
stable_rank(M) = ||M||²_F / ||M||²₂ = (Σσᵢ²) / σ₁²
エネルギーランク(k@90%)
行列エネルギーの90%をカバーするのに必要な特異値の数。「ここまで残せば情報の9割は保持できる」という圧縮ターゲットになる。
使用率(Utilization)
utilization = stable_rank / allocated_rank
割り当てたランクに対する実際の使用率。0.3なら7割が無駄ということになり、圧縮候補。
Mistral-7B + GSM8Kでの実験結果
元記事ではMistral-7BをGSM8K(数学問題)でファインチューニングした実験を行っている。
まずrank=64でプローブ訓練(1200ステップ)を行い、Gradienceで監査。「rank=32で十分」という提案を受けて、複数の圧縮変種を3シードで再訓練・評価した結果:
| 変種 | 平均精度 | 圧縮率 |
|---|---|---|
| probe (r=64) | 28.7% | — |
| uniform_median (r=32) | 28.8% | 50% |
| uniform_p90 (r=32) | 33.7% | 50% |
| per_layer | 31.8% | ~3% |
rank 64のプローブより、rank 32に絞ったuniform_p90が平均+5ポイント高精度。ランクを削ることが正則化として機能し、ノイズフィッティングを防いだという結論。
提案の仕組み
監査から出てくるランク提案は2種類:
- median提案: 全レイヤーの安定ランクの中央値
- p90提案: 90パーセンタイル(大半のレイヤーをカバーするマージン付き)
実験ではmedianは攻めすぎで、p90の方が安定して良い結果を出した。
使い方
pip install gradience
gradience audit --peft-dir ./your-adapter
HuggingFace Trainerへのコールバック統合もできる。
from gradience import GradienceCallback
trainer = Trainer(
model=model,
args=training_args,
callbacks=[GradienceCallback()]
)
画像LoRAに使えるか?
ここが気になるポイントだが、現時点では不明。
Gradienceの実験はテキストLLM(Mistral + 数学タスク)で行われており、Stable DiffusionやFlux向けの画像LoRAでの検証はない。また、ツール自体がHuggingFace PEFT形式を前提としているため、kohya_ss等で生成したsafetensors形式のアダプタにそのまま使えるかも未確認。
ただ、LoRAの重み行列に対する特異値分解という手法自体はモダリティに依存しないので、技術的には応用可能なはず。画像LoRAで「rank 128で回してるけど実は32で足りてた」みたいな知見が得られたら面白い。
画像LoRAの「学習データに似たものが出ない」問題は、ランク以外にも学習率、ステップ数、キャプションの質、正則化画像の有無など要因が多いので、Gradienceだけで解決する銀の弾丸にはならない。ただ、試行錯誤の中で「ランクは足りてる/足りてない」を一つ潰せるツールとして使える可能性はある。