重點速覽
硬碟存放模型檔,記憶體(RAM)是載入後的中繼站,顯存(VRAM)放最常被反覆讀取、運算的權重與 KV cache。最理想是全部放進顯存;放不下時,部分層改放系統記憶體並由 CPU 運算,速度會明顯變慢;連記憶體都不夠時,作業系統只能靠硬碟分頁頂著,那時才真的會卡。判斷順序是:先算總需求,再看顯存、記憶體、硬碟依序能接住多少。
很多人買顯示卡之前,只問「顯存多大」;也有人覺得「我記憶體很大,應該什麼模型都能跑」。這兩種想法都只對一半。顯存、記憶體、硬碟在本地大模型裡各自負責不同的工作:硬碟存檔,記憶體當中繼,顯存負責最吃力的運算。這篇文章先帶你走一遍模型從檔案到產生第一個字的旅程,再整理三者的角色比較表,最後給你一套「放不下時怎麼分流」的判斷流程,讓你在看到錯誤訊息或速度變慢時,知道問題出在哪一層。
先把三個詞講清楚:
- 顯存(VRAM):顯示卡自己帶的記憶體,GPU 運算時直接讀寫它。
- 記憶體(RAM):電腦主機板上的系統記憶體,CPU 直接讀寫它。
- 硬碟:長期存放檔案的儲存空間,模型檔平常就躺在這裡。
這裡的「本地大模型」是指在你自己的電腦上執行的大型語言模型(LLM,術語表有簡短說明)。下面的細節,以 llama.cpp 這個常見的本地推論引擎的官方說明為主要依據;其他工具的行為可能不同,但三種儲存各自的角色是相通的。
一個模型從檔案到產生第一個字的旅程
先交代兩個名詞。**權重(weights)**是模型訓練出來的那一大堆數字,決定模型怎麼思考,檔案裡存的主要就是它。GGUF 是 llama.cpp 生態系常用的模型檔格式,官方規格寫明它是「為了用 GGML 及相關執行器推論而存放模型的檔案格式」,並且設計成可以快速載入與儲存,特色之一是相容 mmap,也就是模型可以用 mmap 載入。
整趟旅程可以拆成四站。
第一站:硬碟上的模型檔。 你下載的 GGUF 檔就是權重加上所需的描述資訊(官方規格說明,所有載入模型需要的資訊都在同一個檔案裡)。這個階段它只是檔案,還沒有占用任何顯存。
第二站:載入到記憶體或顯存。 載入模型時,引擎要決定每一塊權重住在哪裡。llama.cpp 預設的載入方式是 mmap(官方說明寫的是 auto:除非裝置不支援,否則使用記憶體映射)。**mmap(memory-map,記憶體映射)**是讓作業系統把檔案對應到程式的記憶體位址,需要的內容才被讀進來,而不是一次先複製一份。被映射的內容由作業系統的分頁快取(page cache)管理;官方在談 NUMA 選項時也順帶說明,當 mmap 的預取與預讀被停用,頁面會改成「第一次存取時才載入,而不是一次全部載入」。
另一個關鍵參數是 GPU 層數。大模型由很多層(layer,一層一層重複的運算區塊)堆疊而成,llama.cpp 用 -ngl(--n-gpu-layers,「最多有多少層存放在顯存」)來決定放多少層上顯示卡,預設值是 auto,也可設為 all。這種「放一部分在顯存、其餘留在系統記憶體」的做法,官方 README 稱為 CPU+GPU 混合推論,用途是「部分加速比顯存總量還大的模型」。
第三站:配置推論時才會用到的空間。 載入權重之外,還要預留兩種空間:KV cache(下一節詳述),以及運算過程需要的暫存緩衝區(官方 fit-params 範例裡稱為 compute)。
第四站:運算並產生第一個字。 引擎讀進你的提示詞,逐層計算,產生第一個 token(術語表:模型處理文字的最小單位)。之後每多生成一個 token,KV cache 就會再長一點。
官方說明中和這段旅程最相關的旗標有這幾個。旗標名稱和預設值會隨版本調整,以官方文件為準,你在較舊的教學裡看到的寫法可能和現行說明不同:
| 旗標(以官方文件為準) | 官方說明的意思 |
|---|---|
-lm, --load-mode | 模型載入模式,預設 auto(用 mmap,除非裝置不支援)。可選 none、mmap、mlock、mmap+mlock、dio |
-ngl, --n-gpu-layers | 最多有幾層存放在顯存,可填數字、auto 或 all,預設 auto |
-c, --ctx-size | 提示詞的上下文(context)大小,預設 0,代表從模型讀取 |
-ctk / -ctv | KV cache 的資料型別(K 與 V),預設 f16 |
-kvo, --kv-offload | 是否讓 KV cache 也卸載到加速裝置,預設啟用 |
-fit, --fit | 是否自動調整未指定的參數,使模型塞進裝置記憶體,預設 on |
載入模式的幾個選項,官方的描述是:mmap 為記憶體映射;mlock 是「鎖定在記憶體中,防止它在被映射時被換出」,可能提升效能,但代價是需要更多 RAM,載入時間也可能變長;none 代表不使用特別的載入模式,載入會較慢,但在不用 mlock 時可能減少分頁換出,而且官方特別提醒:如果模型比全部的 RAM 還大,關掉 mmap 會導致模型根本載不進去。
三種儲存的角色比較表
先看「誰負責什麼」。下表的「相對快慢」與「容量」欄是一般硬體原則的定性描述,不是任何官方說明給的數字;其中「系統記憶體比顯存慢」這點,llama.cpp 多 GPU 說明裡有一句直接的依據(「相對較慢的系統 RAM」)。
| 類別 | 顯存(VRAM) | 系統記憶體(RAM) | 硬碟 |
|---|---|---|---|
| 本地推論裡放什麼 | 優先放權重(-ngl 決定放幾層);預設連 KV cache 與運算緩衝也跟著放這裡 | 放不下顯存的那幾層權重;mmap 讀進來的檔案頁面;CPU 運算要用的資料 | 模型檔本身(GGUF);系統開始分頁時充當溢出空間 |
| 相對速度(一般原則) | 相對最快,GPU 直接存取 | 比顯存慢;CPU 存取 | 相對最慢,通常只在載入或分頁時被讀寫 |
| 容量(一般原則) | 通常最小,換顯示卡才能升級 | 通常中等,可另購加裝 | 通常最大 |
| 用完了會怎樣 | 載入時錯誤(OOM,out of memory,記憶體耗盡);或在 --fit 預設啟用下被自動縮小上下文、把部分層改放別處 | 開啟 mmap 時,系統可能把頁面換出再讀回;關掉 mmap 且模型比 RAM 大時載入失敗 | 檔案放不下,下載或複製失敗,與推論無關 |
| 影響什麼 | 能不能放得下、速度快不快 | 放不下顯存時的接住能力、速度掉多少 | 載入快慢、能存多少模型 |
再看「推論時用到的四樣東西,各自住在哪」。這一張對照官方 fit-params 範例的三欄(model、context、compute)加上檔案本身:
| 東西 | 是什麼 | 預設住在哪(依官方說明) | 隨什麼成長 |
|---|---|---|---|
| 權重 | 模型本體的數字 | 由 -ngl 決定幾層在顯存,其餘在系統記憶體 | 隨模型參數量與量化方式 |
| KV cache | 把已處理過的 token 的中間結果存起來,避免重複計算 | 預設啟用 KV cache 卸載;多卡時第 l 層的 KV cache 放在擁有第 l 層的那張卡 | 隨上下文長度大致成正比 |
| 運算緩衝(compute) | 推論過程的暫存空間 | 同樣計入裝置記憶體 | 隨批次大小等參數 |
| 模型檔 | 硬碟上的 GGUF | 硬碟;載入後(mmap)會有檔案頁面常駐記憶體 | 固定 |
KV cache 的來源,Hugging Face 官方的最佳化教學這樣說:它儲存了所有先前輸入位置、所有層、所有注意力頭的 key/value 向量,因此在長輸入或多輪對話時會變得很占記憶體;該教學也寫明,使用 KV cache 之後,最大所需記憶體隨序列長度是線性成長,而不是平方。教學中的範例模型(bigcode/octocoder)在假設輸入長度 16000 的情況下,KV cache 大約要 15 GB,「約為模型權重本身的一半」。這是該文件的特定範例,不要拿來當作你的模型的數字;估算你自己模型的 KV cache,請看 怎麼依顯存選模型。至於權重為什麼可以縮小成原來的幾分之一,那是 量化 的主題,這裡不重複。
總需求怎麼分配到三種儲存
先把總需求拆成三項。
總需求 ≈ 權重 + KV cache + 額外開銷
權重 :GGUF 檔大小是很好的起點(檔案裡主要就是權重)
KV cache :隨上下文長度(-c)增加,大致成正比
額外開銷 :運算緩衝、作業系統與其他程式要用的空間,要留餘裕
詳細怎麼逐項估算,放在 依顯存選模型+估算方法 那篇;這篇只用它來做分流判斷。下面是判斷流程,從上往下一步一步看:
- 全部放得進顯存嗎? 比較「總需求」與「可用顯存扣掉餘裕」。可以,就全放顯存,這是最快、最單純的情況。官方
--fit的預設餘裕(--fit-target)是每張裝置 1024 MiB,可以當作「別把顯存塞到滿」的參考,旗標細節請以官方說明為準。 - 放不下,先縮小可調的部分。 上下文長度是第一個可以動的,因為 KV cache 跟它成正比。官方 fit-params 範例輸出的順序就是先把上下文從 40960 縮到 4096(
--fit-ctx預設下限 4096),然後才處理層的分配。 - 還放不下,把部分層留在系統記憶體。 這是前面提到的混合推論。引擎會依
-ngl把一部分層放顯存、其餘留在系統記憶體,由 CPU 運算。先確認一件事:系統記憶體放得下剩下的權重,還留得出給作業系統與其他程式。 - 記憶體也不夠,才輪到硬碟。 這時要靠 mmap 讓作業系統用分頁方式頂著。它不是什麼好選擇,下面專門講。
如果是 MoE(混合專家)模型,第 3 步有更細的做法:官方提供 --cpu-moe、--n-cpu-moe 之類的旗標,讓你指定把哪些專家權重留在 CPU;為什麼 MoE 可以這樣拆,請看 MoE 混合專家模型。
示範計算一:官方 fit-params 範例裡的三欄
這是官方說明裡貼出的一段實際輸出(官方範例用的是一張 24GB 等級的顯示卡),這裡只引用其中的數字:
- 可用顯存 24077 MiB(MiB 是 1024×1024 位元組,與 GB 的 10 億位元組不同)。
- 全放顯存的預估需求 61807 MiB,超過可用顯存,所以不行。
- 引擎把上下文從 40960 縮到 4096,輸出寫的是「需要的記憶體總共減少 3456 MiB」。
- 最後的記憶體分解中,裝置上使用 19187 MiB,其中 model(權重)17904、context(KV cache)384、compute(運算緩衝)898。同一段輸出還顯示,其中 34 層的專家(expert)權重被指定放在 CPU 端,也就是系統記憶體。
驗算兩件事(示範計算,前提是 KV cache 與上下文長度成正比):
上下文 4096 時的 KV cache:384 MiB
上下文 40960 時的 KV cache:384 × (40960 ÷ 4096) = 384 × 10 = 3840 MiB
少掉的部分:3840 − 384 = 3456 MiB ← 與官方輸出「減少 3456 MiB」吻合
三欄加總:17904 + 384 + 898 = 19186 MiB ← 官方寫 19187,差 1 是四捨五入
這個例子同時示範了本篇最重要的觀念:權重、KV cache、運算緩衝是三筆分開的帳,而且光看權重(17904)不等於整體占用(19187)。
示範計算二:假設一個密集模型,12 GiB 顯存放不下
下面是自己假設的情境,不是任何實際型號。
假設前提:
- 一個 300 億參數的密集模型(所有參數每次都用,與 MoE 相對)。
- 量化密度比照 llama-bench 官方範例檔:Qwen2.5-7B-Instruct 的 Q4_K_M 檔,官方範例列出 model_size 為 4677120000 位元組、model_n_params 為 7615616512。
- 可用顯存假設 12 GiB;KV cache 假設 1.5 GiB、緩衝與餘裕假設 1 GiB(兩者皆為示範假設值)。
每參數位元數 = 4677120000 × 8 ÷ 7615616512 ≈ 4.91 bit
權重大小 ≈ 30×10^9 × 4.91 ÷ 8 ≈ 18.4×10^9 位元組 ≈ 17.2 GiB
(同樣的 300 億參數若用 FP16:依 Hugging Face 教學的經驗法則「約 2×X GB」,X=30,約 60 GB)
顯存可放權重 = 12 − 1.5 − 1 = 9.5 GiB
放得進顯存的比例 ≈ 9.5 ÷ 17.2 ≈ 55%
需要留在系統記憶體的權重 ≈ 17.2 − 9.5 ≈ 7.7 GiB
這是粗估:各層大小不完全相同、輸入輸出層也要另外考慮,實際分配以引擎報告為準。結論是:這個情境下,大約一半多的權重在顯存,其餘約 7.7 GiB 要在系統記憶體,加上作業系統與其他程式的需求,記憶體要有餘裕。只要系統記憶體接得住,硬碟就不會參與推論。
為什麼放到系統記憶體會變慢,放到硬碟會更慢
系統記憶體為什麼慢。 官方多 GPU 說明講得很直接:模型放不進顯存時,「模型的一部分得在相對較慢的系統 RAM 上執行」;同一份說明在排錯表裡也寫,把 --n-gpu-layers 調低時,「剩下的層會在 CPU 上執行,推論會慢很多」。換句話說,被留在記憶體的那幾層,不只是資料放在比較慢的地方,連運算也是在 CPU 上做,兩件事同時發生。這份說明沒有給具體倍數,本文也不給。
另一個相關的機制是 CUDA 的統一記憶體:llama.cpp 建置說明提到,在 Linux 上設定環境變數 GGML_CUDA_ENABLE_UNIFIED_MEMORY=1,可以讓顯存用盡時改為換到系統 RAM,而不是直接當掉(Windows 上對應的是 NVIDIA 控制面板裡的一個設定)。這是驅動層級的替代方案,不是上面那種「由引擎明確分配層數」的做法,行為差異請以官方說明為準。
硬碟為什麼是最後手段。 回到 mmap:它讓作業系統像用記憶體一樣存取檔案,頁面被讀進 RAM 後可以重複使用。問題出在 RAM 不夠大的時候,系統可能把頁面換出去,之後再讀回來。官方說明的許多選項,正是為了處理這件事:mlock 的用途就是「強制系統把模型留在 RAM,而不是換出或壓縮」;官方載入模式的說明也提到分頁換出(pageouts)是需要留意的事。另外一個例子是 --lazy-mode:官方說明它可以讓某些張量(例如每層的嵌入)「按需從硬碟讀取,而不是常駐」,預設只對大於 4 GiB 的張量啟用,而且需要 mmap。這說明硬碟確實可以成為執行時的資料來源,但官方是把它當作針對特定張量的選項,而不是通用的救急辦法。
至於「這樣到底多慢」:本文引用的官方說明沒有給數字,所以這裡也不寫數字。可以確認的方向是:硬碟是三者中通常最慢的儲存(一般硬體原則),而推論每生成一個 token 都要用到模型的大部分權重,這是密集模型的特性;如果這些權重得靠硬碟反覆讀回,速度就會被硬碟拖住。以上最後這段是根據一般原理做的推論,不是官方說明的原文。想知道你的機器實際會怎樣,要自己量,量法見 Token/s 怎麼看。
我的瓶頸在哪?三種限制的對照
速度不理想時,先分辨是哪一種限制。下面是定性的對照,不含任何數字。其中「頻寬」的說法有部分依據:Hugging Face 教學指出,自迴歸解碼時,大量的 key/value 向量每一步都要重新讀取,所需的記憶體頻寬可能成為嚴重的時間瓶頸;它也提到 Flash Attention 的優勢來自減少對顯存的讀寫,把中間運算留在速度更快的晶片內記憶體(SRAM)裡,也就是說教學是拿顯存和晶片內的 SRAM 相比,才說顯存「較慢」。其餘欄位屬於一般原則。
| 瓶頸類型 | 常見症狀 | 可以怎麼對應 |
|---|---|---|
| 容量不足 | 載入就失敗或報記憶體不足;上下文一拉長就爆;系統整體卡頓、硬碟燈狂閃 | 縮小上下文、改用更小或量化更狠的模型、把部分層改放系統記憶體、補足 RAM |
| 頻寬受限 | 模型已經載入、記憶體也夠,但逐字生成的速度不如預期;上下文越長越明顯 | 縮小上下文、考慮 KV cache 的資料型別(-ctk/-ctv,請以官方說明為準)、盡量讓更多層留在顯存 |
| 運算受限 | 處理長提示詞(預填)特別久;GPU 或 CPU 使用率很高;筆電燙到降頻 | 縮短提示詞、換更小的模型,筆電請看 散熱與電源 |
測量時,llama-bench 把「處理提示詞(pp)」和「生成文字(tg)」分開測,官方說明列出的三種測試是 pp、tg 與兩者合併的 pg。你可以分開看哪一段拖累整體感受,再回到上表對照。
常見誤解
「記憶體很大,就能取代顯存。」 記憶體大解決的是「放不放得下」,不是「跑得快不快」。官方說明把系統 RAM 稱為相對較慢,被留在那邊的層還要由 CPU 運算。所以容量夠只代表模型能載入並運作,不代表速度好。
「硬碟越快越好,所以不用管記憶體。」 快的硬碟可以縮短載入時間,但模型載入後,推論時主要讀寫的是記憶體與顯存。只有在記憶體不足、系統開始用硬碟頂替時,硬碟速度才會變成瓶頸;那是要避免的狀態,而不是靠換快硬碟就能優雅解決的。
「檔案大小就是需要的顯存。」 前面的示範計算一就是反例:權重 17904 MiB,但整體占用是 19187 MiB,還有 KV cache 與運算緩衝。另外要小心單位,4677120000 位元組在不同單位下是不同的數字:
4677120000 ÷ 10^9 ≈ 4.68 GB
4677120000 ÷ 2^30 ≈ 4.36 GiB
下載頁面常顯示 GB,工具回報常用 MiB 或 GiB,比對時要看清楚單位。
用實際工具對照
本站的 Strata vs PolyStrata 一文,列需求時就是把「RAM 加顯存合計」與「硬碟空間」分開列出,正好對應本文的分工:硬碟看模型檔放不放得下,記憶體加顯存看載入與執行放不放得下。選模型、看需求時,用本篇的順序去讀那種規格,比只看某一個數字更準。
延伸閱讀
- 依顯存選模型+估算方法:把總需求公式算到實際數字。
- 量化是什麼:同一個模型為什麼可以變成不同大小的檔案。
- MoE 混合專家模型:為什麼 MoE 可以把部分權重留在 CPU。
- Token/s 怎麼看與正確的速度測試方法:量出你的機器到底慢在哪。
- 筆電跑 AI 的散熱與電源注意事項:運算受限與降頻的實際情況。
- 術語表:token、context window 等名詞的簡短說明,可從 context window 開始。
常見問題
本地跑大模型,顯存、記憶體、硬碟哪個最重要?
以能不能跑得順來看,顯存最重要,因為能放進顯存的部分最不會拖慢速度。記憶體決定放不下顯存的部分有沒有地方接,硬碟則主要影響模型檔的存放與載入。三者分工不同,缺哪一個的症狀也不一樣。
顯存不夠,用記憶體補可以嗎?
可以。llama.cpp 官方說明有提到 CPU+GPU 混合推論,用來部分加速比顯存還大的模型。但官方也把系統記憶體稱為相對較慢,放到那邊的層會在 CPU 上執行,整體速度會下降。
模型檔案有多大,就需要多少顯存嗎?
不是。檔案大小只是權重的部分,執行時還要加上 KV cache(隨上下文長度成長)和運算用的緩衝區。官方 fit-params 範例裡,這三項是分開列出的。
硬碟換成更快的 SSD,推論會變快嗎?
主要會讓載入模型的時間縮短。模型載入完成並常駐在記憶體或顯存之後,推論時主要讀寫的是記憶體與顯存。只有在記憶體不足、系統開始用硬碟分頁頂替的時候,硬碟速度才會直接影響生成速度。
什麼是 mmap?要不要關掉?
mmap(記憶體映射)是讓作業系統把模型檔對應到記憶體位址、需要時再讀入的載入方式,llama.cpp 預設會使用。官方說明指出關閉它會讓載入較慢,但在不使用 mlock 時可能減少分頁換出;模型比 RAM 大時關掉 mmap 甚至會完全載不進去。要不要調整請以官方說明為準,一般人維持預設即可。
留言
用 GitHub 帳號登入就能留言,留言會公開顯示在 GitHub Discussions。留言前請先看社群規則。