KoboldCppのContextShift機能

  • 最近、LLMのチャットUIとして「SillyTavern」を試しています。非常に多機能ですが、多機能すぎて全貌が把握できていません。

github.com

  • SillyTavernの特徴は、フロントエンド(ユーザーインターフェース)のみの構成で、バックエンド(LLMローダー機能)を持たない点です。
  • そのためローカルLLMを使う場合は、text-generation-webui・llama.cpp・KoboldCPPなど別のアプリをAPIサーバーとして起動し、SillyTavernと接続する必要があります。
  • SillyTavern関連のスレッドを見ると、バックエンドとしてKoboldCPPがおすすめされていることが多いので、ひとまずKoboldCPPをAPIとして使っています。

 KoboldCppのContextShift機能

  • KoboldCPPは、llama.cppをベースにしていて、だいたいllama.cppの開発進捗に順じて機能が追加されている印象です。
  • ただし、llama.cppの機能をすべてフォローしているわけではなく、逆に独自の機能拡張もいくつかなされているようです。
  • 今回KoboldCPPの「ContextShift」という機能に興味を持ったので、備忘的にメモします。この機能についてはKoboldCPPのQAページで以下の通り解説されています。

github.com

ContextShiftとは

Context Shifting は SmartContext の改良版で、GGUFモデルでのみ機能します。この機能は KV cache shifting を利用し、コンテキストの再処理を必要とすることなく、自動的に古いトークンを削除し、新しいトークンを追加します。world infoを使用せずメモリを固定して使う限り、コンテキストを最大にしても連続する生成の間での再処理をほとんどすべて回避できるはずです。追加のコンテキスト領域を消費しない点で、従来のSmartContextよりも優れています。Context Shifting はデフォルトで有効になっています。Context ShiftingとSmartContextの間で出力内容に違いが生じる可能性はありますが、どちらも同じように一貫性を維持できるはずです。Context Shifting を無効にするには、--noshift フラグを使用します。

  • LLMで遊ぶ場合にストレスを感じやすいのは、コンテキスト管理です。LLMには一度にプロンプトとして処理可能なトークン数(テキストの長さ)に制限があります。
  • そのため、上限に近づいたら古いチャット履歴なりをコンテキストから削除してトークン数がオーバーフローしないように調整する必要があります(多くのUIには調整機能が一応ついています)。
  • とはいえ、古い履歴を削除するたびにコンテキストのキャッシュがリセットされるので、あらためて最初からプロンプト処理を繰り返さなければいけません。
  • 長いチャット履歴をコンテキストに入れている場合などはプロンプト再処理にかなり時間がかかるので、これが面倒くさいポイントです。
  • KoboldCPPの Context Shift は、古いトークンの削除に伴うプロンプト再処理を不要にしてくれるらしいので、なかなか魅力的な機能に思えます。
    • llama.cpp にもコンテキストをキャッシュする機能自体はありますが、ContextShiftのように動的に自動管理する仕組みは実装されていないと思います。

 llama.cppのKVキャッシュ関連PR

  • 上記のQAの説明を読んで、ついでにllama.cppのkv cache関連のPRにも目を通してみました。

#3457 demo : per-layer KV / partial offloading of KV cache (Opened 2023/10/04)

#4309 llama : per-layer KV cache (Opened 2023/10/04)

#4312 llama : support quantum K cache (Opened 2023/10/04)

  • そもそも私には kv cache(KeyとValue?)の意味が分かっていませんが、ざっくりコンテキストのキャッシュ/一時保存を指しているんでしょう。たぶん。
  • 最近のllama.cppの部分オフローディング(VRAM容量の制約に対応するため、言語モデルをCPUとGPUに分割して処理・推論する)のスピードアップにKVキャッシュが関わっているようです。
  • 従来、モデルを部分オフロードする場合、KVキャッシュはCPU/GPUのいずれかにまとめて配置しなければならず、その不一致が推論を遅くする一因になっていました。
  • それが、#3457と#4309によりキャッシュの配置もモデルに合わせてCPU/GPUに分割できるようになり、部分オフロード時の推論速度が改善したということのようです。

https://github.com/ggerganov/llama.cpp/pull/3457
  • #4312 は(KVキャッシュのうち)Kキャッシュを量子化するためのPRのようです。モデルだけでなくキャッシュも量子化して圧縮できるんですね。
    •  Vキャッシュの量子化は未実装と書かれていますが、時間がたっているのですでに実装済みかもしれません。
    • -ctk q8_0 / --cache-type-k q8_0 がKキャッシュ量子化のためのフラグ、-ctv q8_0 / --cache-type-v q8_0 がVキャッシュ量子化、と書かれています。
    • また、これにともなって、--memory-f32 と --f16_kv フラグを削除すると書かれています。--memory-f32 は現時点でREADMEに残っているので、ドキュメントは更新されていないようです。