กลับไปที่บล็อก

การแก้ไขปัญหาคู่มือ

llama.cpp ประมวลผลพรอมป์ช้าลง 35 เท่า? แก้ KV cache q5_1

Flash attention บวก KV cache q5_1 อาจดัน attention ไปที่ CPU วิธีตรวจสอบ แก้ด้วย q8_0 และเมื่อใดที่ API ง่ายกว่า

โดย CheapTokens Teamเผยแพร่เมื่อ ใช้เวลาอ่าน 6 นาที

Terminal แสดง GPU ที่ 0 เปอร์เซ็นต์และ CPU ที่ 930 เปอร์เซ็นต์ระหว่างการประมวลผลพรอมป์ของ llama.cpp
ในหน้านี้
  1. หน้าตาบนหน้าจอ
  2. ทำไมแคชที่เล็กกว่าจึงช้าลงมากขนาดนี้
  3. ตรวจสอบในสองนาที
  4. วิธีแก้ 1: ใช้ q8_0 (หรือรีบิลด์)
  5. เมื่อการจูนไม่คุ้มอีกต่อไป
  6. ลำดับที่ควรทำ

โมเดลโลคอลของคุณตอบได้ดี แต่ทุกพรอมป์ยาวตอนนี้ต้องรอเป็นนาทีครึ่งในขณะที่ GPU ไม่ได้ทำอะไรเลย ถ้าคุณรัน llama.cpp ด้วย -fa on และ KV cache แบบ q5_1 นั่นน่าจะเป็นสาเหตุ: บิลด์ CUDA เริ่มต้นไม่มีเคอร์เนล flash-attention สำหรับแคชประเภทนั้น ขั้นตอน attention จึงไปรันบน CPU อย่างเงียบ ๆ การเปลี่ยนแคชเป็น q8_0 ทำให้ผู้รายงานคนหนึ่งได้จาก 38 เป็น 1348 tokens/s ในการประมวลผลพรอมป์

ตัวเลขด้านล่างมาจาก llama.cpp issue #28455 (เปิดเมื่อ 5 กันยายน 2026, บิลด์ 10791, ตรวจสอบเมื่อ 28 ตุลาคม 2026) ผู้รายงานหนึ่งคน, RTX 4080 หนึ่งตัว, โมเดล 27B หนึ่งตัว ดังนั้นอ่านเป็นตัวอย่างที่ทำจริง ไม่ใช่กฎตายตัว การวิเคราะห์สาเหตุรากก็เป็นของพวกเขาเอง: ผู้ดูแลเรียกว่า "known issue" และปิด issue ในวันถัดมา

หน้าตาบนหน้าจอ#

การตั้งค่าเป็นเรื่องปกติ มีคนต้องการคอนเท็กซ์ 131072 โทเคนบนการ์ด 16 GB ใบเดียว จึงลด KV cache ลงเป็น q5_1:

bash
llama-server -m model.gguf -ngl 99 -fa on -c 131072 -np 4 \
  --cache-type-k q5_1 --cache-type-v q5_1

จากนั้นส่งพรอมป์ 3.6K โทเคน การประมวลผลพรอมป์รันที่ 38.4 tokens/s และ decoding ที่ 6.5 tokens/s ลองหารดู: 3,600 ÷ 38.4 = 93.75 ดังนั้นประมาณ 94 วินาทีก่อนคำแรก ด้วย q8_0 พรอมป์เดียวกันรันที่ 1348 tokens/s: 3,600 ÷ 1,348 = 2.67 ต่ำกว่าสามวินาที

จุดสังเกตอยู่ที่ task manager ระหว่างการรันที่ช้า GPU อยู่ที่เกือบ 0% ขณะที่ CPU แสดงประมาณ 930% (เก้าหรือสิบคอร์กำลังทำงาน) GPU ที่ว่างเปล่าขณะที่คุณ "รันบน GPU" คืออาการที่ต้องมองหา

ความเร็วการประมวลผลพรอมป์ด้วย KV cache q5_1 และ q8_0
Prompt eval บนพรอมป์ 3.6K โทเคน, RTX 4080, llama.cpp issue #28455 (5 กันยายน 2026)

ทำไมแคชที่เล็กกว่าจึงช้าลงมากขนาดนี้#

Flash attention เป็นเคอร์เนล GPU แบบ fused บิลด์ CUDA เริ่มต้นมาพร้อมกับมันเฉพาะบางคู่ของประเภท KV cache สำหรับ q4_0, q4_1, q5_0 และ q5_1 ไม่มีเคอร์เนล ดังนั้น llama.cpp จึงไม่หยุดด้วยข้อผิดพลาด มันย้ายการดำเนินการนั้นไปที่ CPU แล้วทำต่อ ทุกอย่างยังทำงานได้ แค่ช้ากว่าประมาณ 35 เท่าในการประมวลผลพรอมป์ (1348 ÷ 38.4 = 35.1)

คำว่า "เงียบ ๆ" นั่นแหละคือปัญหาทั้งหมด ไม่มีอะไรในคำตอบบอกคุณ การประมวลผลพรอมป์ลดลงมากที่สุด (ประมาณ 35×) และการสร้างก็ช้าลงด้วย: 6.5 tokens/s เทียบกับ 30.1 ด้วย q8_0 ใน issue เดียวกัน

ตรวจสอบในสองนาที#

รัน llama-bench ด้วยประเภทแคชเดียวกับที่คุณใช้ในเซิร์ฟเวอร์ ครั้งละหนึ่งแบบ และดู GPU ในอีก terminal หนึ่ง:

bash
llama-bench -m model.gguf -ngl 99 -fa 1 -ctk q8_0 -ctv q8_0 -p 512 -n 0
llama-bench -m model.gguf -ngl 99 -fa 1 -ctk q5_1 -ctv q5_1 -p 512 -n 0
nvidia-smi -l 1

ผลลัพธ์ pp512 ของผู้รายงานบน Qwen 27B Q5_K_XL: 1511.92 tokens/s สำหรับ q8_0/q8_0, ประมาณ 197 สำหรับ q5_1/q5_1 บนบิลด์เริ่มต้น ถ้าสองบรรทัดของคุณแสดงช่องว่างแบบนั้นและ nvidia-smi แสดงว่า GPU ว่างระหว่างบรรทัดที่สอง คุณเจอแล้ว

ก่อนจะแก้ไขอะไร จับคู่สิ่งที่เห็นกับสาเหตุที่เป็นไปได้:

จับคู่

จับคู่อาการแต่ละอย่างกับสาเหตุ

  • GPU ที่ ~0%, CPU ที่ ~930% ระหว่างพรอมป์ยาวAttention รันบน CPU
  • Decoding ลดลงเหลือ ~6.5 tokens/s เทียบกับ 30.1 ด้วย q8_0การสร้างก็ช้าลง ไม่ใช่แค่การประมวลผลพรอมป์
  • แฟล็กเดียวกันเร็วด้วย q8_0คู่ประเภทแคชนี้ไม่มีเคอร์เนล GPU flash-attention ในบิลด์เริ่มต้น

วิธีแก้ 1: ใช้ q8_0 (หรือรีบิลด์)#

วิธีแก้ที่เร็วที่สุดคือเปลี่ยนสองแฟล็กและเก็บอย่างอื่นไว้เหมือนเดิม:

bash
llama-server -m model.gguf -ngl 99 -fa on -c 131072 -np 4 \
  --cache-type-k q8_0 --cache-type-v q8_0

ใน issue นี้ให้ 1348 tokens/s ในการประมวลผลพรอมป์และ 30.1 tokens/s ในการ decoding (เพิ่มจาก 6.5) ราคาที่ต้องจ่ายคือหน่วยความจำ: แคช q8_0 ใหญ่กว่า q5_1 ดังนั้นตรวจสอบว่าความยาวคอนเท็กซ์ของคุณยังพอดีใน VRAM

ถ้าคุณจำเป็นต้องเก็บ q5_1 ไว้ด้วยเหตุผลด้านหน่วยความจำ ให้รีบิลด์โดยคอมไพล์ทุกชุดค่าผสมของแคช flash-attention ไว้:

bash
cmake -B build -DGGML_CUDA=ON -DGGML_CUDA_FA_ALL_QUANTS=ON
cmake --build build --config Release -j

บิลด์นั้นรัน q5_1 ที่ 1509.70 tokens/s บน pp512 และ 1162 tokens/s บนพรอมป์ 3.6K โทเคน โดย decoding ที่ 38.5 tokens/s มีผู้แสดงความคิดเห็นใน issue ชี้ว่าการย้ายงานระหว่างแบ็กเอนด์อาจเปลี่ยนผลลัพธ์เชิงตัวเลขเล็กน้อย และแนะนำให้เปรียบเทียบ perplexity ระหว่างบิลด์ ถ้าคุณใส่ใจผลลัพธ์ที่ตรงเป๊ะ ให้รันสักครั้ง

เปรียบเทียบ

วิธีแก้ไหนเหมาะกับการ์ดของคุณ?

แคช q8_0

เปลี่ยน --cache-type-k และ --cache-type-v เป็น q8_0 ไม่ต้องรีบิลด์ ใช้ VRAM มากกว่า q5_1 ดังนั้นตรวจสอบขนาดคอนเท็กซ์ที่ใส่ได้อีกครั้ง

รีบิลด์ด้วย FA_ALL_QUANTS

เก็บ q5_1 ไว้และบิลด์ด้วย -DGGML_CUDA_FA_ALL_QUANTS=ON VRAM เท่าเดิม แต่คุณต้องดูแลบิลด์เองและคอมไพล์นานขึ้น

คำตอบ "known issue" ของผู้ดูแลไม่ได้บอกว่าเวอร์ชัน llama.cpp ปัจจุบันเปลี่ยนเรื่องนี้หรือไม่ การตรวจสอบที่ซื่อตรงคือคู่ llama-bench ด้านบน: ถ้าทั้งสองบรรทัดใกล้กัน คุณก็สบายใจได้

เมื่อการจูนไม่คุ้มอีกต่อไป#

สมมติคุณแก้ได้แล้ว และตอนนี้กำลังชั่งน้ำหนักรอบถัดไป: แฟล็กเพิ่ม, GPU ตัวที่สอง, quant ที่เล็กลง ถ้างานคือสรุป รีวิวโค้ด หรือสกัดข้อมูลบนพรอมป์ไม่กี่พันโทเคน ให้ถามว่าคำขอหนึ่งครั้งกินเวลาและแรงคุณเท่าไร ไม่ใช่แค่กินวัตต์

นี่คือเวิร์กโหลดที่ระบุไว้เพื่อเปรียบเทียบ สมมติงานสรุปส่ง 3,600 โทเคนอินพุตและได้กลับมา 500 โทเคน 1,000 ครั้ง บน CheapTokens นั่นประมาณ $0.104 บน DeepSeek-V4-Flash (คอนเท็กซ์ 380K, เอาต์พุตสูงสุด 32,768 โทเคนต่อคำตอบ, ราคาเดียวทุกชั่วโมง) และประมาณ $0.092 บน GLM-5.3-Flash (คอนเท็กซ์ 390K) ตารางนับอินพุตและเอาต์พุตรวมกัน พร้อมคอลัมน์ OpenRouter เพื่อเปรียบเทียบ:

โมเดล ต่อคำขอ 1,000 คำขอ OpenRouter, 1,000 คำขอ
GLM-5.3-Flash $0.000092 $0.092 $0.187
DeepSeek-V4-Flash $0.0001 $0.104 $0.249
MiniMax-M2.7 $0.00026 $0.255 $1.68

3,600 โทเค็นอินพุตและ 500 โทเค็นเอาต์พุตต่อคำขอ ราคาต่อ 1M โทเค็นเป็นราคาปัจจุบันและเปลี่ยนแปลงไปพร้อมกับอัตราค่าบริการของเรา คอลัมน์ OpenRouter แสดงราคาอ้างอิงสำหรับปริมาณงานเดียวกัน

API ไม่สนใจประเภทแคช, VRAM หรือแฟล็กบิลด์ของคุณ ไม่มีอะไรต้องตกไปที่ CPU ส่งพรอมป์จริงของคุณสักสองสามอันก่อนแล้วตัดสินคำตอบด้วยตัวเอง ขั้นตอนเล็กมาก: endpoint พูดรูปแบบ OpenAI Chat Completions ดังนั้นไคลเอนต์โลคอลส่วนใหญ่แค่ต้องเปลี่ยน base URL

bash
curl https://api.cheaptokens.dev/v1/chat/completions \
  -H "Authorization: Bearer $CHEAPTOKENS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "deepseek-ai/DeepSeek-V4-Flash-0731", "messages": [{"role": "user", "content": "Summarize the text below in 5 bullets: ..."}], "max_tokens": 500}'

การตั้งค่าทั้งหมดอยู่ใน เอกสาร CheapTokens และราคาต่อโมเดลปัจจุบันอยู่ที่ หน้าราคา สำหรับมุมมองที่ยาวขึ้นเกี่ยวกับฮาร์ดแวร์เทียบกับ API ดู Run DeepSeek locally or use an API ถ้าคุณอยากเห็นว่าอินพุตและเอาต์พุตคิดเงินแยกกันอย่างไร input vs output tokens ครอบคลุมเรื่องนี้

ลำดับที่ควรทำ#

เรียงลำดับ

เรียงขั้นตอนการแก้ปัญหา

  1. รัน llama-bench สำหรับ q8_0 และ q5_1 แล้วดู nvidia-smi
  2. เปลี่ยนประเภทแคชทั้งสองเป็น q8_0
  3. ตรวจสอบว่าความยาวคอนเท็กซ์ยังพอดีใน VRAM
  4. รีบิลด์ด้วย GGML_CUDA_FA_ALL_QUANTS=ON เฉพาะเมื่อคุณต้องการ q5_1
  5. เปรียบเทียบพรอมป์เดียวกันบน API ถ้าการตั้งค่าโลคอลยังไม่คุ้ม esfuerzo

ข้อควรระวังอีกอย่างเกี่ยวกับแหล่งข้อมูล: การวินิจฉัยทั้งหมดอาศัย issue สาธารณะหนึ่งอันและ GPU หนึ่งตัว มอง 1348 และ 38.4 เป็นสิ่งที่เกิดขึ้นที่นั่น และวัดการ์ดของคุณเองก่อนจะเชื่อตัวใดตัวหนึ่ง