llama.cpp LoRA scale比較の設計

CHATGPT / AIChatGPTなどの生成AIを活用して運営・記事制作・更新を行っています。制作方針

llama.cpp b9637のLoRAを対象に、base・prompt・samplingを固定してscaleと複数adapterを比較し、品質、load memory、batching、切替運用の適用範囲を評価する設計を解説します。

同一の固定条件からLoRA scaleだけを分岐させ、品質・memory・batchingを比較する範囲の図解

先に結論

LoRAのscale比較で意味があるのは、同じbase GGUF、同じadapter GGUF、同じprompt列、同じchat template、同じsamplingを固定し、scaleだけを変えた場合です。最初にadapterなし、0.5、1.0の3条件を独立runとして保存し、task品質、format遵守、拒否・誤答、latency、memoryを分けて評価します。

llama.cpp b9637のserverは複数adapterを事前loadし、globalまたはrequest単位でIDとscaleを切り替えられます。ただし、異なるLoRA構成のrequestは同じbatchへ入らないと公式文書が明記しています。切替の便利さだけで採用せず、adapter常駐memory、cacheへの影響、batch分断を実workloadで測る必要があります。本稿は机上調査と測定設計であり、benchmark結果や最適scaleは示しません。

確認日時: 2026年8月5日 05:30(Asia/Tokyo)
対象version: llama.cpp b9637、commit aedb2a5e9ca3d4064148bbb919e0ddc0c1b70ab3(2026年6月14日公開)
検証区分: 固定commitのserver README、release、変換scriptに基づく机上調査・測定計画です。model load、推論、VRAM/RSS、latency、品質採点は実施していません。
想定範囲: 単一llama-server、1つのbase GGUF、1〜2個の互換LoRA GGUF、local loopback接続。分散推論、LoRA学習、merge後weightとの性能比較は適用外

確認済み事実と本稿の設計判断

固定commitの公式文書から確認できる事実は次のとおりです。

  • —loraはLoRA adapterをscale 1.0で読み込む
  • —lora-scaled FNAME:SCALEで起動時scaleを指定できる
  • 複数adapterを読み込み、—lora-init-without-applyで初期scaleを0にできる
  • GET /lora-adaptersでID、path、scaleを取得できる
  • POST /lora-adaptersでglobal scaleを設定できる
  • request bodyのloraで、そのrequestだけのIDとscaleを指定できる
  • requestに含めなかったadapterのscaleは0として扱われる
  • 異なるLoRA構成のrequestはbatchingされず、性能が低下し得る

「adapterなし、0.5、1.0から始め、品質・memory・batchingを別々に判定する」のは本稿の測定設計です。0.5や1.0が特定taskの最適値だという公式保証ではありません。

再現性のために固定する条件

区分固定する値
softwarellama.cpp tag/commit、build option、compiler、backend、driver
base配布repository、revision、GGUF filename、SHA-256、quantization、chat template
adapter学習元base revision、adapter repository、GGUF SHA-256、rank/alpha、target module、変換script commit
runtimecontext、batch/ubatch、threads、GPU offload、Flash Attention、KV cache type
generationprompt bytes、system message、seed、temperature、top-k、top-p、生成上限、stop条件
workloadprompt集合、到着順、同時request数、scale構成ごとの比率
observationwarm-up、測定回数、clock、memory sample方法、timeoutと失敗の定義

同じ自然文に見えても、chat templateが違えばtoken列は変わります。比較用promptはraw fileとして保存し、可能なら/tokenizeのtoken IDも記録します。adapterの品質を評価する前に、base単独の出力とfailure rateをbaselineにします。

3条件をCLIで分ける

b9637固定の—lora-scaled構文はFNAME:SCALEです。現在のmasterとcommand表記が変わる可能性があるため、異なる版のhelpを混ぜません。

BASE_GGUF="/absolute/path/to/base-model.gguf"
ADAPTER_GGUF="/absolute/path/to/task-adapter.gguf"
PROMPT="固定した評価prompt"

# 条件A: adapterなし
./llama-cli -m "$BASE_GGUF" -p "$PROMPT" -n 256 --seed 42 --temp 0

# 条件B: scale 0.5
./llama-cli -m "$BASE_GGUF" --lora-scaled "$ADAPTER_GGUF:0.5" \
  -p "$PROMPT" -n 256 --seed 42 --temp 0

# 条件C: scale 1.0
./llama-cli -m "$BASE_GGUF" --lora "$ADAPTER_GGUF" \
  -p "$PROMPT" -n 256 --seed 42 --temp 0

上のcommandは比較軸を示すもので、実行結果は掲載していません。shellの終了code、stderr、resolved generation settingsをrunごとに保存し、途中でcontextやoffloadを変えません。

serverでrequest単位にscaleを切り替える

2つのadapterを初期scale 0でloadする例です。外部公開せずloopbackへbindします。

./llama-server \
  -m /absolute/path/to/base-model.gguf \
  --lora /absolute/path/to/adapter-a.gguf \
  --lora /absolute/path/to/adapter-b.gguf \
  --lora-init-without-apply \
  --host 127.0.0.1 \
  --port 8080

まずIDと初期scaleを取得します。

curl http://127.0.0.1:8080/lora-adapters

返されたIDを使い、request単位でscaleを指定します。次のidは例なので、実際の一覧へ合わせてください。

curl http://127.0.0.1:8080/completion \
  -H 'Content-Type: application/json' \
  -d '{
    "prompt": "固定した評価prompt",
    "n_predict": 256,
    "temperature": 0,
    "seed": 42,
    "lora": [{"id": 0, "scale": 0.5}]
  }'

adapter Bだけを使うrun、AとBを同時に使うrunは別条件です。requestで指定しなかったadapterはscale 0になります。globalなPOST /lora-adaptersとrequest単位指定を同じ測定区間で混ぜると、どのscaleが適用されたか追跡しにくくなるため、baselineではrequest単位へ統一します。

品質評価は事前のrubricで分ける

1つの好みの回答だけでscaleを選びません。adapterの目的に合わせ、少なくとも次を別scoreにします。

評価軸観測例採用を止める例
task達成必須項目の充足、正答、分類一致baseより誤答や欠落が増える
formatJSON schema、定型文、長さ制約parse error、余分なfield
保持能力adapter対象外の一般prompt一般能力の明確な悪化
safety拒否すべきprompt、個人情報不適切な追従、過剰拒否
安定性同一条件の反復、異なるseedcrash、空出力、極端なばらつき

採点者、正解dataset、license、個人情報の扱いも記録します。scaleを上げて対象taskが改善しても、対象外promptや安全性が悪化するなら、用途を限定するか採用しません。

memoryとload時間を分けて測る

adapterを非mergeで保持すると、base fileを用途ごとに複製せず切り替えられます。一方で、adapter weightは別にloadされるため、複数常駐時のmemoryが0になるわけではありません。次の時点を分けます。

  1. server起動前
  2. base load完了直後
  3. adapter A load後
  4. adapter B load後
  5. 最初のprefill中のpeak
  6. decode中のsteady state
  7. scale切替後の最初のrequest

CPU RSS、GPU allocated/reserved、load時間、first-token latencyを同じsampling方法で取ります。file sizeをそのままVRAM増加量と見なさず、backend、offload、mmap、temporary bufferを含む観測範囲を明記します。

batching分断をworkload比率で測る

公式文書は、LoRA構成が異なるrequestは同じbatchへ入らないと説明しています。したがって、単一requestのlatencyだけではproduction影響を判断できません。

最低限、次の4 workloadを分けます。

workload確認すること
全件adapterなしbaseだけのbatching baseline
全件adapter A、同じscale同一構成でまとめられる範囲
A 50%/B 50%adapter別queueとbatch分断
Aでscaleが複数同じadapterでも構成差がある場合の影響

request数、prompt長、生成長、到着間隔を揃え、completed request/s、TTFT p50/p95、inter-token latency、queue時間、batch sizeの実測値を保存します。throughput低下が見えたら、adapter別serverへ分離する案と、1 serverでmemoryを共有する案を同じhardware予算で比較します。

複数adapterを同時適用する判断

複数adapterを同時にscale指定できても、効果が単純加算される保証はありません。target moduleが重なる場合、順序やscaleの組み合わせで出力が変わり得ます。A単独、B単独、A+Bを別条件にし、単独で合格していないadapterを組み合わせません。

また、adapter Aがbase X、adapter Bがbase Yを学習元にしている場合、名前の似たbaseへ同時適用する根拠にはなりません。各adapterのbase_model_name_or_path、revision、tensor対応を確認し、load成功だけで互換性を判断しません。

適用外と失敗時の戻し方

load errorまたはcrash

複数adapterをすべて外してbase単独へ戻り、次にAだけ、Bだけの順で増やします。scale、context、offloadを同時に変えません。adapterの変換元と固定commitの変換scriptが違う場合は、元fileを残したまま別名で再変換します。

品質がscaleに対して単調に変わらない

正常です。scaleは「品質percent」ではありません。prompt群ごとのscore分布を確認し、対象taskと対象外taskの境界を決めます。最良の平均だけでなくworst caseとfailure countを採用条件へ入れます。

throughputが急に落ちる

LoRA構成別の同時request数と実際のbatch groupingを確認します。adapter切替そのもの、cache状態、batch分断を分けるため、同一構成だけのrunと混在runを比較します。改善しなければadapter別processへの分離を検討しますが、base重複memoryとのtrade-offを再測定します。

現行masterへ一般化する場合

b9637以後はCLI表記、server endpoint、default port、adapter実装が変わり得ます。この記事のcommandをそのままmasterへ流用せず、対象commitの—helpとserver READMEを再監査します。特に2026年8月にはserver既定portの将来変更予告が出ているため、接続先を暗黙値へ依存させません。

採用判断

LoRA非merge運用を採用する条件は、baseを共有できることだけではありません。固定prompt群で必要品質を満たし、adapter常駐後のmemoryが上限内で、実際のadapter比率でもbatch分断がSLOを壊さず、失敗時にscale 0またはbase単独へ戻せることです。

初めて1 adapterをloadする段階なら、llama.cppでLoRAを非merge適用する入門から進めてください。GGUF自体のload errorはGGUFが読み込めない原因と対処法へ切り分けます。

参考資料