Resonance Lab · W03 Lab Note

想幫 Route A 也拿 Kaggle 排行榜分數,結果一頭撞進 GGUF 記憶體崩潰

Route B 靠著 push 上 Kaggle notebook 拿到了排行榜分數,自然會想:Route A 能不能比照辦理,讓兩條路線在同一個排行榜上公平比較?這篇記錄嘗試的完整過程,以及為什麼最後決定停手。

這篇解什麼問題

同一份 0.885 的分數,能不能在 Kaggle 的排行榜上也拿到驗證——嘗試的過程比結果本身更有意思。

我怎麼做

Route A 本地是用 llama-cpp-python 載入 GGUF 模型跑的,但這是 code competition,重新評分時一律關網路——本地那套「跑的時候即時從 HuggingFace 下載模型」的做法在 Kaggle 上直接行不通,得先把 4.7GB 的 Qwen3-8B-Q4_K_M.gguf 上傳成 Kaggle 私有 Dataset,當離線 kernel input。

接著發現 Kaggle 官方 image 沒有預裝 llama-cpp-python,而且關網路的環境裝不了。改用已經預裝好的 transformers 讀 GGUF,理論上可行,只差一個純 Python 的輔助套件 gguf(118KB,依賴的 numpy、pyyaml、requests、tqdm 全部都已經內建)——包成一個獨立的小 dataset,離線 pip install --no-index 解決。用一個幾秒鐘就跑完的探測 kernel 先驗證這兩步都可行,沒有直接拿完整跑一次的時間去賭。

結果與數據

真正卡住的地方,是 transformers 讀 GGUF 的底層機制:它會把量化過的權重完整解量化成 fp16——8B 參數大約要攤開成 16GB——才搬上 GPU 或 CPU。這一步跟選 GPU 還是 CPU 完全無關,兩邊都得先在 host RAM 把這 16GB 攤開。啟用 GPU 的 kernel 跑到這一步,process 直接被系統砍掉,錯誤是 DeadKernelError: Kernel died——不是可以在程式碼裡接住的 torch.cuda.OutOfMemoryError,研判是 host RAM(不是顯示卡的 VRAM)在解量化當下就爆掉了。這代表原本規劃的「GPU 先試,OOM 就退回 CPU」這道防線根本防不住這種死法——退到 CPU,極可能在同一步用同樣的方式再死一次。

一句話結論

llama.cpp 能在本地又快又省記憶體跑起 8B 模型(296 秒跑完 200 題),關鍵就是它全程保持量化狀態運算、從不整包解量化;transformers 讀 GGUF 這條路徑會直接丟掉這個優勢——Route A 最終維持本地的 0.885,沒有 Kaggle 排行榜分數,這是方法論本身的限制,不是懶得做。