llama.cppでLoRAを非merge適用する入門

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

llama.cpp b9637で対応するGGUF LoRA adapterをbase modelへ非mergeで読み込み、同じpromptでadapterなし・ありを確認する最短手順と失敗時の戻し方を解説します。

Baseを変えずにLoRAを重ね、同じpromptで適用前後を確認して用途を切り替える流れの図解

先に結論

llama.cppでは、base modelのGGUFを書き換えず、別fileのLoRA(Low-Rank Adaptation)adapterを--loraで重ねて推論できます。最初は1つのadapterをscale 1.0で読み込み、adapterなしと同じpromptを各1回実行して、両方がerrorなく完了することを確認します。

重要なのは、任意のbaseとadapterを組み合わせられるわけではない点です。adapterが学習された元base、architecture、対象tensor、tokenizerが対応している必要があります。本稿はllama.cpp b9637/commit aedb2a5e9ca3d4064148bbb919e0ddc0c1b70ab3へ固定した机上手順で、model取得、推論品質、速度、memoryは実機未検証です。

確認日時: 2026年8月5日 05:30(Asia/Tokyo)
固定した版: llama.cpp b9637、commit aedb2a5e9ca3d4064148bbb919e0ddc0c1b70ab3(2026年6月14日公開)
想定環境: b9637のllama-cliまたはllama-server、互換するbase GGUFとLoRA adapter GGUF、2 fileを置けるdiskと推論に必要なmemory
検証区分: 固定commitのserver文書、release、変換scriptを照合した机上調査です。binary build、GGUF変換、model load、生成結果は未検証です。
対象外: LoRA学習、adapterのmerge、特定adapterの品質保証、第三者modelのlicense判定

LoRA adapterを重ねると何が変わるか

LoRAは、base model全体を作り直す代わりに、学習で得た小さな追加weightを別fileとして扱う方法です。llama.cppの公式文書では、LoRA adapterをGGUF形式で読み込み、base modelとは別に推論へ適用します。したがって、用途ごとに巨大なbase GGUFを複製せず、adapterを外せば元のbase経路へ戻せます。

ただし「fileが小さい」と「安全に互換する」は別です。少なくとも配布元のmodel cardやadapter_config.jsonで次を確認してください。

  1. adapterのbase_model_name_or_pathが、用意したbaseと一致する
  2. LoRA変換時に参照したbase configが同じrevisionである
  3. adapterとbaseのlicense、用途制限、再配布条件を別々に確認した
  4. 入力を第三者serverへ送らずlocal fileだけで試す構成になっている

量子化されたbase GGUFへadapterを重ねる場合も、adapterの学習元baseまで別物にしてよいわけではありません。似た名前や同じparameter数だけで判断せず、repositoryとrevisionを記録します。

始める前のfile確認

この記事では、すでに次の2 fileがある前提にします。実在pathへ置き換えてください。

/absolute/path/to/base-model.gguf
/absolute/path/to/task-adapter.gguf

Hugging Face PEFT形式のadapterしかない場合、固定commitにはconvert_lora_to_gguf.pyがあります。scriptはadapter directory内のadapter_config.jsonadapter_model.safetensorsまたはadapter_model.binを読み、base configを—base—base-model-id、またはadapter設定から解決します。変換にはPython依存packageが必要なため、入門手順では新しいsoftwareを自動installせず、公式scriptの—helpと固定commitのrequirementsを先に確認します。

file名だけでなくhashも保存すると、後日の再現に役立ちます。

shasum -a 256 /absolute/path/to/base-model.gguf
shasum -a 256 /absolute/path/to/task-adapter.gguf

この出力値は各自のfileで異なります。本稿では架空のhashを例示しません。

最短手順:適用なしとありを分けて実行する

1. base modelだけで起動する

まずadapterを指定せず、baseが単独で読めることを確認します。

BASE_GGUF="/absolute/path/to/base-model.gguf"
PROMPT="次の依頼へ簡潔に答えてください。ローカル推論の確認項目を3つ挙げてください。"

./llama-cli \
  -m "$BASE_GGUF" \
  -p "$PROMPT" \
  -n 128 \
  --seed 42 \
  --temp 0

成功確認は「期待した文章になったか」より先に、processがmodel load errorなく起動し、生成を終えて終了code 0になったかで行います。出力本文はmodel、chat template、build、backendで変わるため、本稿では正解例を作りません。

2. 同じbaseへadapterを重ねる

次に、promptと生成条件を変えず—loraだけを追加します。

BASE_GGUF="/absolute/path/to/base-model.gguf"
ADAPTER_GGUF="/absolute/path/to/task-adapter.gguf"
PROMPT="次の依頼へ簡潔に答えてください。ローカル推論の確認項目を3つ挙げてください。"

./llama-cli \
  -m "$BASE_GGUF" \
  --lora "$ADAPTER_GGUF" \
  -p "$PROMPT" \
  -n 128 \
  --seed 42 \
  --temp 0

公式CLIでは—loraのscaleは1.0です。最初から複数adapterや極端なscaleへ進まず、1 fileでloadできることを先に確定します。

3. 比較結果を保存する

確認表には、少なくとも次を残します。

項目adapterなしadapterあり
llama.cppb9637/commit aedb2a5…同じ
base GGUF hash同じ値同じ値
prompt bytes同じ同じ
seed/temperature/生成上限42/0/128同じ
load完了記録記録
process終了code記録記録
出力の評価後で同じ基準で採点後で同じ基準で採点

1回の見た目だけで「品質が上がった」と断定しません。まずloadと生成経路が分かれたことを確認し、品質評価は複数promptと事前に決めた採点基準で別に行います。

llama-serverでadapter状態を確認する

固定版server文書では、起動時に—loraでadapterを読み込み、GET /lora-adaptersでID、path、scaleを確認できます。

./llama-server \
  -m /absolute/path/to/base-model.gguf \
  --lora /absolute/path/to/task-adapter.gguf \
  --host 127.0.0.1 \
  --port 8080

別terminalからlocal endpointを確認します。

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

成功時はhealthがreadyになり、adapter一覧に読み込んだfileが現れることを確認します。server APIへ認証を追加した検証ではないため、127.0.0.1の外へ公開しません。

つまずきやすい点と戻し方

adapterのloadでtensor不一致になる

最初に—loraを外し、base単独が読めるかへ戻ります。単独で成功するなら、adapterの学習元base、revision、target module、変換時のbase configを確認します。別adapterを無作為に重ねてerrorを隠しません。

GGUFではないadapterを渡している

adapter_model.safetensorsをそのまま—loraへ渡す手順ではありません。固定commitのconvert_lora_to_gguf.pyで変換対象とbase configを確認するか、配布元が提供する互換GGUFを使います。変換後も元fileを残し、出所とhashを記録します。

出力差が見えない

load成功と品質差は別問題です。adapterが対象とするtaskに合うpromptか、scaleが1.0か、同じchat templateかを確認します。serverでrequestごとのlora指定を使う場合、指定されなかったadapterのscaleは0になるため、request JSONも保存します。

memory不足になる

最後に足したadapterを外してbaseへ戻し、base load直後とadapter追加後のmemoryを別々に観測します。context、GPU offload、batch、他processを同時に変えると原因が分からなくなります。model規模の見積もりはローカルLLMのVRAM計算方法も参照してください。

scaleと複数adapterへ進む前に

最初の1 adapterが再現できたら、—lora-scaledやserverのrequest単位指定でscaleを比較できます。ただし、scaleが大きいほど品質が高いとは限りません。異なるLoRA構成のrequestは同じbatchへまとめられず性能へ影響し得るため、比較条件と運用設計が必要です。

詳しい固定条件、複数adapter、request単位のscale、memoryとbatchingの観測方法は、llama.cpp LoRA scale比較の設計で扱います。

参考資料