
MacのGPUでLLM(大規模言語モデル)を動かすとき、出力を長くすれば、生成時間も少しずつ長くなると考えるのが自然です。
ところがApple MPS(Metal Performance Shaders、Apple GPU向けの計算・画像処理基盤)では、近い出力長の設定でもレイテンシ(処理開始から完了までの時間)が突然10倍以上に跳ね上がり、さらに出力を長くすると元へ戻る場合があると報告されました。
本記事では、最大21倍の遅延スパイクを観測した論文をもとに、KV Cacheとの関係、MPS内部の実行レジーム(条件によって現れる異なる性能状態)、再現実験の読み方、Mac上でLLMを評価するときの注意点を解説します。
3文要約

本論文は、Apple MPS上のTransformerデコードで、生成トークン数を増やしても処理時間が比例して増えず、特定の生成トークン数の範囲だけ最大21倍遅くなった後に回復する現象を報告しています(以下、この範囲を「異常区間」と呼びます)。
異常は主にprefillではなくdecodeで発生し、GPT-2、BLOOM、OPT、M3 Max、M3 Pro、複数のPyTorch版で定性的に再現されましたが、CPUとNVIDIA CUDA T4では同じ条件下で確認されませんでした。
KV Cacheは全体として有効である一方、異常区間では実用上の高速化率が1.9倍まで縮み、メモリ使用量だけではこの急な遅延と回復を説明できないため、論文はMPS内部の処理方法が条件に応じて切り替わる可能性を示しています。
論文情報

| 項目 | 内容 |
|---|---|
| 論文タイトル | Non-Monotonic Latency in Apple MPS Decoding: KV Cache Interactions and Execution Regimes |
| 著者 | Willy Fitra Hendria |
| 所属 | Independent Researcher |
| 発表年 | 2026年 |
| arXiv初版 | 2026年5月9日 |
| 本記事の対象 | 2026年5月14日公開のv2 |
| 論文リンク | Non-Monotonic Latency in Apple MPS Decoding |
| HTML版 | arXiv HTML |
| arXiv PDF |
本記事では、論文が測定した事実と、そこから考えられる実務上の解釈を分けて記載します。
特に、論文はMPS内部のkernel(GPU上で実行される計算処理)やscheduler(処理の割り当て機構)を直接観測していません。
論文が確認したのは、「特定の生成トークン数で処理時間が急増し、さらに長くすると回復する」という外部から観測できる現象までです。
「そのトークン数を境にMPSが別のkernelへ切り替わり、処理効率が落ちた」と直接観測・証明したわけではありません。内部の処理方法が切り替わったという説明は、測定結果と矛盾しない仮説として扱う必要があります。
本記事の目的

ローカルLLMのベンチマークでは、「平均で毎秒何トークン生成できるか」「CPUよりGPUが速いか」といった単一の数字に注目しがちです。
しかし、本論文の結果が示すのは、ある生成トークン数で測った性能から、少しだけ短い、または長い設定の性能を予測できない場合があるという問題です。
たとえばGPT-2 Mediumでは、496トークンの生成に9.5秒、512トークンには89.2秒、640トークンには8.8秒かかりました。496トークンの結果を見て「512トークンも少し遅くなる程度だろう」と考えたり、512トークンの結果を見て「640トークンならさらに遅いだろう」と考えたりすると、実測と大きく外れます。
本記事では、次の順番で整理します。
- 自己回帰生成におけるprefillとdecodeの違い
- KV Cacheが何を保存し、なぜ通常は速くなるのか
- Apple MPSで観測された非単調レイテンシ
- KV Cache、メモリ使用量、モデル種類、プロンプト長の切り分け
- Mac上でLLMを評価・運用するときの実践的な対策
背景:LLM推論のprefillとdecode

Decoder-only Transformerの推論は、大きくprefill(入力をまとめて処理する段階)とdecode(出力を1トークンずつ生成する段階)の2つに分かれます。Transformerの基本構造は、過去記事のDecoder-only Transformerとは?GPT型LLMの仕組みを図解でも詳しく解説しています。
| 段階 | 処理 | 典型的な特徴 |
|---|---|---|
| prefill | 入力プロンプト全体をまとめて処理する | 行列同士の大きな演算を並列化しやすい |
| decode | 直前までの文脈を使い、次の1トークンを生成する | トークンごとに逐次実行され、KV Cacheを読み続ける |
たとえば「Apple SiliconでLLMを動かす方法を説明して」というプロンプトを入力すると、prefillで入力トークン全体の内部表現を作ります。
その後のdecodeでは、1トークン生成するたびに、そのトークンを文脈へ追加して次のトークンを予測します。
自己回帰生成(過去に生成したトークンを使って、次のトークンを順番に作る方式)では、トークン \(t\) を生成し終えないとトークン \(t+1\)を確定できません。
そのためdecodeは、GPUに十分な並列演算器があっても、生成ステップ間の依存関係をなくせません。
本論文では、異常区間に入る512トークンの設定でprefillが0.11秒、全体の0.1%にすぎない一方、decodeは89.1秒かかりました。
直前に測った496トークンの設定ではdecodeが9.4秒だったため、両設定の約80秒の差はほぼdecodeから生じています。
前提知識:KV Cacheは何をしているのか

先に論文の主題を整理します。本論文が明らかにしたいのはKV Cacheの優劣ではなく、MPSでは生成トークン数と処理時間が比例せず、特定の範囲だけ極端に遅くなる現象です。
KV Cacheの有効・無効は、その現象がキャッシュだけで起きるのかを切り分けるための実験条件の1つです。結果を理解する前提として、まずKV Cacheの役割を確認します。
Self-Attentionでは、各トークンからQuery、Key、Valueを作り、現在のQueryと過去のKeyの類似度を使ってValueを集約します。
1つのAttention headについて、decode時刻\(t\)の計算は、簡略化すると次のように表せます。
\[
q_t = x_t W_Q, \qquad k_t = x_t W_K, \qquad v_t = x_t W_V
\]
\[
a_t
=
\mathrm{softmax}\left(
\frac{q_t K_{1:t}^{\mathrm{T}}}{\sqrt{d_k}}
\right)
\]
\[
o_t = a_t V_{1:t}
\]
ここで、\(K_{1:t}\)と\(V_{1:t}\)は、先頭から現在までのKeyとValueです。
KV Cacheは、過去トークンの\(K\)と\(V\)を各Transformer層に保存します。
次のトークンを生成するときは、新しいトークンの\(k_t\)と\(v_t\)だけを追加し、過去の分を再計算しません。
| 観点 | KV Cacheあり | KV Cacheなし |
|---|---|---|
| 過去トークンのKey・Value | 保存して再利用 | 各生成ステップで再計算 |
| decodeの計算量 | 大幅に削減 | 出力が長いほど重複計算が増える |
| メモリ使用量 | 文脈長にほぼ比例して増える | キャッシュ分は不要 |
| 一般的な用途 | LLM推論の標準設定 | 検証や、極端なメモリ制約時の選択肢 |
Hugging Face Transformersの標準的なDynamicCacheも、生成が進むにつれてKeyとValueを動的に追加します。
KV Cacheは通常、速度と引き換えにメモリを使う技術です。
ここで重要なのは、「KV Cacheを使うと遅くなる」という結論ではないことです。
異常区間でもキャッシュありの方がキャッシュなしより速く、KV Cache自体の有効性は保たれています。ただし、異常区間では通常時ほど大きな高速化を得られません。この結果は、KV Cacheが原因だと断定する材料ではなく、MPSの非単調な処理時間がキャッシュ利用時の性能にも強く影響することを示しています。
Apple MPSとは?PyTorchからMacのGPUを使う仕組み

MPSはMetal Performance Shadersの略で、Apple GPU向けに調整された計算・画像処理kernel群です。
PyTorchのmpsデバイスを使うと、機械学習の計算グラフや演算がMPS GraphとMPSのkernelへ対応付けられ、Apple SiliconのGPUで実行されます。この橋渡しを担う部分をMPSバックエンドと呼びます。
| 層 | 役割 | 開発者からの見え方 |
|---|---|---|
| Transformers / PyTorch | モデルとtensor演算を記述 | Python APIで操作できる |
| PyTorch MPS backend | PyTorch演算をMPS側へ橋渡し | device="mps"として選ぶ |
| MPS Graph / MPS kernel | 計算graphの最適化とGPU演算 | 高水準APIから内部詳細は見えにくい |
| Apple GPU | 実際の並列計算を実行 | Metal profilerなどで低水準に調査する |
Appleの公式説明では、MPSのkernelは各Metal GPUファミリーの特性に合わせて調整されています。
補足:kernelとCUDAのwarpは別のもの
kernelは、GPUへ実行を依頼する計算処理です。一方、CUDAのwarpは、そのkernelを同じ命令で並列実行する32スレッドのグループを指します。つまり、kernelは「実行する処理」、warpは「その処理を実行するスレッドのまとまり」であり、同じものではありません。
MPSのkernelとCUDA kernelは実行基盤が異なるため完全に同一視はできませんが、「GPU上で実行される計算処理」という大まかな対応関係はあります。CUDAのwarp、tile、Tensor Coreの関係は、過去記事のGPUはなぜ行列積をtile化するのか?warp・Shared Memory・Tensor Coreから理解するで解説しています。CUDAの定義はNVIDIA CUDA Programming Guideも参照してください。
PyTorchではdevice="mps"を指定するだけでApple GPUを利用でき、開発者がkernelの選択や実行順序を細かく指定しなくても処理できます。これは実装を簡単にする大きな利点です。
一方、その内部判断は高水準のPyTorch APIから見えにくいため、特定の生成トークン数だけ急に遅くなっても、「どのkernelが選ばれたのか」「処理の割り当てが変わったのか」をAPIの計測だけで切り分けることは困難です。本論文も遅延現象までは確認していますが、内部原因の特定には至っていません。
従来のベンチマークでは見落としやすい問題

LLM推論性能は、固定した1つの出力長や、複数の出力長で測った平均値を使って比較されることがあります。
平均値はデバイス同士の全体的な性能差を比べるには分かりやすい一方、特定の生成トークン数だけで起きるピークや極端な遅さをならしてしまいます。たとえば512トークンだけが約10倍遅くても、384・512・640トークンの平均だけを見れば、「どの設定が苦手なのか」は分かりません。
本論文のGPT-2 Mediumでは、384トークンで5.12秒、512トークンで84.54秒、640トークンで8.67秒でした。
もし384トークンと640トークンだけを測れば、512トークン付近の異常区間を検出できません。
逆に512トークンだけを測れば、「MPSは常に極端に遅い」と誤解する可能性があります。
| 測定方法 | 長所 | 短所 |
|---|---|---|
| 単一の出力長 | 簡単で比較しやすい | 局所的な異常を見落とす |
| 128トークン刻み | 大まかな傾向を少ない実験で把握できる | 境界位置と区間幅が曖昧になる |
| 16トークン刻みの局所測定 | 急変する境界を見つけやすい | 測定時間と実験数が増える |
| トークン単位の詳細計測 | prefillとdecodeを切り分けられる | 同期処理が実行挙動へ影響しうる |
論文は、まず大きな間隔で生成トークン数を変えて異常を見つけ、次に480〜656トークンを16トークン刻みで測ることで、どこから遅くなり、どこで回復するかを詳しく調べています。
論文解説:MPSの非単調レイテンシをどう切り分けたか

論文は、次の問いを順番に切り分けています。
| 問い | 実験 | 論文で得られた結果 |
|---|---|---|
| 一時的な測定のばらつきか | ウォームアップ3回、測定5回、局所測定 | 高遅延区間が複数点で持続 |
| prefillが原因か | トークン単位の時間計測 | 差のほぼすべてがdecodeで発生 |
| 1台だけの問題か | M3 MaxとM3 Proを比較 | 両方で定性的に再現、境界は異なる |
| GPT-2固有か | BLOOM-560M、OPT-350Mを追加 | 他のモデル系列でも再現 |
| PyTorch版固有か | 2.7.0、2.8.0、2.11.0を比較 | 複数版で定性的に持続 |
| KV Cacheだけが原因か | キャッシュの有効・無効を比較 | 無効でも非単調性が残る |
| 単純なメモリ不足か | MPS割当量とシステムメモリを測定 | 使用量の変化と遅延の回復が一致しない |
| 出力長だけで決まるか | 3トークンと約65トークンのプロンプトを比較 | プロンプト長も異常区間への進入に影響 |
これらの実験は、「一時的な測定のばらつきだけ」「KV Cacheだけ」「メモリ使用量だけ」といった単純な説明を、1つずつ検証するために行われました。結果として、どれか1つだけを原因とする説明では、遅延の発生と回復の両方を説明できませんでした。
ただし、複数の要因が組み合わさっていると証明したわけでもありません。論文が示したのは、モデル、端末、プロンプト長、キャッシュ設定など複数の条件で異常区間の位置や大きさが変わることです。原因となる内部kernelや条件の組み合わせは、今後の調査課題として残っています。
実験環境と測定方法

中心となる測定環境は、14-core CPU、30-core GPU、36GB unified memoryを持つM3 Max搭載MacBook Proです。
macOS 14.8.1、Python 3.9.6、PyTorch 2.8.0、Transformers 4.57.6、LitServe 0.2.16を使用しています。
| 条件 | 設定 |
|---|---|
| 主なApple端末 | M3 Max、36GB unified memory |
| 再現用Apple端末 | M3 Pro、18GB unified memory |
| 比較する実行基盤 | CPU、Apple MPS、NVIDIA CUDA T4 |
| モデル | DistilGPT-2、GPT-2、GPT-2 Medium、GPT-2 Large、BLOOM-560M、OPT-350M |
| 最大生成トークン数 | 128〜768トークン |
| 生成方法 | 乱数シードを固定した決定的デコード |
| 各設定の測定 | ウォームアップ3回を除外し、その後の5回を平均 |
| EOS(文末トークン) | 生成停止条件として使わず、設定したトークン数まで生成 |
実験はモデルを直接呼び出すbare model callではなく、LitServeを通して行われており、APIサーバーでのリクエスト処理やworkerへの割り当ても含む実運用に近い構成です。
補足:実験構成に関する用語
– bare model call:APIサーバーを介さず、Pythonコードからモデルの推論関数を直接呼ぶ方法です。
– LitServe:モデルをAPIとして提供するためのサービング基盤です。入力の変換、推論の呼び出し、応答の整形などをまとめて扱います。詳しくはLitServe公式ドキュメントを参照してください。
– request処理:APIが受け取った入力を検証・変換し、推論後の結果を応答形式へ整える処理です。
– worker scheduling:届いたリクエストを、モデルを保持して推論するworkerプロセスへ割り当てる処理です。
このため全体の応答時間にはMPS上のモデル計算以外の処理も含まれます。ただし論文は、遅延差のほぼすべてがトークンを順次生成するdecode中に生じたことを確認し、APIの前処理だけでは説明できないと判断しています。
以上を踏まえ、論文はLitServe側のリクエスト処理よりも、MPS側のkernel実行に関係する現象だと解釈しています。ただし、MPS内部のkernelを直接観測した結論ではありません。
トークン単位の測定では正確な時間を得るため、decodeの各ステップ後に同期処理を入れています。
同期処理を追加した測定と、追加していない通常実行では条件が異なるため、両者の処理時間をそのまま比較できません。
論文もこの点を明記し、キャッシュの有効・無効など、同じ計測条件で得た数値だけを比較しています。
結果1:512トークン付近で遅くなり、640トークンで回復する

代表的な結果は次のとおりです。
| モデル | 最大生成トークン数 | 処理時間 | 生成速度 |
|---|---|---|---|
| GPT-2 Medium | 384 | \(5.12 \pm 0.06\)秒 | \(75.27 \pm 0.83\) token/s |
| GPT-2 Medium | 512 | \(84.54 \pm 12.18\)秒 | \(6.20 \pm 0.99\) token/s |
| GPT-2 Medium | 640 | \(8.67 \pm 0.05\)秒 | \(73.88 \pm 0.40\) token/s |
| GPT-2 Large | 256 | \(4.91 \pm 0.02\)秒 | \(52.12 \pm 0.24\) token/s |
| GPT-2 Large | 384 | \(103.41 \pm 4.99\)秒 | \(3.70 \pm 0.18\) token/s |
| GPT-2 Large | 512 | \(9.27 \pm 0.05\)秒 | \(55.20 \pm 0.30\) token/s |
GPT-2 Largeでは、384トークンの設定が、その前後にある正常な設定に比べて最大約21倍遅くなりました。
重要なのは、モデルが大きいほど常に遅いという単純な結果ではない点です。
大きいモデルほど、より少ない生成トークン数で高遅延レジームへ入る傾向がありました。ここでレジームとは、生成トークン数などの条件に応じて現れる、低遅延・高遅延といった異なる性能状態を意味します。
補足:CUDA T4はTPU v4ではない
CUDA T4は、GoogleのTPU v4ではありません。論文で使われたのは、CUDAで実行するNVIDIA T4 Tensor Core GPUです。T4はTuring世代のNVIDIA製GPUで、16GBのGDDR6メモリを搭載した推論向けアクセラレータです。ここでCUDAはNVIDIA GPU向けの並列計算基盤、T4は具体的なGPU製品名を表します。
CPUとNVIDIA T4上のCUDAでは、同じ条件でも処理時間が滑らかに増えました。そのため、この現象はTransformer一般に必ず起きるものではなく、MPSバックエンドに強く関係すると考えられます。
結果2:異常は1点ではなく、512〜624トークンの範囲で続いた

GPT-2 Mediumの最大生成数を480〜656トークンまで16トークン刻みで変えると、処理時間は次のように変化しました。
| 区間 | 観測された状態 | 代表値 |
|---|---|---|
| 480〜496トークン | 正常な低遅延 | 9.2〜9.5秒 |
| 512〜624トークン | 高遅延レジーム | 83.2〜110.1秒 |
| 640〜656トークン | 低遅延へ回復 | 8.8秒、8.2秒 |
496トークンから512トークンへ増やした1回の変更で、処理時間は9.5秒から89.2秒へ急増しました。
624トークンから640トークンへ増やしたときは、反対に高遅延の状態から8.8秒へ戻りました。
高遅延が512トークンという1点だけなら、一時的なOS負荷や測定外れ値の疑いが強くなります。
しかし、複数の連続した生成トークン数で一貫して遅く、境界で急に切り替わったため、論文はこれを「pathological execution regime」と表現しています。直訳すると「病的な実行レジーム」です。
ここでpathological(病的)とは、生成結果が壊れるという意味ではありません。同じ出力を得られるものの、通常の傾向から外れ、処理効率だけが極端に悪い状態を強調する表現です。
結果3:KV Cacheは有効だが、異常区間では恩恵が縮む

GPT-2 MediumでKV Cacheを有効・無効にした比較は、次の結果でした。
| Decoding budget | Cache ON | Cache OFF | OFF / ON |
|---|---|---|---|
| 128 | \(1.38 \pm 0.02\)秒 | \(6.76 \pm 0.10\)秒 | 4.9倍 |
| 256 | \(2.90 \pm 0.03\)秒 | \(20.63 \pm 0.79\)秒 | 7.1倍 |
| 384 | \(5.11 \pm 0.03\)秒 | \(42.67 \pm 7.69\)秒 | 8.4倍 |
| 512 | \(83.21 \pm 7.98\)秒 | \(161.60 \pm 1.14\)秒 | 1.9倍 |
| 640 | \(8.79 \pm 0.04\)秒 | \(139.00 \pm 21.48\)秒 | 15.8倍 |
| 768 | \(9.69 \pm 0.04\)秒 | \(196.64 \pm 40.22\)秒 | 20.3倍 |
キャッシュを無効にしても、512トークンで161.6秒、640トークンで139.0秒となり、生成トークン数に比例して処理時間が増える結果にはなりませんでした。
したがって、KV Cacheを無効にすれば現象が消えるわけではありません。
一方、通常区間ではキャッシュによって4.9〜20.3倍速くなるのに、512トークンでは1.9倍まで差が縮みました。
これは、キャッシュ有効時の処理が高遅延レジームの影響を強く受け、通常区間で得られていた高速化効果が大きく縮んだことを示します。
論文の決定的なgreedy decoding(各時点で最も確率の高いトークンを選ぶ生成方法)では、キャッシュの有効・無効で出力は同一でした。
つまり、この差は生成内容の分岐ではなく、実行方法に関係する差と考えられます。
結果4:単純なメモリ不足では説明できない

Apple SiliconはCPUとGPUがunified memory(CPUとGPUで共有する物理メモリ)を使います。
そのため、システム全体のメモリ使用量が32GB付近まで増えたことを見れば、単純なメモリ不足やストレージへの退避が原因だと考えたくなります。
しかし、測定結果は完全には一致しません。
| Decoding budget | Peak MPS allocation | Peak system memory | Cache ON latency |
|---|---|---|---|
| 128 | 1,426MB | 13,166MB | 1.38秒 |
| 256 | 1,451MB | 16,809MB | 2.90秒 |
| 384 | 1,476MB | 22,111MB | 5.11秒 |
| 512 | 1,500MB | 32,881MB | 83.21秒 |
| 640 | 1,525MB | 33,261MB | 8.79秒 |
| 768 | 1,550MB | 31,227MB | 9.69秒 |
MPSが報告するGPUメモリ割当量は、128から768トークンまで約1,426MBから1,550MBへ、ほぼ一定の割合で増えました。
異常が始まる512トークンにだけ急な段差はありません。
システム全体のメモリ使用量は512トークン付近で大きく増えましたが、640トークンでも512トークン以上の使用量を維持しているのに、処理時間は正常へ戻りました。
したがって、メモリ圧力が無関係だとは言えないものの、容量の枯渇だけでは急な進入と回復の両方を説明できません。
結果5:モデル・端末・プロンプト長で境界が動く

M3 Maxでは主にGPT-2 MediumとGPT-2 Largeで異常が目立ちました。
一方、計算資源とメモリ容量が小さいM3 Proでは、GPT-2やDistilGPT-2のような小さいモデルでも異常が観測されました。
BLOOM-560MとOPT-350Mでも、短い設定では低遅延、中間で急増し、より長い設定で回復する同様の構造が現れました。
| model | 384 token | 512 token | 640 token | 768 token |
|---|---|---|---|---|
| BLOOM-560M | \(15.17 \pm 0.05\)秒 | \(80.76 \pm 5.04\)秒 | \(134.58 \pm 6.13\)秒 | \(40.80 \pm 0.21\)秒 |
| OPT-350M | \(7.40 \pm 0.07\)秒 | \(95.13 \pm 2.03\)秒 | \(15.71 \pm 0.13\)秒 | \(19.35 \pm 0.11\)秒 |
プロンプト長も、高遅延区間へ入る境界に影響しました。
512トークン生成する設定では、3トークンの短いプロンプトが7.3秒だったのに対し、約65トークンの長いプロンプトは83.9秒でした。
長いプロンプトは入力と出力を合わせた系列長が約577トークンとなり、短いプロンプトの約515トークンより先に高遅延領域へ入ったと考えられます。
ただし、640トークン設定ではプロンプト長が異なっても両方とも低遅延へ戻りました。
この非対称性から、異常への進入は合計系列長の影響を受ける一方、回復はdecoding budgetなど別の設定要因にも依存する可能性があります。
実行レジームとは何か

実行レジームとは、同じ高水準コードでも、入力テンソルの形状や一時領域の大きさなどの条件に応じて、実行基盤の内部で異なる性能状態が現れることを指します。
一般論として、実行環境は条件に応じて次のような判断を変える可能性があります。
- 使用するkernelやアルゴリズム
- テンソルの分割方法
- GPUへ命令を送る順序
- 一時バッファの確保方法
- 計算グラフのコンパイル方法や実行計画
本論文の観測は、低遅延、高遅延、再び低遅延という離散的な切り替えと整合します。
一方、PyTorch MPS APIからはkernel単位の詳細な計測情報を得られないため、内部のどの判断が変化したのかは確定していません。
| 論文で確認したこと | 確認していないこと |
|---|---|
| 特定区間で安定して高遅延になる | 原因となるkernelの名称 |
| decode phaseが差の大半を占める | MPS内部schedulerの具体的な判断 |
| CPU・CUDAでは同条件のspikeがない | 全Apple Silicon世代で同じ境界になること |
| 複数model・端末・PyTorch版で再現 | MLX、llama.cpp、Ollamaでも同じ現象が出ること |
| メモリ量だけでは回復を説明できない | memory subsystemが一切関係しないこと |
「実行レジームが原因」と「実行レジームのような現象が観測された」は、意味が異なります。
本記事では後者として扱います。
実務への影響:MacでLLMをどう評価すべきか

本論文から得られる最も直接的な教訓は、MPSの性能を1つの出力長だけで判断しないことです。
1. 実運用に近いプロンプト長と出力長を複数条件で測る
短文チャット、長文要約、コード生成では、プロンプト長と出力長の分布が異なります。
平均値だけでなく、実際に使う範囲の中央値、95パーセンタイル、最大付近を含め、複数の条件を測る必要があります。
大きな間隔で測って不自然な点を見つけたら、その前後を16〜32トークン程度の細かい間隔で再測定します。
2. prefillとdecodeを分ける
Time To First Token(最初のトークンが出るまでの時間)とTime Per Output Token(2トークン目以降の平均生成時間)を分けると、入力処理と逐次生成のどちらが悪化したか判断しやすくなります。
ただし、各生成ステップに同期処理を入れる詳細計測は通常実行へ影響するため、同期処理を追加した測定値と、追加していない測定値を混ぜて比較しないことが重要です。
3. 処理時間の平均だけでなく、ばらつきも記録する
平均値だけでは、同じ条件で毎回遅くなる現象と、ときどき偶然遅くなる測定のばらつきを区別できません。
最初の数回をウォームアップとして除外し、複数回測定して、平均、標準偏差、可能なら各回の結果を残します。
4. キャッシュの有効・無効は原因調査に使い、運用対策と混同しない
本論文ではキャッシュを無効にしても非単調性が残り、処理全体も大幅に遅くなりました。
したがって、異常を見つけたときにKV Cacheを無効化することは、一般的な高速化対策にはなりません。
キャッシュの有効・無効を比べる実験は、問題がキャッシュ固有かを切り分けるためには有効です。
5. 実行基盤を同じ条件で比較する
MPS、CPU、CUDAだけでなく、実際のMac運用ではMLX、llama.cpp、Core MLなど複数の実行基盤があります。
ただし、本論文が直接比較したのはPyTorch MPS、CPU、NVIDIA T4上のCUDAです。
別の実行基盤へ結果をそのまま一般化せず、同じモデル、量子化、プロンプト、生成設定で測り直す必要があります。
高画質・カメラ系タスクへの応用をどう考えるか

本論文は画像処理モデルではなく、Transformer言語モデルの自己回帰decodeを対象にしています。
そのため、ノイズ除去、デモザイク、超解像のように、画像を入力して画像を一括出力する処理へ、今回の512トークン付近の現象を直接当てはめることはできません。
一方、カメラ画像を理解して長い説明を生成するVLM(Vision-Language Model、画像と言語を同時に扱うモデル)や、撮影内容を対話的に案内するAIアシスタントは、自己回帰decodeとKV Cacheを使います。
| 応用 | 本論文との関係 | 確認すべき点 |
|---|---|---|
| 写真のcaption生成 | 言語decodeを使う | 画像token数と出力token数の組み合わせ |
| 画像に関する長文Q&A | 長いpromptと長いdecodeを使う | 合計系列長と異常境界 |
| カメラ操作AI agent | tool callを自己回帰生成する | 応答時間のtail latency |
| denoise / demosaic | 通常は画像modelの一括推論 | 本論文の現象を直接一般化しない |
| super resolution | autoregressiveでなければ対象外 | model固有のMPS性能を別途測る |
端末上のカメラアシスタントでは、平均応答時間が短くても、「特定の質問だけ10倍遅くなる」ような最悪時に近い応答時間がUXを大きく損ないます。
画像トークンを含む長いプロンプトは異常区間へ入る条件を変える可能性があるため、テキストだけの短いベンチマークで性能を判断しないことが重要です。
ただし、これは本論文の結果から導く実務上の推論であり、VLMを使った追試は今後必要です。
よくある誤解

| よくある誤解 | 正確な情報・解釈 |
|---|---|
| 出力を長くすれば必ず少しずつ遅くなる | MPSでは、特定区間で急に遅くなり、その後回復する非単調な結果が観測された |
| KV Cacheが遅延スパイクの唯一の原因である | キャッシュを無効にしても非単調性が残るため、キャッシュだけでは説明できない |
| KV CacheはMPSでは使わない方がよい | 全測定点でキャッシュ有効時の方が速い。異常区間で高速化率が縮むという結果である |
| unified memoryが満杯になっただけである | システムメモリ使用量が高いままでも処理時間が回復し、MPSのメモリ割当量も滑らかに増えた |
| 512トークンを避ければ解決する | 境界はモデル、端末、プロンプト長で動くため、固定値として一般化できない |
| すべてのMac・実行基盤で同じ問題が起きる | 論文が確認したのはM3 Max、M3 Pro上のPyTorch MPSが中心である |
| 原因となるMPS kernelが特定された | APIから見える測定結果が実行レジームを示唆した段階で、kernel単位の原因は未特定である |
| 生成結果も壊れる | 決定的な生成条件ではキャッシュの有効・無効で同じ出力が得られ、主に性能の問題として観測された |
論文の限界と今後の検証

本論文は、見落とされやすい現象を明確な測定で示した点に価値があります。
一方、次の制約があります。
- 中心評価はM3 Maxで、追加再現はM3 Proに限られる
- M1、M2、M4、M5など他世代の境界は未評価である
- モデルはGPT-2系、BLOOM-560M、OPT-350Mが中心で、現在の大規模LLMやVLMは未評価である
- PyTorch MPS内部をkernel単位で追跡した計測がなく、根本原因を確定していない
- MLX、llama.cpp、Ollama、Core MLなど別の実行基盤へ一般化できない
- プロンプト長は3トークンと約65トークンの代表点で、網羅的には測定していない
- ベンチマーク用のプログラムと設定ファイルは、論文公開時に提供予定とされ、v2時点では利用できない
今後は、端末世代、OS、PyTorch、Transformers、モデル構造、データ型、バッチサイズ、プロンプト長、生成長を軸に、条件を組み合わせた再現実験が必要です。
さらにMetal ProfilerやMPS Profilerを使い、異常境界の前後でGPU命令、kernel、メモリ割り当てがどう変わるかを調べることで、実行レジームの正体へ近づけます。
まとめ

本論文は、Apple MPS上の自己回帰decodeで、生成トークン数を増やしても処理時間が一定の割合では増えない現象を報告しました。
GPT-2 Mediumでは512〜624トークン付近に高遅延レジームが現れ、GPT-2 Largeでは前後の正常な設定に対して最大約21倍の遅延が観測されました。
異常は主にdecode段階にあり、複数のモデル系列、M3 MaxとM3 Pro、複数のPyTorch版で定性的に再現されました。
KV Cacheは全体として大きな高速化をもたらしますが、異常区間ではキャッシュ無効時に対する速度比が1.9倍まで縮みました。
キャッシュを無効にしても非単調性は残り、メモリ使用量の増え方と処理時間の回復も一致しないため、どれか1つの要因だけでは説明できません。
Mac上のLLM性能を評価するときは、1つの生成トークン数や平均生成速度だけで判断せず、実運用範囲を細かく測り、prefillとdecode、平均とばらつき、キャッシュの有効・無効、複数の実行基盤を分けて比較することが重要です。
関連技術

| 関連技術 | 本論文とのつながり | 参考情報 |
|---|---|---|
| PyTorch MPS backend | Apple GPU上で今回の現象が観測された実行基盤 | MPS backend – PyTorch |
| Metal Performance Shaders | Apple GPU向けに最適化されたkernel群 | Metal Performance Shaders – Apple |
| KV Cache | 過去tokenのKey・Valueを再利用する推論高速化 | Caching – Hugging Face |
| DynamicCache | Transformersで標準的に使われる動的cache | Cache strategies – Hugging Face |
| FlashAttention | メモリIOを意識してAttentionを高速化する手法 | FlashAttention論文 |
| MPS profiler | MPS kernelの性能を調べるためのPyTorch側の手段 | torch.mps – PyTorch |
次に読むべき記事

- KV Cacheとは?Transformer推論で再計算を減らす仕組み
- PrefillとDecodeの違いとは?LLM推論の待ち時間を分解する
- Apple SiliconでLLMを動かす方法:MPS・MLX・llama.cppの違い
- FlashAttentionとは?AttentionをIO-awareに高速化する仕組み
- LLMベンチマークの測り方:TTFT・TPOT・Throughput・Tail Latency
ローカルLLMを安定して運用するには、「どの端末が平均で速いか」だけでなく、「どの入力条件で実行方式が変わるか」を測る視点が必要です。


コメント