上一篇我們抓到第一個嫌疑犯:
Memory Bandwidth
但 LLM Inference 還有另一個很常見的問題。
有時候模型明明跑得好好的,聊著聊著,顯存卻開始一路往上吃。
甚至同一個模型,剛開始可以跑,Context 一拉長就直接爆顯存。
這次的嫌疑犯就是:
KV Cache
假設我們現在跟模型聊:
我叫小明。
接著再問:
我叫什麼名字?
模型要回答「小明」,當然就得知道前面講過什麼。
問題是,LLM 在產生下一個 Token 時,本來就會參考前面的所有 Token。
如果每產生一個新 Token,都把前面的內容全部重新算一次:
前面 1000 個 Token → 重算 → 產生第 1001 個 Token
下一次:
前面 1001 個 Token → 再重算 → 產生第 1002 個 Token
這樣很快就會慢到不行。
這就是 KV Cache 的用途。
在 Transformer 的 Attention 裡,會產生:
其中前面 Token 的 Key 和 Value,其實算過之後就不用每次全部重算。
所以我們乾脆把它們留下來。
流程就會變成:
Prompt → 計算 K/V → 存進 KV Cache → Decode → 直接讀前面的 KV → 產生下一個 Token
簡單來說就是:
算過的先記起來,下次不要重算。
有點像考試時的計算紙。
前面已經算出來的結果,不會每做到下一題就把整張紙擦掉再算一次。
問題就是:
Cache 要佔記憶體。
而且 Context 越長,需要保存的東西就越多。
可以先簡單想成:
Context 越長 → KV Cache 越大 → 顯存吃得越多
例如:
1000 Tokens → 一小塊 KV Cache
8000 Tokens → 更大一塊 KV Cache
32000 Tokens → 顯存開始有感
如果今天又不是只有一個使用者,而是:
100 個 Request × 每個都有自己的 Context
那 KV Cache 很快就會變成一個非常可怕的顯存黑洞。
很多人第一次估算 LLM 需要多少 VRAM,可能只會看:
這個模型幾 GB?
例如一個量化後的模型可能只需要 10GB。
看起來 24GB 顯存綽綽有餘。
但真的跑起來後,還要塞:
所以:
模型放得進 GPU
不代表:
你的服務就撐得住。
特別是在高併發或 Long Context 的情境下,KV Cache 很容易變成真正的顯存大戶。
因為顯存不是無限的。
如果每個 Request 都隨便佔一大塊空間,很快就會遇到一個問題:
有空間,但不好用。
就像停車場一樣。
你明明還有很多空位,但每台車都亂停,最後可能還是塞不進新的車。
KV Cache 的管理也有類似問題。
怎麼分配?
怎麼回收?
不同長度的 Request 要怎麼放?
怎麼避免浪費一堆顯存?
這些問題,也正是後來 PagedAttention 會出現的原因。
今天先記住:
KV Cache 的目的,是把前面 Token 已經算過的 Key / Value 留下來,避免 Decode 時一直重算。
它可以讓生成快很多。
但代價就是:
吃顯存。
而且 Context 越長、使用者越多,吃得越兇。
所以下一篇,我們就要來看看:
PagedAttention 到底在解決什麼?
為什麼只是「管理 KV Cache 的方式不同」,就能讓 vLLM 變成這麼重要的推論引擎?