llama.cpp投機的decode入門

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

llama.cpp b10328を基準に、追加model不要のn-gram方式をbaselineから有効化し、応答完了、draft token、acceptanceを確認して元へ戻す最短手順を説明します。

先読みしたtoken候補をtarget modelが検証し、採用分だけ応答へ進める基本の流れ

先に結論

llama.cppの投機的decodeは、軽い方法で複数tokenを先読みし、target modelがまとめて検証して、採用できたtokenだけを応答へ進める仕組みです。最初は別のdraft modelを用意せず、過去のtoken列から繰り返しを探すngram-modを試します。--spec-type noneのbaselineを先に保存し、同じGGUF、prompt、samplingで応答完了とdraft/accepted tokenを確認してください。acceptanceが出ても総時間が短くなる保証はないため、「有効になった」と「速くなった」は分けて判断します。

確認日時: 2026年8月12日(Asia/Tokyo)
対象version: llama.cpp b10328、commit dd2c7c4(2026年8月8日release)と、同commitのllama-server公式README。投機的decode文書は2026年8月12日の公式masterを併せて確認。
検証区分: 公式文書に基づく机上調査・再現手順です。この制作環境ではGGUF推論、速度測定、GPU/CPU別の互換性確認を実行していません。
適用外: targetとdraft modelの組み合わせ、EAGLE-3/MTP/DFlash/DSparkの専用checkpoint、複数requestでの性能、全backendの最適値。

始める前に仕組みを分ける

投機的decodeでは、最終的なtokenを決めるmodelをtarget model、先読み候補を作る側をdraftと呼びます。draftが候補を複数作り、targetが一括で検証します。候補がtargetの判断と一致した分だけ進めるため、draftの誤りをそのまま最終出力へ採用する仕組みではありません。

llama.cpp b10328のllama-serverには、別modelを使うdraft-simple、target専用のcheckpointを使うEAGLE-3やMTP系、追加modelなしのn-gram系など複数方式があります。初回にn-gramを選ぶ理由は、target/draftのarchitectureやtokenizer互換性を確認する作業を増やさず、現在のGGUFだけで制御経路を試せるからです。

n-gramは過去のtoken列に同じpatternが現れたとき、その後に続いたtokenを候補にします。codeの繰り返し、既存文書をなぞる編集、要約などでは候補を作りやすい一方、短い会話や毎回新しい表現ではdraft tokenがほとんど出ない場合があります。公式文書も、ngram-modのhash poolがserver slot間で共有されることを説明しています。初回検証は他userと共有しないlocal serverで行います。

すでに推論自体が遅い、またはGGUFが読み込めない場合は、先にllama.cppが遅い原因と高速化設定でbaselineのbackendとmemoryを直します。引数の意味だけを探す場合はllama.cpp主要パラメータ一覧と役割を分けて参照してください。

baselineを先に保存する

既存serverを直接置き換えず、b10328を別directoryへ用意し、手元の絶対pathへ置き換えます。次のcommandは読者側で実行する例で、制作環境では実行していません。

LLAMA_SERVER="/absolute/path/to/b10328/build/bin/llama-server"
TARGET_GGUF="/absolute/path/to/target-model.gguf"

"$LLAMA_SERVER" --version
"$LLAMA_SERVER" --help | grep -- '--spec-type'

versionにcommit dd2c7c4が出ることと、helpに—spec-typeがあることを確認します。予定したbuildと違う場合は進めず、binaryのpathを直します。model hashも保存します。

shasum -a 256 "$TARGET_GGUF"

まず投機なしで起動します。

"$LLAMA_SERVER" \
  -m "$TARGET_GGUF" \
  --host 127.0.0.1 \
  --port 8080 \
  --spec-type none \
  --metrics

別terminalから、繰り返しを含む自分の検証用textを同じrequestへ入れます。ここでは内容を固定するため、fileからJSON文字列へ変換します。

PROMPT_FILE="/absolute/path/to/repetitive-test.txt"

jq -n --rawfile prompt "$PROMPT_FILE" '{
  prompt: $prompt,
  n_predict: 128,
  temperature: 0,
  stream: false
}' > request.json

curl --fail-with-body http://127.0.0.1:8080/completion \
  -H 'Content-Type: application/json' \
  --data-binary @request.json > baseline.json

baseline.jsonに応答本文、生成token数、timingsがあり、serverがerrorなく完了したことを確認します。この時点では速さの良し悪しを決めず、比較できる正常系を作るのが目的です。

n-gram方式を有効にする

baseline serverをCtrl+Cで停止し、同じbinary、GGUF、port、request条件のままngram-modだけを追加します。

"$LLAMA_SERVER" \
  -m "$TARGET_GGUF" \
  --host 127.0.0.1 \
  --port 8080 \
  --spec-type ngram-mod \
  --spec-ngram-mod-n-match 24 \
  --spec-ngram-mod-n-min 48 \
  --spec-ngram-mod-n-max 64 \
  --metrics

この値はb10328の公式helpに載る既定値を明示したものです。最初から調整せず、「方式だけを変えた比較」にします。先ほどと同じrequestを送ります。

curl --fail-with-body http://127.0.0.1:8080/completion \
  -H 'Content-Type: application/json' \
  --data-binary @request.json > ngram.json

curl --fail-with-body http://127.0.0.1:8080/metrics > ngram-metrics.txt

成功確認は次の順です。

  1. ngram.jsonがerrorで終わらず、必要な応答を返している。
  2. server logにspeculative decodingの統計が出る。
  3. metricsのllamacpp:spec_decode_num_draft_tokens_totalが0より大きい。
  4. llamacpp:spec_decode_num_accepted_tokens_totalがdraft token以下である。
  5. baselineと生成条件が同じで、用途上必要な出力を保っている。

promptに繰り返しが少ないとdraft tokenが0のままでも、起動失敗とは限りません。検証用textの中に同じcode blockや定型句が複数回現れることを確認します。結果を都合よくするために本番promptを改変するのではなく、n-gramが向くworkloadかを見極めます。

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

optionがunknownになる

古いbinaryや別directoryのbinaryを実行している可能性があります。—versionと絶対pathを確認します。旧—draft—draft-nはb10328のhelpで削除済みとされ、—spec-draft-n-maxまたは方式別の—spec-ngram-*へ分かれています。古い記事の引数を混ぜません。

acceptanceが0、またはdraftが作られない

n-gramは履歴内のpattern一致が必要です。短い質問、創作、毎回異なる内容では候補が作られないことがあります。長く繰り返しのある検証textでも0なら、serverを再起動して他requestの共有poolを消し、対象fileとrequest内容を確認します。draft長やmatch長を一度に変えないでください。

acceptanceが高いのに速くならない

acceptanceは候補の当たりやすさで、draft作成、target検証、sampling、queueを含む総時間ではありません。baselineとngram.jsonのtimings、client側の開始から完了まで、同じ生成token数を比べます。数回だけの最速値では採用せず、詳しい比較は投機的decodeの性能検証設計で条件を固定します。

元へ戻す

serverを停止し、—spec-type noneでbaseline commandを再実行します。専用modelを追加していないため、n-gram初回検証のrollbackは起動optionを戻すだけです。production設定を編集した場合は、保存した旧configへ戻し、同じbaseline requestが完了することまで確認します。

まとめ

投機的decodeの最初の成功は、「速くなった」という結論ではなく、baselineと同じ条件で先読み候補が作られ、targetが検証し、応答が完了した状態です。b10328では—spec-type noneを基準に、追加model不要のngram-modを一項目だけ追加できます。draft token、accepted token、総時間を分けて保存し、効果がないworkloadでは迷わずnoneへ戻してください。

さらに深く理解する

同じテーマの玄人向け検証記事で、n-gram、draft model、EAGLE-3/MTPを比較するときの固定条件、acceptanceと総時間のtrade-off、適用外を確認できます。

参考資料