画像エンコード結果の再利用(実験機能)
September 21, 2026 · View on GitHub
LFM2.5-VLの画像エンコーダー+projectorが出力したembeddingを、llama.cpp内部で再利用します。モデルへの画像・state・質問の入力処理(decoder prefill)は質問ごとに実行し、KVや再帰状態は共有しません。PNG/JPEGの読み込み・リサイズ等の前処理も質問ごとに行います。
公式b11042のソースに小さなパッチを適用した、別の実験用バイナリです。通常の./run.shや配布済みバイナリには変更を加えていません。このビルド手順はLinux/ROCm向けで、この環境ではR9700で確認しています。
このページのランチャーはLFM用です。 Sarashinaは同じLRU部品を使いますが、projectorと前処理の修正が必要なため専用のビルド・ランチャーへ分離しています。
起動
初回は下記「ビルドと再検証」の手順でビルドしてください。バイナリはリポジトリに含めません。同じポートのサーバーが動いている場合は止めてから起動します。
./run_image_cache_gpu.sh --port 18080 --backend-port 18097
別ターミナルから既存のクライアントをそのまま使えます。下の例の画像は各自でsample_pics/に配置します(画像は同梱していません)。
python3 systemone_client.py \
--url http://127.0.0.1:18080 \
--input examples/vision_gss_4.json \
--image sample_pics/20260911_image_resized.png
同じ実験バイナリで無効にする場合:
JEV_IMAGE_CACHE_MIB=0 ./run_image_cache_gpu.sh --port 18080 --backend-port 18097
GPU_DEVICEの既定値はROCm0です。ROCmライブラリはROCM_LIBRARY_DIRで指定できます。未指定で既存LM Studioのvendor-v4ディレクトリが存在する場合はそれを利用します。
再利用範囲と寿命
- LFM2のvisionのみが対象で、音声や他モデルには適用しません。
- 正規化後の画素の完全なバイト列・形状・タイルの付加情報をキーにします。同じ画像IDを持つ別タイルの取り違えを防ぎます。
- モデルコンテキストごとに独立したメモリ上のLRUです。画像を変更すると別のキーになり、モデル終了時に全削除します。ディスクには保存しません。
- 既定の上限はキーとembeddingの合計128 MiB。超過時は古いエントリーから破棄します(管理オブジェクトや一時作業メモリは上限外)。
JEV_IMAGE_CACHE_MIB=0..4096で変更できます。 - 同時に来た同一画像のエンコードを重複させないよう、初回計算を含めてロックします。失敗した計算結果は保存しません。
- 4問の初回送信では1回計算+3回再利用、同じ画像の再送信では4回とも再利用します。複数タイル画像では各タイル・サムネイルごとに同様に処理します。
- HTTPの
X-Jev-Local-State-Cache: off-imagesは引き続きdecoder側のState共有が無効であることを示します。画像embeddingのhit/missはバックエンドログのJEV_IMAGE_CACHEで確認します。
比較結果
512×286 pxのGSS画像+4問、R9700、4 slots、CTX_SIZE=32768。無効→有効→有効→無効の順で、各ブロックは初回1回+5回測定。モデルロードと入力ファイルの読み込みは時間から除き、HTTP応答完了までを測定しました。
| 条件 | 時間 |
|---|---|
| 無効、初回リクエスト(2回) | 380〜383 ms |
| 有効、未登録の画像(2回、各1 miss+3 hits) | 192〜212 ms |
| 無効、初回を除く10回の中央値 | 358 ms |
| 有効、同じ画像の再送信10回の中央値 | 98 ms |
同じ画像の再送信では約3.66倍高速でした。初回は約1.9倍です。4問の選択結果は全条件で同じ。4並列での確率の揺れは最大約0.0247(2.47ポイント)あり、無効時にも揺れを確認しています。1ワーカーの追加比較ではキャッシュ有無で全候補確率の差は0でした。
これは1画像・4問の測定であり、サイズや質問数に応じて効果は変わります。元の質問の選択肢順による偏り・誤答の問題を改善する機能ではありません。
測定要約は画像評価の記録にまとめています。生データのresults/は各環境で生成するGit対象外のフォルダで、過去の測定ファイルは配布しません。
ビルドと再検証
Linux x86_64、GCC(g++、C++17)、CMake 3.14以上、Ninja、利用可能なAMD ROCm環境が必要です。通常の推論と異なり、コンパイルを行います。ROCmプラグインは公式b11042ランタイムのlibggml-hip.soを利用します。C++ ABIの一致のためGCC/libstdc++を使ってください。CC・CXX・CMAKE・NINJAで各実行ファイルを指定できます。依存ツールやOSパッケージは自動インストールしません。
./setup.sh --model vision --backend rocm
python3 scripts/build_image_cache.py --jobs 8
# LM Studio同梱ROCmライブラリを利用する場合の例。
# システムのROCmライブラリで動く環境ではLD_LIBRARY_PATHの指定は不要です。
LD_LIBRARY_PATH="$HOME/.lmstudio/extensions/backends/vendor/linux-llama-rocm-vendor-v4${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
python3 -m tools.benchmark_image_cache \
--image sample_pics/20260911_image_resized.png
setup.sh --model vision --backend rocmも同じROCm共有ライブラリが必要です。LM Studioのライブラリを利用する場合は、セットアップ前からLD_LIBRARY_PATHを設定してください。
比較ツールは同一の実験ビルドでキャッシュを無効・有効に切り替えます。入力は--input(Choiceのみ)、画像は--image、GPUは--deviceで指定できます。GPUの既定はROCm0で、機種名は固定しません。比較ツールは実験用ポート19080/19097を使い、終了・失敗時に自分が起動したプロセスを停止します。ポートが使用中なら停止し、--port・--backend-portで変更できます。既存の測定JSONとログは上書きします。別保存先は--output、数値比較の逐次実行は--workers 1で指定します。
ソースのURLとSHA256はnative/source.jsonに固定し、変更箇所はscripts/patch_vision_cache.pyとnative/vision_embedding_cache.hで管理しています。ビルド成果物のハッシュは.cache/vision-build-gcc/jev-build.jsonに保存します。ネイティブ単体テストは同時ミスの集約、キーの区別、エラー処理、LRUによる破棄、上限超過、コンテキスト間の分離を確認します。
開発時の追加検証では、赤/青の別画像が混同されず、1024×1024の合成画像の4タイル+サムネイルがそれぞれ初回miss、再送時hitになることも確認しました。