SSD Nodes Learn 🎉 VPS เริ่ม $5.50/เดือน
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-13

เปรียบเทียบ Ollama Quantization: q4_K_M, q8_0 และ fp16

เลือกขนาดโมเดล Ollama ให้เหมาะกับ RAM ด้วยการเปรียบเทียบเชิงตัวเลขระหว่าง q4_K_M, q8_0 และ fp16 เจาะลึกความต่างของความแม่นยำและประสิทธิภาพที่คุณต้องรู้ก่อนเริ่มดาวน์โหลด

การเปลี่ยนแปลงของ quantization ใน Ollama

การทำ quantization ใน Ollama คือการจัดเก็บน้ำหนัก (weight) แต่ละตัวในโมเดลด้วยจำนวนบิตที่น้อยลงกว่าไฟล์ที่ใช้ฝึกสอนมา แท็กที่ลงท้ายด้วย q4_K_M จะเก็บข้อมูลประมาณ 4 บิตต่อน้ำหนัก ในขณะที่ fp16 จะเก็บ 16 บิต ส่งผลให้ขนาดไฟล์ดาวน์โหลดลดลงเหลือประมาณหนึ่งในสี่ และเครื่องอ่านข้อมูลน้อยลงหนึ่งในสี่เท่าเพื่อสร้างแต่ละ token น้ำหนักจะถูกปัดเศษลงบนตารางที่หยาบขึ้น ไม่ได้ถูกตัดทิ้งไป และที่ระดับ 4 บิต โมเดลส่วนใหญ่ยังคงให้คำตอบใกล้เคียงกับระดับความแม่นยำเต็มรูปแบบ

นี่คือข้อแลกเปลี่ยนทั้งหมด: การใช้หน่วยความจำที่น้อยลงมากและความเร็วในการสร้าง token ที่เพิ่มขึ้น โดยแลกกับความแม่นยำที่ลดลงเพียงเล็กน้อย เนื้อหาต่อไปนี้จะอธิบายวิธีคาดการณ์ผลลัพธ์ทั้งสองด้านสำหรับโมเดลเฉพาะบนเครื่องเฉพาะ ก่อนที่คุณจะเสียเวลา 20 นาทีในการดาวน์โหลดไฟล์ที่ไม่สามารถใช้งานได้

หาก Ollama ยังไม่ทำงาน ให้เริ่มต้นด้วย การติดตั้ง Ollama บน VPS หน้าเว็บนี้อนุมานว่า ollama ls ทำงานได้เรียบร้อยแล้ว

วิธีอ่านแท็กการทำ quantization ของ Ollama เช่น q4_K_M

โมเดลในเครื่องจะถูกจัดส่งในรูปแบบไฟล์ GGUF ซึ่งเป็นฟอร์แมตที่ llama.cpp ใช้สำหรับจัดเก็บค่าน้ำหนัก (weights) ลงบนดิสก์ เนื่องจาก Ollama ถูกสร้างขึ้นบนพื้นฐานของ llama.cpp แท็กของ Ollama จึงใช้ชื่อการทำ quantization เดียวกับของ llama.cpp โดยไม่มีการเปลี่ยนแปลง

ตัวเลขคือความกว้างเป้าหมาย (target width) q4 หมายความว่า tensor ของค่าน้ำหนักส่วนใหญ่ถูกบีบอัดไว้ที่ 4 บิตต่อค่า q8 หมายถึง 8 บิต ส่วน fp16 คือการไม่ทำ quantization เลย ซึ่งก็คือโมเดลที่ความละเอียด 16 บิตแบบ floating point อันเป็นความละเอียดที่โมเดลส่วนใหญ่ถูกเผยแพร่ออกมา

K เป็นเครื่องหมายระบุ K-quant ค่าน้ำหนักจะถูกจัดกลุ่มเป็นบล็อกขนาดเล็ก และแต่ละบล็อกจะเก็บค่าสเกลของตัวเองไว้ข้างๆ ค่าที่ถูกบีบอัด บล็อกที่ค่าน้ำหนักทั้งหมดอยู่ใกล้ 0.01 จะได้รับค่าสเกลที่ละเอียด ส่วนบล็อกที่มีค่าผิดปกติ (outlier) ขนาดใหญ่หนึ่งค่าจะได้รับค่าสเกลที่หยาบกว่า ค่าสเกลต่อบล็อกเหล่านี้คือสิ่งที่ทำให้ไฟล์ขนาด 4 บิตยังคงใช้งานได้ และยังเป็นเหตุผลว่าทำไมไฟล์ขนาด 4 บิตจึงไม่ได้มีขนาด 4 บิตต่อค่าน้ำหนักอย่างแท้จริง

ตัวอักษรตัวสุดท้ายคือส่วนผสม (mixture) S, M และ L เป็นตัวกำหนดจำนวน tensor ที่จะถูกปรับความกว้างให้สูงกว่าเป้าหมาย ใน q4_K_M tensor ที่ได้รับผลกระทบมากที่สุดจากการปัดเศษจะถูกจัดเก็บด้วยความกว้างที่มากกว่า ในขณะที่ส่วนใหญ่ยังคงอยู่ที่ 4 บิต นี่คือเหตุผลที่ q4_K_M ให้ผลลัพธ์ที่ดีกว่า q4_0 แบบเดิมในขณะที่มีขนาดไฟล์ใกล้เคียงกัน

ให้ตรวจสอบกับ Ollama ว่ามีไฟล์อะไรอยู่ในดิสก์ แทนการคาดเดาจากชื่อที่คุณพิมพ์:

ollama pull qwen3:8b-q4_K_M
ollama show qwen3:8b-q4_K_M

ollama show จะแสดง architecture, parameters, quantization, context length และ embedding length บรรทัด quantization คือข้อมูลจริงสำหรับโมเดลที่คุณดึงมาเมื่อหลายเดือนก่อนและจำไม่ได้แล้วว่าเลือกเวอร์ชันไหนไว้

จำนวนบิตต่อค่าน้ำหนักคือที่มาของขนาดไฟล์

การประมาณขนาดไฟล์ทุกครั้งเริ่มต้นจากตัวเลขเดียว คือจำนวนบิตที่รูปแบบไฟล์ใช้ต่อค่าน้ำหนักหนึ่งค่า โดยคำนวณเป็นค่าเฉลี่ยตลอดทั้งไฟล์ llama.cpp ได้เผยแพร่ตัวเลขที่วัดได้สำหรับ Llama 3.1 8B ไว้ในเอกสารประกอบการทำ quantize ซึ่งตัวเลขเหล่านี้สามารถนำไปประยุกต์ใช้กับโมเดลแบบ dense ที่มีโครงสร้างใกล้เคียงกันได้เป็นอย่างดี

ChartGGUF quantization types measured on Llama 3.1 8B (published llama.cpp figures)
The data behind this chart
[
  {
    "label": "F16",
    "bits_per_weight": 16,
    "file_gib": 14.96
  },
  {
    "label": "Q8_0",
    "bits_per_weight": 8.5,
    "file_gib": 7.95
  },
  {
    "label": "Q6_K",
    "bits_per_weight": 6.56,
    "file_gib": 6.14
  },
  {
    "label": "Q5_K_M",
    "bits_per_weight": 5.7,
    "file_gib": 5.33
  },
  {
    "label": "Q4_K_M",
    "bits_per_weight": 4.89,
    "file_gib": 4.58
  },
  {
    "label": "Q3_K_M",
    "bits_per_weight": 3.99,
    "file_gib": 3.74
  }
]

สิ่งที่น่าประหลาดใจในตารางนั้นคือคอลัมน์ที่สอง Q4_K_M ไม่ได้ใช้สี่บิตต่อค่าน้ำหนัก แต่มีค่าการวัดอยู่ที่ 4.89 บิต เนื่องจากทั้งการปรับสเกลของบล็อก (block scales) และเทนเซอร์ที่ถูกยกระดับ (promoted tensors) ต่างก็ใช้พื้นที่จัดเก็บจริง ส่วน Q8_0 นั้นมีค่าการวัดอยู่ที่ 8.5 บิต แทนที่จะเป็นแปดบิตด้วยเหตุผลเดียวกัน หากใช้ตัวเลขที่วัดได้จริงนี้ในการคำนวณ ผลลัพธ์ที่ได้จะคลาดเคลื่อนจากขนาดไฟล์จริงเพียงไม่กี่เปอร์เซ็นต์เท่านั้น:

weight bytes = parameter count x bits per weight / 8
8.03e9 params x 4.89 bits / 8 = 4.91e9 bytes = 4.57 GiB

นั่นคือไฟล์ Q4_K_M ขนาด 4.58 GiB ซึ่งคำนวณกลับมาจากตัวเลขสองค่า และยังเป็นขนาดหน่วยความจำที่ค่าน้ำหนักเหล่านั้นใช้เมื่อโหลดเข้าสู่ระบบอีกด้วย Ollama ไม่มีการแตกไฟล์ใดๆ ในขณะโหลด ค่าน้ำหนักที่ผ่านการทำ quantize จะถูกเก็บไว้ในหน่วยความจำในรูปแบบที่ถูกบีบอัดเช่นเดิม และแต่ละบล็อกจะถูกแปลงในขณะที่ถูกเรียกใช้งานเท่านั้น

สิ่งที่ Ollama จัดส่งจริงสำหรับโมเดลแต่ละขนาด

ไลบรารีจะเผยแพร่แท็ก q4_K_M, q8_0 และ fp16 สำหรับโมเดลส่วนใหญ่ นี่คือขนาดของ Qwen3 ณ เดือนสิงหาคม 2026 ซึ่งอ่านจากรายการแท็กบนหน้าโมเดล

ChartDownload size of Qwen3 tags in the Ollama library, GB
The data behind this chart
[
  {
    "label": "Qwen3 4B",
    "q4_K_M_gb": 2.6,
    "q8_0_gb": 4.4,
    "fp16_gb": 8.1
  },
  {
    "label": "Qwen3 8B",
    "q4_K_M_gb": 5.2,
    "q8_0_gb": 8.9,
    "fp16_gb": 16
  },
  {
    "label": "Qwen3 14B",
    "q4_K_M_gb": 9.3,
    "q8_0_gb": 16,
    "fp16_gb": 30
  },
  {
    "label": "Qwen3 32B",
    "q4_K_M_gb": 20,
    "q8_0_gb": 35,
    "fp16_gb": 66
  }
]

แท็กเริ่มต้นมีความสำคัญในที่นี้ ollama pull qwen3:8b จะดาวน์โหลดไฟล์ขนาด 5.2 GB เท่ากันทุกประการกับ ollama pull qwen3:8b-q4_K_M เนื่องจากแท็กที่ไม่มีส่วนต่อท้ายนั้นคือ build แบบ q4_K_M โดยตรง q4_K_M ไม่ใช่การประนีประนอมที่ไลบรารีเสนอให้แบบไม่เต็มใจ แต่เป็นค่าเริ่มต้นที่ต้นทางเลือกมา ดังนั้นการใช้ค่านี้จึงเป็นการเริ่มต้นที่สมเหตุสมผลที่สุดสำหรับโมเดลใดก็ตามที่คุณยังไม่ได้ทดสอบด้วยตนเอง เหตุผลเดียวกันนี้เป็นตัวกำหนดการเลือกแท็กใน การรัน Qwen 3 บน VPS

อัตราส่วนเหล่านี้คงที่ในทุกแถว การเปลี่ยนจาก q4_K_M ไปเป็น q8_0 มีค่าใช้จ่ายเพิ่มขึ้นประมาณร้อยละเจ็ดสิบ แทนที่จะเพิ่มขึ้นเป็นสองเท่าพอดี เนื่องจาก embedding และ output tensor ไม่ได้ขยายขนาดในลักษณะเดียวกับส่วนที่เหลือ fp16 มีขนาดใหญ่กว่า q4_K_M ประมาณสามเท่า โมเดลขนาด 32B ที่ q4_K_M จะมีน้ำหนักไฟล์ 20 GB ซึ่งเกินกว่าที่เครื่องขนาด 16 GB จะรองรับได้หากมีการใช้ context window ใดๆ ก็ตาม สำหรับมุมมองที่กว้างขึ้นว่าโมเดลใดเหมาะกับเครื่องประเภทไหน โปรดดู โมเดลที่คุณสามารถ self-host ได้

เหตุใด KV cache จึงเป็นต้นทุนส่วนที่สองที่ขึ้นอยู่กับบริบท

Weights คือต้นทุนคงที่ ส่วน KV cache (key and value cache) คือต้นทุนผันแปร ทุก token ใน context window จะเก็บ vector ของ key และ value ไว้ในทุก layer ดังนั้น cache จะขยายตัวเป็นเส้นตรงตามขนาด window ที่คุณกำหนด โดยระบบจะจัดสรรหน่วยความจำสำหรับ window ทั้งหมดตั้งแต่ตอนโหลดโมเดล ไม่ใช่ค่อยๆ จัดสรรตามความยาวของบทสนทนา นี่คือเหตุผลว่าทำไม window ขนาดใหญ่จึงกินหน่วยความจำแม้คุณจะส่งคำสั่งเพียงคำเดียวก็ตาม

KV bytes per token = 2 (key and value) x layers x kv_heads x head_dim x bytes_per_element
Qwen3 8B at f16:  2 x 36 x 8 x 128 x 2 = 147456 bytes = 144 KiB per token

ตัวเลขของโมเดลเหล่านี้มาจาก configuration ของโมเดลเอง ได้แก่ 36 layers, 8 key/value heads และ head dimension ขนาด 128 โดย ollama show จะระบุสถาปัตยกรรมและจำนวน parameter ให้คุณ ส่วน config.json ของโมเดลบน Hugging Face จะให้ข้อมูลส่วนที่เหลือ ให้นำต้นทุนต่อ token คูณด้วยขนาด window แล้วคุณจะพบว่า cache ไม่ใช่ค่าที่ปัดเศษทิ้งได้อีกต่อไป

Chartqwen3:8b-q4_K_M: KV cache and floor RAM by context length, GB
The data behind this chart
[
  {
    "label": "4k",
    "kv_cache_gb": 0.6,
    "floor_ram_gb": 5.8
  },
  {
    "label": "8k",
    "kv_cache_gb": 1.21,
    "floor_ram_gb": 6.4
  },
  {
    "label": "16k",
    "kv_cache_gb": 2.42,
    "floor_ram_gb": 7.6
  },
  {
    "label": "32k",
    "kv_cache_gb": 4.83,
    "floor_ram_gb": 10
  }
]

ที่ค่า default window ของ Ollama คือ 4096 tokens ตัว cache จะเพิ่มหน่วยความจำอีก 0.6 GB นอกเหนือจากตัว weights หากเพิ่ม window เป็น 32k ตัว cache เพียงอย่างเดียวจะสูงถึง 4.83 GB ซึ่งเกือบเท่ากับหน่วยความจำที่ใช้สำหรับ quantized weights และค่าต่ำสุดของหน่วยความจำสำหรับโมเดลทั้งหมดจะกลายเป็น 10 GB ที่เรียกว่าค่าต่ำสุดเพราะยังมี compute buffers และระบบปฏิบัติการที่ต้องใช้หน่วยความจำเพิ่มขึ้นไปอีก ให้ตรวจสอบตัวเลขจริงจากคอลัมน์ SIZE ของ ollama ps หลังจากโหลดโมเดลแล้ว

การตั้งค่า window จะทำที่ฝั่งเซิร์ฟเวอร์ ไม่ใช่ต่อคำขอ (request) เมื่อคุณรัน Ollama ในฐานะ service:

OLLAMA_CONTEXT_LENGTH=8192 ollama serve

สำหรับการติดตั้งแบบ systemd ให้ใส่ไว้ใน drop-in file แทน:

sudo systemctl edit ollama
[Service]
Environment="OLLAMA_CONTEXT_LENGTH=8192"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"

รีสตาร์ทด้วย sudo systemctl restart ollama จากนั้นตรวจสอบคอลัมน์ CONTEXT ของ ollama ps เพื่อยืนยันขนาด window ที่โมเดลกำลังรันอยู่จริงๆ OLLAMA_KV_CACHE_TYPE สามารถทำ quantization ให้กับตัว cache เองได้ โดย f16 คือค่า default ส่วน q8_0 จะใช้หน่วยความจำประมาณครึ่งหนึ่งของ f16 และ q4_0 จะใช้ประมาณหนึ่งในสี่ นี่เป็นตัวเลือกแบบ global ดังนั้นทุกโมเดลบนเซิร์ฟเวอร์นั้นจะถูกจัดการด้วยวิธีเดียวกัน บนเครื่องที่มีทรัพยากรจำกัดแต่ต้องการใช้ window ขนาดใหญ่ การลดขนาด cache ลงครึ่งหนึ่งจะช่วยคืนหน่วยความจำได้มากกว่าการปรับแต่งส่วนอื่นใด การตั้งค่า num_ctx และต้นทุนที่เกี่ยวข้อง จะอธิบายรายละเอียดเกี่ยวกับตัว window เอง

สิ่งที่สามารถรันได้บน VPS ขนาด 8, 16 หรือ 32 GB

ให้พิจารณาน้ำหนักของโมเดล (weights) รวมกับ KV cache และเผื่อพื้นที่สำหรับระบบปฏิบัติการและโปรเซสอื่นๆ ที่ทำงานอยู่ การเผื่อพื้นที่ไว้ 2 GB ถือว่าเพียงพอสำหรับการใช้งานบน VPS ขนาดเล็ก

8 GB. โมเดลขนาด 4B ที่ระดับ q4_K_M ใช้พื้นที่ 2.6 GB ซึ่งเหลือพื้นที่เพียงพอสำหรับ context window ขนาดใหญ่ โมเดลขนาด 8B ที่ระดับ q4_K_M สามารถรันได้ด้วย context window เริ่มต้นที่ 4k โดยมีพื้นที่เหลือเพียงเล็กน้อย ไม่แนะนำให้รันโมเดล 8B ด้วย context window ขนาด 32k เนื่องจากค่าพื้นฐานของ 10 GB จะเกินขีดจำกัดของเครื่อง

16 GB. โมเดลขนาด 8B ที่ระดับ q4_K_M พร้อม context window ขนาด 16k หรือ 32k สามารถทำงานได้อย่างราบรื่น โมเดลขนาด 14B ที่ระดับ q4_K_M ใช้น้ำหนัก 9.3 GB และสามารถรันได้ด้วย context window ขนาดปานกลาง โมเดลขนาด 8B ที่ระดับ q8_0 ใช้น้ำหนัก 8.9 GB ซึ่งสามารถรันได้เช่นกัน การทดสอบเปรียบเทียบโมเดลทั้งสองนี้ด้วย prompt ของคุณเองถือเป็นวิธีที่มีประสิทธิภาพที่สุดในการทำความเข้าใจเรื่องนี้

32 GB. โมเดลขนาด 14B ที่ระดับ q8_0 (16 GB) และ 32B ที่ระดับ q4_K_M (20 GB) สามารถโหลดเข้าหน่วยความจำได้ทั้งคู่ สำหรับโมเดลขนาด 32B ที่ใช้ context window ขนาดใหญ่จะใช้ทรัพยากรจนเกือบเต็มขีดจำกัด ดังนั้นควรตรวจสอบ ollama ps แทนการคาดเดาเอาเอง

การควอนไทซ์ระดับใดที่เสื่อมสภาพก่อน

ข้อผิดพลาดจากการควอนไทซ์ไม่ได้กระจายตัวอย่างสม่ำเสมอในทุกการทำงานของโมเดล ความลื่นไหลของภาษาจะคงอยู่ได้นานที่สุด ซึ่งเป็นเหตุผลว่าทำไมความเสียหายนี้จึงสังเกตได้ยาก โมเดลที่ถูกควอนไทซ์มาอย่างแย่ยังคงเขียนประโยคที่อ่านรู้เรื่องได้ ความแม่นยำ (precision) จะเป็นสิ่งแรกที่สูญเสียไป เช่น การเรียกคืนหมายเลขเวอร์ชัน ลายเซ็นของ API หรือวันที่ได้อย่างถูกต้องแม่นยำ รวมถึงกระบวนการคิดที่เป็นลำดับยาวๆ ซึ่งข้อผิดพลาดเล็กน้อยในขั้นตอนที่สองอาจนำไปสู่คำตอบที่ผิดในขั้นตอนที่แปด หรือรูปแบบผลลัพธ์ที่เข้มงวดซึ่งวงเล็บที่ผิดเพียงตัวเดียวก็ทำให้การเรียกใช้เครื่องมือ (tool call) ล้มเหลว

กรณีสุดท้ายคือบททดสอบในทางปฏิบัติ เมื่อโมเดลต้องส่งผลลัพธ์เป็น JSON เพื่อให้โค้ดของคุณนำไปประมวลผล ความเสียหายจากการควอนไทซ์จะปรากฏออกมาในรูปแบบของข้อผิดพลาดในการ parse แทนที่จะเป็นเพียงภาษาที่ดูแย่ลงเล็กน้อย ทำให้คุณพบปัญหาได้ในวันเดียวกัน ตัวแทนอัจฉริยะด้านการเขียนโค้ด (coding agent) คือบททดสอบที่เข้มงวดที่สุด เพราะมันจะสั่งให้โมเดลเรียกใช้เครื่องมือซ้ำแล้วซ้ำเล่า ดังนั้นการ ชี้เป้า agent ไปยังเซิร์ฟเวอร์ Ollama ของคุณ จะทำให้เห็นผลกระทบของการควอนไทซ์ที่รุนแรงเกินไปได้ภายในช่วงบ่าย

หากต่ำกว่าสี่บิต การสูญเสียประสิทธิภาพจะเพิ่มขึ้นอย่างรวดเร็ว ประเภท q3 และสองบิตมีไว้สำหรับผู้ที่ต้องการบีบอัดโมเดลขนาดใหญ่ลงในฮาร์ดแวร์ขนาดเล็ก ซึ่งเป็นทางเลือกที่ใช้งานได้จริงเมื่อทางเลือกอื่นคือการไม่สามารถรันโมเดลนั้นได้เลย แต่พวกมันไม่ใช่ค่าเริ่มต้นที่ดี ระหว่าง q4_K_M และ q8_0 ช่องว่างของประสิทธิภาพนั้นน้อยเกินกว่าที่ตารางค่า perplexity ที่เผยแพร่ทั่วไปจะตัดสินได้สำหรับภาระงานของคุณ ดังนั้นอย่าพยายามตัดสินด้วยวิธีนั้น ให้รันทั้งสองแบบกับ prompt ของคุณเองสักสามสิบรายการแล้วอ่านผลลัพธ์ที่ได้ด้วยตนเอง

เมื่อใดที่ q8_0 หรือ fp16 คุ้มค่ากับ RAM

ให้ดึง q8_0 เมื่อคุณมีหน่วยความจำเหลือเฟือจริงๆ และงานของคุณไม่ยอมรับความผิดพลาดเล็กน้อย เช่น การสกัดข้อมูลที่มีโครงสร้าง (structured extraction), การเรียกใช้เครื่องมือ (tool calling) หรือโค้ดที่ต้องคอมไพล์ได้ คุณกำลังซื้อประกันในกรณีนี้ ไม่ใช่การทำให้โมเดลฉลาดขึ้นอย่างเห็นได้ชัด

ให้ดึง fp16 ด้วยเหตุผลเพียงสองประการเท่านั้น คือคุณกำลังทำ quantization โมเดลด้วยตัวเองและต้องการไฟล์ต้นฉบับ หรือคุณกำลังวัดค่าพื้นฐาน (baseline) เพื่อดูว่าการทำ build แบบ 4-bit ของคุณสูญเสียประสิทธิภาพไปเท่าใด การให้บริการจาก fp16 ใช้หน่วยความจำมากกว่า q4_K_M ถึงสามเท่าสำหรับความแตกต่างที่คนส่วนใหญ่แยกไม่ออกในการทดสอบแบบ blind test และบนเครื่องที่ใช้ CPU เพียงอย่างเดียว มันยังลดอัตราการสร้าง token ของคุณลงเหลือเพียงหนึ่งในสามอีกด้วย

กฎที่ชัดเจนกว่าภายใต้งบประมาณหน่วยความจำที่จำกัดคือ โมเดลขนาดใหญ่ที่ q4_K_M มักจะให้ผลลัพธ์ดีกว่าโมเดลขนาดเล็กที่ q8_0 การใช้ 9.3 GB สำหรับน้ำหนักโมเดล 14B เทียบกับ 8.9 GB สำหรับน้ำหนักโมเดล 8B นั้นใช้ RAM (random access memory) ใกล้เคียงกัน แต่โมเดลที่ใหญ่กว่ามีความรู้มากกว่า ให้ทดสอบสิ่งนี้ด้วย prompt ของคุณเองแทนที่จะเชื่อตามคำบอกเล่าเพียงอย่างเดียว

การอนุมานด้วย CPU เพียงอย่างเดียวถูกจำกัดด้วยแบนด์วิดท์ของหน่วยความจำ

VPS ส่วนใหญ่ไม่มี GPU ดังนั้นโมเดลจึงทำงานในหน่วยความจำระบบบน CPU ของโฮสต์ การสร้างข้อความ (generation) จึงถูกจำกัดด้วยแบนด์วิดท์ของหน่วยความจำ ไม่ใช่ความสามารถในการคำนวณ เพราะการสร้างหนึ่งโทเค็นจำเป็นต้องอ่านค่าน้ำหนัก (weight) ทั้งหมดหนึ่งครั้ง ซึ่งทำให้เกิดเพดานความเร็วที่ไม่เกี่ยวข้องกับจำนวนคอร์ที่คุณซื้อมา

tokens per second ceiling = memory bandwidth / bytes read per token
50 GB/s / 5.2 GB  =  9.6 tokens/s    qwen3 8B q4_K_M
50 GB/s / 8.9 GB  =  5.6 tokens/s    qwen3 8B q8_0
50 GB/s / 16 GB   =  3.1 tokens/s    qwen3 8B fp16

50 GB/s คือตัวเลขทางทฤษฎีโดยประมาณสำหรับโฮสต์ที่ใช้ DDR4-3200 แบบ dual channel ส่วนแบ่งที่คุณได้รับจริงจะน้อยกว่านั้น เนื่องจาก VPS ต้องแชร์บัสร่วมกับผู้เช่ารายอื่นบนเครื่องเดียวกัน ดังนั้นให้ถือว่าตัวเลขเหล่านั้นเป็นเพดานสูงสุดที่ไม่มีใครเข้าถึงได้ รูปแบบของประสิทธิภาพคือส่วนที่สำคัญ: บน CPU การลดจำนวนบิตต่อน้ำหนักลงครึ่งหนึ่งจะทำให้ความเร็วในการสร้างโทเค็นเพิ่มขึ้นประมาณสองเท่า การทำ Quantization จึงเป็นกลไกที่ช่วยเพิ่มความเร็วได้มากที่สุดสำหรับเครื่องที่ไม่มี GPU

การประมวลผล Prompt มีพฤติกรรมที่แตกต่างออกไป การอ่าน Prompt ที่ยาวจะถูกจำกัดด้วยพลังการคำนวณ (compute bound) มากกว่าแบนด์วิดท์ ดังนั้นการเพิ่มจำนวนคอร์จะช่วยในส่วนนี้ได้ ในขณะที่แทบไม่มีผลต่อความเร็วในการสร้างข้อความ เครื่องที่รับ Prompt ขนาด 4k ได้อย่างรวดเร็วแต่สร้างข้อความออกมาได้ช้าถือว่าทำงานเป็นปกติ

อย่าเชื่อตัวเลขการคำนวณใดๆ โดยปราศจากการพิสูจน์ วัดจำนวนโทเค็นต่อวินาทีบนเครื่องของคุณเอง ด้วย Prompt เดียวกันในแต่ละระดับการทำ Quantization แล้วให้ตัวเลขที่คุณวัดได้เป็นตัวตัดสินเหนือข้อมูลเหล่านี้

การทำ Quantization โมเดลด้วยตนเอง

Ollama สามารถสร้างโมเดลที่ผ่านการทำ quantization จากไฟล์ต้นฉบับที่เป็น fp16 หรือ fp32 ได้ ซึ่งมีความสำคัญเมื่อคุณทำการ fine-tune โมเดลขึ้นมาเองและยังไม่มี library tag รองรับ ให้ระบุตำแหน่งของ weights ที่ยังไม่ได้ทำ quantization ไว้ใน Modelfile:

FROM /path/to/my/model/f16

จากนั้นทำการ build และตรวจสอบผลลัพธ์:

ollama create --quantize q4_K_M mymodel
ollama show mymodel

--quantize รองรับ q8_0, q4_K_S และ q4_K_M ในส่วนนี้จะไม่มีตัวเลือก q6_K หรือ q5_K_M ดังนั้นสำหรับรูปแบบดังกล่าว คุณต้องทำ quantization ด้วยเครื่องมือของ llama.cpp เอง แล้วจึงนำเข้าไฟล์ GGUF ที่เสร็จสมบูรณ์เข้ามา โดยบรรทัด quantization จาก ollama show คือวิธีที่คุณใช้ตรวจสอบว่าการ build ได้ผลลัพธ์ตามที่คุณต้องการหรือไม่

สิ่งที่จะพบเมื่อเกิดข้อผิดพลาด

ทุกอย่างทำงานบน CPU ในขณะที่คุณคาดหวังให้ทำงานบน GPU ให้ตรวจสอบคอลัมน์ PROCESSOR:

ollama ps

ระบบจะแสดงค่า 100% GPU, 100% CPU หรือการแบ่งส่วน (split) เช่น 48%/52% CPU/GPU การแบ่งส่วนหมายความว่าน้ำหนักของโมเดล (weights) รวมกับ KV cache ไม่สามารถบรรจุลงใน VRAM (หน่วยความจำบนการ์ดจอ) ได้ทั้งหมด จึงมีการย้ายบางส่วนของโมเดลไปไว้ในหน่วยความจำหลักของระบบ ส่งผลให้ความเร็วลดลงจนใกล้เคียงกับการประมวลผลด้วย CPU เพียงอย่างเดียว เนื่องจากทุกโทเค็นต้องรอการประมวลผลจากส่วนที่ช้ากว่า ให้ลดขนาด context window, ทำการ quantize cache หรือเลือกใช้ build ที่มีขนาดเล็กลง การเพิ่มจำนวนคอร์ของ CPU จะไม่ช่วยแก้ปัญหานี้

โมเดลถูกสั่งยุติการทำงาน (killed) ขณะกำลังโหลด ให้ตรวจสอบ log ของ kernel และ service:

sudo dmesg -T | grep -i "out of memory"
sudo journalctl -u ollama -n 50

บรรทัดที่มีข้อความ Out of memory: Killed process หมายความว่าผลรวมของน้ำหนักโมเดล, KV cache และบัฟเฟอร์ มีขนาดเกินกว่าหน่วยความจำที่มีอยู่บนเครื่อง ในกรณีของ VPS ที่ไม่ได้ตั้งค่า swap ไว้ เครื่องอาจเกิดอาการค้างเป็นเวลาหลายวินาทีก่อนที่บรรทัดดังกล่าวจะปรากฏขึ้น

คำตอบที่ได้แย่ลงทั้งที่ไม่ได้เปลี่ยนแปลงการตั้งค่าใดๆ build ของโมเดลเดียวกันสองเวอร์ชันสามารถอยู่ใน ollama ls ภายใต้ tag ที่แตกต่างกันได้ และสคริปต์ที่ดึงชื่อโมเดลแบบไม่มี suffix จะดึงเวอร์ชันล่าสุดที่ library ชี้ไปเสมอ ให้รันคำสั่ง ollama show เทียบกับ tag ที่ client ของคุณเรียกใช้งานจริง แล้วอ่านบรรทัด quantization แทนที่จะเชื่อชื่อโมเดลที่ระบุไว้ในไฟล์ตั้งค่าของคุณ

FAQ

ฉันควรดึง Ollama quantization รุ่นไหน?

ให้เริ่มต้นด้วย q4_K_M ซึ่งเป็นค่าเริ่มต้นที่ไลบรารีของ Ollama จัดเตรียมไว้สำหรับโมเดลส่วนใหญ่ ดังนั้น ollama pull qwen3:8b และ ollama pull qwen3:8b-q4_K_M จึงเป็นการดึงไฟล์เดียวกัน ให้เปลี่ยนไปใช้ q8_0 ก็ต่อเมื่อคุณมีหน่วยความจำเหลือเฟือและงานของคุณต้องการความแม่นยำสูง เช่น การเรียกใช้เครื่องมือ (tool calling) หรือการส่งออกข้อมูลในรูปแบบ JSON ที่ซับซ้อน หากคุณมีงบประมาณหน่วยความจำจำกัด การใช้โมเดลขนาดใหญ่ที่ q4_K_M มักจะให้ผลลัพธ์ที่ดีกว่าโมเดลขนาดเล็กที่ q8_0 ดังนั้นควรทดสอบการจับคู่ดังกล่าวก่อนที่จะเพิ่ม RAM เพื่อแลกกับความละเอียดที่สูงขึ้น

q4_K_M หมายถึงสี่บิตต่อหนึ่งน้ำหนัก (weight) จริงหรือไม่?

ไม่จริง จากการวัดผลบน Llama 3.1 8B พบว่ามีค่าเท่ากับ 4.89 บิตต่อหนึ่งน้ำหนัก เนื่องจากบล็อกของน้ำหนักแต่ละบล็อกจะเก็บค่าสเกลของตัวเอง และเทนเซอร์ที่สำคัญที่สุดจะถูกปรับให้เป็นประเภทที่มีความละเอียดสูงขึ้น ส่วน Q8_0 มีค่าเท่ากับ 8.5 บิตแทนที่จะเป็นแปดด้วยเหตุผลเดียวกัน ให้ใช้ตัวเลขที่วัดได้จริงในการคำนวณ: จำนวนพารามิเตอร์คูณด้วยจำนวนบิตต่อหนึ่งน้ำหนัก แล้วหารด้วยแปด จะได้ขนาดไฟล์เป็นไบต์

โมเดล 8B ต้องการ RAM เท่าใดบน VPS ที่ใช้เฉพาะ CPU?

ให้คำนวณจากน้ำหนัก (weights), KV cache และพื้นที่สำรอง Qwen3 8B ที่ q4_K_M มีขนาดน้ำหนักอยู่ที่ 5.2 GB สำหรับหน้าต่างบริบท (context window) ค่าเริ่มต้นที่ 4096 token แคชจะเพิ่มขนาดขึ้นอีก 0.6 GB ทำให้ความต้องการขั้นต่ำอยู่ที่ประมาณ 5.8 GB ก่อนจะรวมหน่วยความจำสำหรับ compute buffers และระบบปฏิบัติการ หากใช้หน้าต่างบริบทที่ 32k แคชเพียงอย่างเดียวจะมีขนาด 4.83 GB ดังนั้นควรวางแผนไว้ที่ 8 GB สำหรับหน้าต่างบริบทสั้น และ 16 GB หากคุณต้องการหน้าต่างบริบทที่ยาวขึ้น

ทำไมโมเดลของฉันถึงใช้ CPU 100% ทั้งที่เครื่องมี GPU?

ให้รันคำสั่ง ollama ps และตรวจสอบคอลัมน์ PROCESSOR หากพบค่า 100% CPU หรือการแบ่งส่วนเช่น 48%/52% CPU/GPU หมายความว่าน้ำหนักรวมกับ KV cache ไม่สามารถบรรจุลงใน VRAM ได้ทั้งหมด Ollama จึงย้ายบางส่วนหรือทั้งหมดของโมเดลไปไว้ในหน่วยความจำหลักของระบบ สาเหตุที่พบบ่อยคือหน้าต่างบริบทมีขนาดใหญ่เกินกว่าที่การ์ดจะรองรับได้ เนื่องจากแคชจะถูกจองพื้นที่สำหรับหน้าต่างบริบททั้งหมดทันทีที่โหลดโมเดล ให้ลดขนาดหน้าต่างบริบทลงด้วย OLLAMA_CONTEXT_LENGTH, ตั้งค่า OLLAMA_KV_CACHE_TYPE=q8_0 เพื่อลดขนาดแคชลงครึ่งหนึ่ง หรือดึงโมเดลที่มี quantization ขนาดเล็กลงมาใช้งานแทน