KV 캐시를 RAM으로 오프로드하는 게 생각보다 나쁘지 않을지도
Maybe KV cache offload to RAM isn't bad
핵심 요약
llama.cpp에서 KV 캐시를 RAM으로 오프로드하면 성능 저하를 감수하고 더 큰 컨텍스트 윈도우를 확보할 수 있다는 실험 공유.
- KV 캐시 오프로드 — VRAM 부족 시 RAM으로 캐시를 넘겨 모델 전체를 GPU에 올리는 전략임.
- 성능 트레이드오프 — 약간의 속도 저하가 발생하지만 컨텍스트 윈도우를 2배로 확장할 수 있음.
- 품질 유지 — RAM 오프로드 시 KV 캐시 양자화를 하지 않아도 되어 f16 품질을 그대로 유지함.
- 실제 활용 — 컨텍스트 확보가 절실한 경우 KV 캐시를 줄이는 것보다 RAM 오프로드가 더 효율적임.
llama.cpp에 -nkvo ( --no-kv-offload ) 옵션이 있는데, 이게 KV 캐시를 VRAM 대신 RAM으로 보내버리는 놈임. 당연히 성능 깎아먹으니까 다들 기피하는데, 이유가 다 있지.
근데 세상에 공짜 점심은 없는 법이고, 다 트레이드오프가 있는 거 아니겠냐. 내 경우에는 이게 충분히 해볼 만한 가치가 있다고 본다. 일단 들어봐.
지금 RTX 5060 Ti 16GB에 32GB DDR5 꽂아서 Qwen3.6 27B (IQ4_XS) 돌리는 중임. 65k 컨텍스트 채우려면 KV 캐시를 q4_0으로 양자화하고 GPU에는 레이어 58개만 올려야 함. 이렇게 하면 피크 찍을 때 23 tps 나오고, 긴 문장 뽑아낼 땐 16 tps까지 떨어짐.
llama-server -m Qwen3.6-27B-IQ4_XS.gguf -c 65000 \ -ctk q4_0 -ctv q4_0 -fa on -ngl 58 -np 1 \ --temp 0.6 --top-p 0.95 --top-k 20 --presence-penalty 1.25 \ --min-p 0.0 --chat-template-kwargs '{"preserve_thinking":true}' \ --spec-type draft-mtp --spec-draft-n-max 2
여기서 -nkvo를 추가하면 모델 전체를 GPU에 다 때려 박을 수 있고, KV 캐시도 기본값인 f16으로 쓸 수 있음. 속도는 피크 때 19 tps, 긴 문장 뽑을 땐 14 tps로 좀 줄어들긴 하는데, 이 정도면 나쁘지 않은 거래라고 봄.
llama-server -m Qwen3.6-27B-IQ4_XS.gguf -c 65000 \ -fa on -ngl 99 -nkvo -np 1 \ --temp 0.6 --top-p 0.95 --top-k 20 --presence-penalty 1.25 \ --min-p 0.0 --chat-template-kwargs '{"preserve_thinking":true}' \ --spec-type draft-mtp --spec-draft-n-max 2
재밌는 건, MTP 버전 기준으로 레이어 65개 중 63개만 GPU에 올려도 컨텍스트 윈도우를 128k까지 두 배로 늘릴 수 있다는 거임. 생성 속도도 거의 차이 안 나더라.
llama-server -m Qwen3.6-27B-IQ4_XS.gguf -c 131072 \ -fa on -ngl 63 -nkvo -np 1 \ --temp 0.6 --top-p 0.95 --top-k 20 --presence-penalty 1.25 \ --min-p 0.0 --chat-template-kwargs '{"preserve_thinking":true}' \ --spec-type draft-mtp --spec-draft-n-max 2
RAM으로 오프로드할 때 KV 캐시 양자화해도 딱히 좋아지는 게 없어서, 사실상 f16 퀄리티를 공짜로 챙기는 셈임. 오히려 어떤 경우에는 성능이 더 떨어지기도 하더라.
결론은, 모델 올리려고 억지로 KV 캐시 낮추고 있거나 컨텍스트 윈도우가 더 필요하다 싶으면, 그냥 KV 캐시를 RAM으로 넘겨버리는 게 훨씬 나을 수도 있다는 거임.
