世界を動かす技術を、日本語で。

Show HN: KVSplit – Apple Siliconで2-3倍長いコンテキストを実行する

2025年5月17日原文(github.com)

概要

  • KVSplit はApple Silicon向けに開発された、Attention機構の KVキャッシュ に異なる量子化精度を適用するツールです。
  • メモリ使用量を最大72%削減 し、品質低下を最小限に抑えつつ、より長いコンテキストや大型LLMをMacで実行可能。
  • K8V4(8bitキー/4bit値) 構成が最良のバランスを実現し、 推論速度も向上 する場合が多いです。
  • Metal完全対応 でApple Siliconのパフォーマンスを最大化。
  • 簡単なインストール と包括的なベンチマーク・可視化ツールを提供。

Apple Silicon向けKVSplit:差別化KVキャッシュ量子化によるLLM推論の最適化

KVSplitとは

  • Attentionの キー(key)と値(value)独立した量子化精度 を適用することで、 メモリ効率と品質維持 を両立する技術提案。
  • Apple Silicon (M1/M2/M3)に最適化されており、Metalサポートを活用すること。
  • llama.cpp をパッチ適用し、--kvq-key/--kvq-valフラグで 個別ビット幅 を指定可能に拡張すること。
  • ベンチマークスイート と可視化ツールを同梱し、効果を定量的に確認すること。

主な特徴・メリット

  • メモリ使用量削減 :最大72%削減(K4V4構成)、K8V4で59%削減+品質劣化0.86%のみ確認。
  • 長いコンテキストウィンドウ :同じメモリ予算で2〜3倍長い文脈長を実現すること。
  • 推論速度向上 :K8V4やK4V8構成で最大8%高速化を確認すること。
  • 品質維持 :キーのビット幅が品質に大きく影響し、値は低ビット幅でも品質劣化が小さいことを実証。
  • Metal最適化 :Apple SiliconのMetalフレームワークをフル活用し、効率的な推論を実現すること。

ベンチマーク結果(8Kトークン時)

| 構成 | VRAM使用量 | メモリ削減率 | 推論速度 (tokens/sec) | 品質劣化 (Perplexity) | |----------|------------|--------------|----------------------|-----------------------| | FP16 | 176MB | — | 54,360 | — | | K8V8 | 93.5MB | 47% | 51,503 | +0.03% | | K8V4 | 71.5MB | 59% | 57,438 | +0.86% | | K4V8 | 71.5MB | 59% | 58,690 | +6.06% | | K4V4 | 49.5MB | 72% | 55,193 | +6.15% |

  • K8V4 が最良のバランス(メモリ59%削減、品質劣化0.86%、速度+5.7%)。
  • K4V8 は同じビット数でも品質劣化が7倍大きいことを確認(キー精度の重要性を示唆)。

メモリ削減のスケーリング

  • シーケンス長が伸びるほど KVキャッシュのメモリ削減効果が増大 すること。
  • 例:FP16で32Kトークン→約1.4GB、K8V4で約400MBに圧縮可能。

インストール・セットアップ

  • 前提条件 :macOS (Apple Silicon), Homebrew, Xcode Command Line Tools
  • リポジトリクローン
    git clone https://github.com/dipampaul17/KVSplit.git
    cd kvsplit
    chmod +x scripts/install_kvsplit.sh
    ./scripts/install_kvsplit.sh
    
  • Python環境 (仮想環境orシステムPythonを選択可能)、 llama.cpp のMetal対応ビルド自動化、 テストモデルの自動ダウンロード、可視化ツールのセットアップも自動化すること。

llama.cppでの利用例

  • FP16ベースライン
    ./llama.cpp/build/bin/llama-cli -m models/your-model.gguf -p "Your prompt" -t 8 --flash-attn
    
  • 推奨:K8V4(8bitキー/4bit値)
    ./llama.cpp/build/bin/llama-cli -m models/your-model.gguf -p "Your prompt" -t 8 --flash-attn --kvq 8
    
  • K4V8(4bitキー/8bit値)
    ./llama.cpp/build/bin/llama-cli -m models/your-model.gguf -p "Your prompt" -t 8 --flash-attn --kvq-key 4 --kvq-val 8
    
  • K4V4(4bitキー/4bit値)
    ./llama.cpp/build/bin/llama-cli -m models/your-model.gguf -p "Your prompt" -t 8 --flash-attn --kvq 4
    
  • 長文対応例(32K文脈長)
    ./llama.cpp/build/bin/llama-cli -m models/your-model.gguf -c 32768 -n 4096 -t 8 --flash-attn --kvq 8 -f your-long-document.txt
    

コマンドラインフラグ一覧

  • -t 8:スレッド数(Apple Siliconは8推奨)
  • --flash-attn:最適化Attention有効化
  • --kvq N:キー・値ともにNビット指定
  • --kvq-key N:キーのみNビット指定
  • --kvq-val N:値のみNビット指定
  • -c N:文脈長(長いほどKVSplitの恩恵増大)
  • -n N:生成トークン数
  • -f FILE:入力ファイル指定
  • -m MODEL:モデルファイルパス

ベンチマーク・可視化

  • 簡易比較
    python scripts/quick_compare.py --model models/your-model.gguf
    
  • 詳細ベンチマーク
    python scripts/benchmark_kvsplit.py
    python scripts/benchmark_kvsplit.py --config K8V4 --seq-len 4096
    
  • 可視化
    python scripts/visualize_results.py
    
  • メモリ削減のGIF化
    ./scripts/capture_memory.sh
    

プロジェクト構成

  • llama.cpp/:Metal最適化llama.cpp
  • models/:モデル格納先
  • scripts/:インストール・ベンチマーク・可視化スクリプト
  • results/:ベンチマーク結果
  • plots/:可視化出力
  • README.md:ドキュメント

科学的知見・論拠

  • キーは値よりも量子化に敏感 であり、精度劣化を抑えるにはキー側のビット幅を優先することが重要。
  • K8V4 が「品質・効率・速度」の最適解であることを実証。
  • メモリ効率 を最大化しつつ、消費者向けMacで長文コンテキストや大型モデルを扱うことが現実的になる提案。

推奨構成

  • 総合ベスト :K8V4(8bitキー/4bit値)→59%削減+品質劣化0.86%のみ、速度向上(+5.7%)
  • 最大メモリ削減 :K4V4(4bitキー/4bit値)→72%削減、品質劣化約6%(用途限定向き)
  • 長文対応 :K8V4またはK4V4(文脈長が長いほど恩恵大)

今後のロードマップ

  • 適応的精度制御 :トークン重要度に基づく動的ビット幅割当
  • 層ごとの量子化 :モデル層ごとに異なる精度を適用すること
  • モデル特化最適化 :Mistral、Phi-3等への最適化
  • Webデモ・モバイル対応 :iOS/iPadOSへの展開

ライセンス・貢献

  • MITライセンス で公開
  • 貢献歓迎 :Issue/PRでフィードバック・改善提案を受け付けること

参考文献・クレジット

  • "More for Keys, Less for Values: Adaptive KV Cache Quantization" (2024)
  • "Unifying KV Cache Compression for Large Language Models with LeanKV" (2025)
  • llama.cpp (ベース実装)、 TinyLlama (テストモデル)

まとめ

  • Apple Silicon大型LLM/長文推論 を実現したいユーザーにとって、 KVSplit は現時点で最も合理的な選択肢。
  • メモリ効率・品質・速度 すべてを高水準で両立する提案であり、今後のLLM推論の標準技術となる可能性が高いことを確認。

Hackerたちの意見

いい仕事だね。すごく興味深いけど、もう少し高レベルな情報が必要だな。例えば、2048トークンのコンテキストウィンドウを持つモデルを4-6kのコンテキストウィンドウで動かせるの?それとも、128kモデル(gemma3みたいな)を256k以上のコンテキストウィンドウで使えるの?ローカルモデルの理想的な使い方は何なの?ありがとう。

K8V4設定で59%のメモリ節約ができるから、同じハードウェアでコンテキストを2.4倍長く実行できるよ。2048トークンのコンテキストを持つモデルは約5000トークンを処理できるし、8Kコンテキストモデルは約19.5Kトークンに達することができる。実際には、MacBookで本全体を一度に処理したり、大きなコードベースをファイルを分割せずに分析したり、チャットアプリで包括的な会話履歴を維持したりすることを意味するよ。メモリの節約はコンテキストの長さに比例して増えるから、コンテキストウィンドウが長ければ長いほど、より多くのメモリを節約できる。私のM4 MacBookで8Kコンテキストを使ったとき、KVキャッシュを176MBから72MBに減らしたよ。128Kコンテキストでは、その同じ割合の節約でギガバイトの空きが出る。最適化は、モデルパラメータに制限されるのではなく、コンテキストウィンドウに制限されるときに最も価値があるよ。大きなモデルの重みではなく、長い入力によってOOMエラーが出る場合、KVSplitはそのボトルネックに直接対処するんだ。

2048トークンのコンテキストウィンドウを持つモデルを4-6kのコンテキストウィンドウで動かせるのか? 特定のモデルのメモリフットプリントを減らすよ。好きなようにできる。トレーニング後にコンテキストウィンドウを拡張するのは簡単じゃないから、自分が何をしているかわからないなら、より大きなコンテキストウィンドウでトレーニングされたモデルを探した方がいいよ。ローカルモデルにはオフラインで作業したり、プライバシーやセキュリティのための多くの用途があるけど、ほとんどの人はモデルを調整する実験に使ってるね。

ちょっと気になるんだけど、モデルをすでに.gguf形式に変換した後に、差分KV量子化(K8V4みたいな)を適用することってできるの?それとも特別なサポートでモデルを再構築する必要があるの?どんな.ggufファイルでも互換性があるなら、モデルタイプ(MistralやPhi-3など)やトークナイザーの設定に制限はあるの?

そう、それが主な利点の一つなんだ - KVSplitは既存の.ggufモデルで再構築や特別な変換なしに動くよ。量子化はモデルの読み込みや変換中ではなく、KVキャッシュのランタイムで行われる。これは、トークンが処理される際に推論中にKVキャッシュが作成されるからで、モデルの重みとは完全に別物なんだ。--kvq-keyと--kvq-valフラグは、これらの中間テンソルをメモリにどう保存するかをllama.cppに指示するだけ。以下のモデルで成功を確認したよ:- Llama-3モデル - Mistralモデル - Phi-2/Phi-3 - TinyLlama - Qwenバリアント 唯一の制限は、llama.cppのMetalバックエンドが必要で、現在のFA実装がカスタムKVキャッシュ形式をバイパスするから、-fa 0でFlash Attentionを無効にする必要があること。技術自体は、標準的なアテンションメカニズムを使用するどんなトランスフォーマーアーキテクチャでも動くはずだよ。

これって、64GBや128GBのAppleシリコン(36GBや48GBよりも)でかなり速くなるの?大きなコンテキストや大きなモデルは、どんなに高価なAppleシリコンでも遅すぎるって読んだことがあるから、これがより多くのメモリを活用するのか、それとも実際には小さめのモデルがAppleシリコンではまだ有効なのか気になるな。

KVSplitからのメモリ節約はコンテキストの長さに比例してスケールするから、より高いRAMを持つMac(64GB/128GB)は絶対的にもっと恩恵を受けるよ。128GBのMac Studioでは、数十万トークンのコンテキストウィンドウを扱える可能性がある。ただ、KVSplitは計算速度を根本的に変えるわけじゃなくて、メモリ効率を改善するだけなんだ。私たちのベンチマークでは、K8V4で14.5%のスループット改善が見られたけど、これは計算が減ったわけじゃなくて、メモリのローカリティが良くなったからなんだ。「痛いほど遅い」大きなモデルの問題は、主に計算の制限から来ていて、メモリの制約からではない。70Bパラメータのモデルは、利用可能なRAMやKVキャッシュの最適化に関係なく、同じトークン生成速度で動作する。KVSplitがするのは、利用可能なメモリをより良く活用すること。特にボトルネックがモデルサイズではなくコンテキストの長さであるときに価値がある。実際のApple Siliconの使用においては、スイートスポットは小さなモデル(7B-13B)で、今は拡張されたコンテキストウィンドウを持っている。これで、合理的な生成速度を維持しながら、かなり多くのテキストを処理できるようになる。もしワークフローが巨大なコンテキストと大きなモデルの両方を必要とするなら、サーバーグレードのGPUを考慮するべきだけど、KVSplitはAppleハードウェアでの実現可能性の限界を押し上げるのに役立つよ。

このパッチはMLXで適用できるの?MLXでの速度が良くなってるんだ。それにあなたのアプローチを組み合わせれば、Macユーザーが使える速度で長い会話ができるようになるかも。

たぶんそうだと思うけど、今はMLXのことに夢中で、よく設計されたフレームワークだけど、誰かが「これがベストなやり方」ってベンチマークした例のコードがあまり成熟してないことに気づいてる。実は、Haskellのバインディングが一番の希望なんだよね。誰かがこの前指摘してたけど、その遅延特性がそのパラダイムにすごく合ってるし、コンパイルグラフへの純粋関数アプローチも役立つと思う。HaskellでのMLは楽しそうだね。

面白そうだね!どうしてこうなるのか、何か直感的な理由はある?その直感から発見したの?それともただのランダムな実験?一つ言っておくと、あなたのインストールスクリプトには「パッチを適用」ステップでまだプレースホルダーがあるみたい。提案なんだけど、llama.cppをフォークして、それをgitサブモジュールとして含める方が「git cloneしてパッチを適用」ステップよりもユーザーフレンドリーかもしれないね。さらに、みんなそれぞれ異なるローカルPythonのセットアップを持ってるから、llama.cppの部分をPythonの部分から分けられるといいかも。HomebrewのPythonに依存しないようにするために。

直感についての素晴らしい質問だね!違いは、これらのコンポーネントがアテンションで果たす役割の核心から来てる。キーはどのトークンに注意を向けるかを決める - それが類似性計算を通じて実際のアテンションパターンを作り出す。バリューは、アテンションが決まった後にどの情報が次に渡されるかを保存するだけ。キーのベクトルが過度に量子化されると、すべてのトークンの相互作用に対する類似性計算が歪む。キーに小さなエラーがあると、注意が完全に間違ったトークンに向かってしまう。でも、バリューはもっと寛容だよ。バリューのベクトルが量子化されると、エラーはその特定のトークンの情報内容にしか影響しないから、アテンションパターンがすでに確立されている後では。図書館のカタログシステムと本そのものの違いみたいなもんだね。カタログ番号(キー)が壊れたら、全然違うセクションを探すことになる。でも、本の中のいくつかの単語(バリュー)がかすれても、まだ正しい本を読んでる - ただ時々ノイズがあるだけ。数学的には、キーはソフトマックス計算に参加していて、小さなエラーが正規化プロセスを通じて指数関数的に増幅される。バリューは線形加重平均を受けるだけで、エラーは打ち消し合う傾向がある。最初にこの非対称性に気づいたのは「More for Keys, Less for Values」や「KV-AdaQuant」みたいな論文だったけど、Apple Siliconの推論にどれだけ影響するかを正確に定量化したいと思った。K8V4とK4V8の間の7倍の品質差は衝撃的だった。インストールのフィードバックもありがとう!プレースホルダーを修正して、Pythonの依存関係をもっと柔軟にするよ。

注意、あなたのインストールスクリプトは「パッチを適用」ステップにまだプレースホルダーがあるようです。提案ですが、llama.cppをフォークして、それをgitサブモジュールとして含める方が「git cloneしてパッチを適用」ステップよりもユーザーフレンドリーかもしれません。パッチは実際にはllama.cppには適用されません、なぜなら引数解析が8ヶ月前にarg.cppに移動されたからです。でも、それは関係ありません、なぜならKとVの量子化を設定するオプションは2023年にllama.cppに追加されたからです。なぜパッチが存在するのか全く理解できません、異なるコマンドライン引数を通じて設定を変更することで新しいものに見せようとしているだけなのでは?新しいリポジトリからのinstall.shファイルを実行しないことを強くお勧めします、特にパッチファイルを適用するのがそんなに簡単な場合は。

Hacker Newsで議論の続きを見る