SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-09-08

Ollama quantization: Q4, Q8 hay fp16?

So sánh q4_K_M, q8_0 và fp16 bằng phép tính cụ thể: cần bao nhiêu RAM, tốc độ token thay đổi ra sao và chất lượng giảm ở đâu.

Ollama quantization thay đổi những gì

Ollama quantization lưu mỗi weight trong model ở số bit ít hơn so với file dùng để train model đó. Tag kết thúc bằng q4_K_M giữ khoảng 4 bit cho mỗi weight, còn fp16 giữ 16 bit. Vì vậy, file download có kích thước gần bằng một phần tư, và máy chỉ cần đọc một phần tư số byte để tạo mỗi token. Các weight được làm tròn theo một lưới có độ phân giải thấp hơn, không bị loại bỏ hoàn toàn. Với 4 bit, hầu hết model vẫn trả lời gần giống khi chạy ở full precision.

Đó là toàn bộ trade-off: giảm đáng kể memory footprint và tăng số token mỗi giây, đổi lại độ chính xác giảm nhẹ. Phần tiếp theo giải thích cách dự đoán cả hai yếu tố này cho một model cụ thể trên một máy cụ thể, trước khi bạn mất 20 phút download một file không vừa bộ nhớ.

Nếu Ollama chưa chạy, hãy bắt đầu với cài đặt Ollama trên một VPS. Trang này giả định ollama ls đã hoạt động.

Cách đọc tag quantization của Ollama như q4_K_M

Các model local được phân phối dưới dạng file GGUF, là định dạng mà llama.cpp dùng để lưu weights trên disk. Ollama được xây dựng trên llama.cpp, nên các tag của Ollama giữ nguyên tên quantization của llama.cpp.

Con số là độ rộng mục tiêu. q4 nghĩa là hầu hết weight tensor được đóng gói với 4 bit cho mỗi giá trị. q8 nghĩa là 8 bit. fp16 không được quantize: đây là model ở dạng floating point 16 bit, cũng là precision mà phần lớn model được công bố.

K đánh dấu một K-quant. Các weight được chia thành những block nhỏ. Mỗi block lưu scale riêng bên cạnh các giá trị đã đóng gói. Một block có toàn bộ weight gần 0.01 sẽ dùng scale chi tiết hơn. Một block chứa một outlier lớn sẽ dùng scale thô hơn. Các scale riêng theo block giúp file 4 bit vẫn dùng được. Đây cũng là lý do file 4 bit không bao giờ thực sự chỉ có 4 bit cho mỗi weight.

Chữ cái cuối là kiểu phối hợp. S, M và L quyết định có bao nhiêu tensor được nâng lên lớn hơn độ rộng mục tiêu. Trong q4_K_M, các tensor bị ảnh hưởng nhiều nhất khi làm tròn sẽ được lưu với độ rộng lớn hơn, còn phần lớn tensor vẫn ở 4 bit. Vì vậy q4_K_M cho output tốt hơn q4_0 cũ với kích thước file gần như tương đương.

Hãy hỏi Ollama xem trên disk đang có gì thay vì đoán từ tên bạn đã nhập:

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

ollama show in ra architecture, parameters, quantization, context length và embedding length. Dòng quantization là thông tin chính xác cho model bạn đã pull từ nhiều tháng trước và không còn nhớ đã chọn loại nào.

Bits trên mỗi weight quyết định kích thước file

Mọi ước tính kích thước đều bắt đầu từ một con số: format dùng bao nhiêu bit cho mỗi weight, tính trung bình trên toàn bộ file. llama.cpp công bố các số liệu đo được cho Llama 3.1 8B trong tài liệu quantize. Các số liệu này cũng phù hợp với mọi model dense có cấu trúc tương tự.

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
  }
]

Điểm dễ gây nhầm trong bảng đó là cột thứ hai. Q4_K_M không dùng 4 bit cho mỗi weight. Giá trị đo được là 4.89 bit, vì block scale và các tensor được nâng precision cũng chiếm dung lượng thực. Tương tự, Q8_0 dùng 8.5 bit thay vì 8 bit. Dùng số liệu đo được thì phép tính sẽ chênh không quá vài phần trăm so với kích thước file thực:

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

Đó là file Q4_K_M có kích thước 4.58 GiB, tính được từ hai con số. Đây cũng gần đúng là lượng memory mà weights chiếm sau khi được load. Ollama không unpack dữ liệu khi load: các quantized weights nằm trong memory ở cùng dạng đã pack, và mỗi block được convert khi được sử dụng.

Ollama thực sự cung cấp gì cho từng kích thước model

Thư viện cung cấp tag q4_K_M, q8_0 và fp16 cho hầu hết các dòng model. Một vài dòng mới hơn phá vỡ quy luật này và xuất hiện trong thư viện dưới dạng tag chỉ dành cho cloud, không có phiên bản nào để pull ở bất kỳ độ rộng nào. Đây là trở ngại bạn gặp phải khi thử chạy GLM 5.2 trên VPS. Dưới đây là các kích thước Qwen3 tính đến tháng 08 năm 2026, được đọc từ danh sách tag trên trang model. Mọi con số bên dưới đều là dung lượng trên disk trước khi được nạp vào RAM. Hai hoặc ba model kết hợp có thể lấp đầy root volume của một VPS nhỏ, vì vậy bạn nên biết Ollama lưu các model đã download ở đâu trước khi bắt đầu thu thập tag.

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
  }
]

Tag mặc định rất quan trọng ở đây. ollama pull qwen3:8b download đúng 5.2 GB, giống hệt ollama pull qwen3:8b-q4_K_M, vì tag không có hậu tố chính là bản build q4_K_M. Q4_K_M không phải là một lựa chọn thỏa hiệp mà thư viện miễn cưỡng cung cấp. Đây là lựa chọn mặc định từ upstream, vì vậy dùng tag này là bước đầu hợp lý cho mọi model mà bạn chưa tự kiểm thử. Lý do tương tự cũng quyết định các lựa chọn tag trong chạy Qwen 3 trên VPS.

Tỷ lệ này đúng với mọi dòng. Chuyển từ q4_K_M sang q8_0 tốn thêm khoảng 70 phần trăm thay vì tăng gấp đôi, vì embedding tensor và output tensor không tăng theo cùng tỷ lệ với các tensor còn lại. fp16 có dung lượng xấp xỉ gấp 3 lần q4_K_M. Model 32B ở q4_K_M có 20 GB weights, đã vượt quá dung lượng mà một máy 16 GB có thể chứa nếu vẫn cần bất kỳ context window nào. Để xem tổng quan rộng hơn về model nào phù hợp với máy nào, hãy xem những model bạn có thể tự host.

Vì sao KV cache là chi phí thứ hai và phụ thuộc vào context

Weights là chi phí cố định. KV cache (key cache và value cache) là chi phí biến đổi. Mỗi token trong context window giữ các vector key và value cho mọi layer, vì vậy cache tăng tuyến tính theo độ dài window mà bạn cho phép. Cache được cấp phát cho toàn bộ window khi model load, không phải khi cuộc hội thoại dần đầy lên. Vì vậy, window dài vẫn ngốn memory ngay cả khi prompt chỉ có một từ.

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

Các thông số của model đó lấy từ chính cấu hình của model: 36 layer, 8 key/value head và head dimension là 128. ollama show cung cấp thông tin về architecture và số parameter, còn config.json của model trên Hugging Face cung cấp các thông tin còn lại. Lấy chi phí trên mỗi token nhân với kích thước window, bạn sẽ thấy cache không còn là phần chênh lệch không đáng kể.

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
  }
]

Với window mặc định 4096 token của Ollama, cache cộng thêm 0.6 GB ngoài phần weights. Tăng window lên 32k thì riêng cache đã lên tới 4.83 GB, gần bằng lượng memory mà phần weights đã quantize sử dụng, và mức sàn cho toàn bộ model trở thành 10 GB. Gọi đây là mức sàn vì các buffer phục vụ compute và hệ điều hành còn sử dụng thêm memory. Đọc con số thực tế trong cột SIZE của ollama ps sau khi model load xong.

Window được đặt trên server, không phải theo từng request, khi bạn chạy Ollama dưới dạng service:

OLLAMA_CONTEXT_LENGTH=8192 ollama serve

Với bản cài đặt bằng systemd, thay vào đó hãy đặt giá trị này trong drop-in:

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

Khởi động lại bằng sudo systemctl restart ollama, sau đó kiểm tra cột CONTEXT của ollama ps để xác nhận window mà model đang chạy thực sự được load cùng. OLLAMA_KV_CACHE_TYPE thực hiện quantize chính cache: f16 là mặc định, q8_0 sử dụng khoảng một nửa memory của f16, còn q4_0 sử dụng khoảng một phần tư. Đây là tùy chọn global, nên mọi model trên server đó đều dùng cùng một thiết lập. Trên một máy có ít memory nhưng window dài, giảm một nửa cache sẽ giải phóng nhiều memory hơn bất kỳ thay đổi đơn lẻ nào khác. Thiết lập num_ctx và chi phí của nó trình bày chi tiết riêng về window. Cache cũng được cấp phát một lần cho mỗi request slot chạy đồng thời, thay vì một lần cho mỗi server. Vì vậy, cho phép Ollama xử lý 2 prompt cùng lúc sẽ tăng gấp đôi con số bạn vừa dự trù. Đây là cơ sở của phép tính trong chọn số lượng parallel slot và giới hạn queue.

Dung lượng nào phù hợp với VPS 8, 16 hoặc 32 GB

Hãy tính đến dung lượng của weights, KV cache, phần dự phòng cho hệ điều hành và mọi thành phần khác đang chạy. Dành 2 GB làm phần dự phòng là mức thoải mái trên một VPS nhỏ.

8 GB. Model 4B ở q4_K_M có dung lượng 2.6 GB và vẫn đủ chỗ cho context window dài. Model 8B ở q4_K_M chạy được với window mặc định 4k nhưng hầu như không còn dư. Không nên dùng 8B với window 32k trên VPS này, vì mức tối thiểu 10 GB đã vượt quá dung lượng máy.

16 GB. Model 8B ở q4_K_M với window 16k hoặc 32k chạy thoải mái. Model 14B ở q4_K_M có 9.3 GB weights và chạy được với window vừa phải. Model 8B ở q8_0 có 8.9 GB, nên cũng chạy được. Tự so sánh hai cấu hình này bằng các prompt của bạn là cách hữu ích nhất để tìm hiểu vấn đề này.

32 GB. Cả model 14B ở q8_0 (16 GB) và model 32B ở q4_K_M (20 GB) đều có thể load. Bản 32B với window lớn sẽ sát giới hạn dung lượng, vì vậy hãy theo dõi ollama ps thay vì mặc định cho rằng nó sẽ chạy được.

Lượng tử hóa làm suy giảm điều gì trước

Lỗi lượng tử hóa không ảnh hưởng đồng đều đến mọi khả năng của model. Độ trôi chảy thường được giữ lại lâu nhất. Đây chính là lý do vấn đề khó nhận ra: một model lượng tử hóa kém vẫn có thể viết các câu rõ ràng. Độ chính xác suy giảm trước. Khả năng nhớ chính xác số phiên bản, chữ ký API hoặc ngày tháng sẽ giảm. Các chuỗi suy luận dài cũng bị ảnh hưởng, vì một lỗi nhỏ ở bước thứ hai có thể dẫn đến câu trả lời sai ở bước thứ tám. Các định dạng output nghiêm ngặt cũng dễ hỏng; chỉ cần sai một dấu ngoặc là tool call có thể fail.

Trường hợp cuối là phép kiểm tra thực tế. Khi model phải trả về JSON để code của bạn parse, ảnh hưởng của lượng tử hóa sẽ xuất hiện dưới dạng lỗi parse thay vì văn bản kém tự nhiên một cách khó xác định. Vì vậy, bạn có thể thấy vấn đề ngay trong ngày. Coding agent là phép kiểm tra khắt khe nhất, vì nó điều khiển model thực hiện hết tool call này đến tool call khác. Do đó, trỏ một agent vào server Ollama của bạn sẽ làm lộ lượng tử hóa quá mạnh trong vòng một buổi chiều.

Dưới bốn bit, mức suy giảm tăng nhanh. Các loại q3 và hai bit dành cho trường hợp cần đưa một model lớn lên phần cứng nhỏ. Đây vẫn là lựa chọn thực tế khi phương án còn lại là không chạy model. Tuy nhiên, chúng không nên là lựa chọn mặc định. Khoảng cách giữa q4_K_M và q8_0 đủ nhỏ để một bảng perplexity được công bố không thể quyết định loại nào phù hợp với workload của bạn. Vì vậy, đừng cố quyết định theo cách đó. Hãy chạy cả hai với 30 prompt của chính bạn rồi đọc output.

Khi q8_0 hoặc fp16 đáng dùng RAM

Chọn q8_0 khi bộ nhớ thực sự còn dư và tác vụ không chấp nhận sai sót nhỏ: trích xuất có cấu trúc, gọi tool, hoặc code phải biên dịch được. Trong trường hợp này, bạn đang mua thêm độ an toàn, không phải một model thông minh hơn thấy rõ.

Chỉ chọn fp16 trong 2 trường hợp. Hoặc bạn tự quantize model và cần file nguồn, hoặc bạn đang đo baseline để biết bản build four-bit của mình đã đánh đổi bao nhiêu. Chạy model ở fp16 dùng lượng bộ nhớ gấp 3 lần q4_K_M, nhưng khác biệt này hầu hết mọi người không thể nhận ra khi so sánh mù. Trên máy chỉ có CPU, nó còn làm tốc độ sinh token giảm xuống còn một phần 3.

Quy tắc quan trọng hơn, khi ngân sách bộ nhớ cố định: model lớn hơn ở q4_K_M thường vượt model nhỏ hơn ở q8_0. 9.3 GB trọng số 14B so với 8.9 GB trọng số 8B gần như dùng cùng lượng RAM (random access memory), nhưng model lớn hơn hiểu biết nhiều hơn. Hãy kiểm thử bằng prompt của chính bạn thay vì tin ngay điều này.

Suy luận chỉ dùng CPU bị giới hạn bởi băng thông bộ nhớ

Hầu hết gói VPS không có GPU, nên model chạy trong system memory trên CPU của host. Khi đó tốc độ sinh bị giới hạn bởi băng thông bộ nhớ, không phải năng lực tính toán, vì để tạo một token cần đọc mỗi weight một lần. Vì vậy sẽ có một mức trần không liên quan đến số core bạn đã mua.

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 là con số lý thuyết gần đúng đối với host dùng DDR4-3200 dual-channel. Phần băng thông bạn nhận được còn thấp hơn, vì VPS chia sẻ bus đó với mọi tenant khác trên máy. Do đó, hãy xem các con số này là mức trần mà thực tế không đạt tới. Điểm hữu ích nằm ở xu hướng: trên CPU, giảm một nửa số bit trên mỗi weight thường giúp tốc độ token tăng gần gấp đôi. Quantization là đòn bẩy tốc độ lớn nhất trên máy không có GPU. Tốc độ còn lại có chấp nhận được hay không phụ thuộc vào model. Nemotron 3.5 Lightning trên VPS phân tích cụ thể điều đó cho một build, tag và dung lượng RAM nhất định. Một phần khác của thời gian chờ là độ dài nội dung model quyết định viết. Ở tốc độ 10 token mỗi giây, câu trả lời dài 600 token sẽ mất trọn 1 phút. Vì vậy, giới hạn câu trả lời bằng num_predict thường giúp giảm thời gian chờ nhiều hơn so với việc giảm thêm một mức precision.

Xử lý prompt hoạt động khác. Đọc một prompt dài bị giới hạn bởi năng lực tính toán thay vì băng thông, nên thêm core sẽ giúp xử lý prompt nhưng hầu như không làm tốc độ sinh tăng. Một máy xử lý nhanh prompt 4k rồi sinh chậm là đang hoạt động bình thường.

Đừng mặc nhiên tin các phép tính trên. Hãy đo số token mỗi giây trên chính máy của bạn bằng cùng một prompt ở từng mức quantization, rồi dùng số liệu thực tế của bạn để đánh giá lại các con số này.

Tự quantize một model

Ollama có thể build một model đã quantize từ source fp16 hoặc fp32. Điều này hữu ích khi bạn đã fine-tune một model nhưng chưa có library tag tương ứng. Trỏ một Modelfile vào bộ weights chưa quantize:

FROM /path/to/my/model/f16

Sau đó build và xác nhận:

ollama create --quantize q4_K_M mymodel
ollama show mymodel

--quantize chấp nhận q8_0, q4_K_S và q4_K_M. Ở đây không có tùy chọn q6_K hoặc q5_K_M. Với các tùy chọn đó, bạn phải quantize bằng tool riêng của llama.cpp rồi import file GGUF hoàn chỉnh. Cách import này có một lỗi riêng: chat template không khớp khiến model trả lời bằng nội dung rác. Import file GGUF vào Ollama hướng dẫn cách xử lý vấn đề này. Dòng quantization từ ollama show là cách xác minh bản build đã thực hiện đúng yêu cầu của bạn.

Bạn sẽ thấy gì khi có lỗi

Mọi thứ chạy trên CPU trong khi bạn chờ GPU xử lý. Đọc cột PROCESSOR:

ollama ps

Kết quả là 100% GPU, 100% CPU hoặc dạng phân chia như 48%/52% CPU/GPU. Dạng phân chia nghĩa là weights và KV cache không vừa VRAM (video RAM, bộ nhớ trên card đồ họa), nên một phần model được đặt trong system memory. Tốc độ sau đó giảm gần bằng tốc độ chỉ dùng CPU, vì mỗi token đều phải chờ phần chậm hơn. Hãy giảm context window, quantize cache hoặc dùng bản build nhỏ hơn. Thêm core sẽ không giúp ích.

Model bị kill trong lúc load. Kiểm tra kernel và log của service:

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

Dòng chứa Out of memory: Killed process nghĩa là tổng dung lượng của weights, KV cache và các buffer đã vượt quá bộ nhớ trên máy. Trên VPS không cấu hình swap, toàn bộ máy có thể bị treo trong vài giây trước khi dòng này xuất hiện.

Câu trả lời kém hơn trong khi bạn không thay đổi gì. Hai build của cùng một model có thể cùng tồn tại trong ollama ls dưới các tag khác nhau, và một script pull tên không có hậu tố sẽ dùng tag mà library hiện đang trỏ tới. Chạy ollama show với đúng tag mà client yêu cầu và đọc dòng quantization, thay vì tin vào tên trong file cấu hình.

FAQ

Bạn nên tải quantization nào của Ollama?

Hãy bắt đầu với q4_K_M. Đây là tag mặc định mà thư viện Ollama cung cấp cho hầu hết model, nên ollama pull qwen3:8b và ollama pull qwen3:8b-q4_K_M sẽ tải cùng một file. Chỉ chuyển sang q8_0 khi còn dư memory và tác vụ không chấp nhận lỗi nhỏ, chẳng hạn như gọi tool hoặc xuất JSON có cấu trúc. Khi ngân sách memory cố định, model lớn hơn ở q4_K_M thường cho kết quả tốt hơn model nhỏ hơn ở q8_0. Vì vậy, hãy thử cặp này trước khi dành thêm RAM cho độ chính xác.

q4_K_M có thực sự nghĩa là 4 bit cho mỗi weight không?

Không. Đo trên Llama 3.1 8B, giá trị này là 4.89 bit cho mỗi weight, vì mỗi block weight lưu scale riêng và các tensor nhạy cảm nhất được nâng lên kiểu dữ liệu rộng hơn. Q8_0 có giá trị 8.5 bit thay vì 8 bit cũng vì lý do đó. Khi ước tính, hãy dùng giá trị đo được: số parameter nhân với số bit trên mỗi weight, rồi chia cho 8, sẽ ra kích thước file tính theo byte.

Model 8B cần bao nhiêu RAM trên VPS chỉ dùng CPU?

Hãy cộng dung lượng weight, KV cache và phần dự phòng. Qwen3 8B ở q4_K_M có 5.2 GB weight. Với cửa sổ 4096 token mặc định, cache cần thêm 0.6 GB, nên mức tối thiểu vào khoảng 5.8 GB trước khi tính compute buffer và hệ điều hành. Với cửa sổ 32k, riêng cache đã cần 4.83 GB. Hãy dự trù 8 GB cho cửa sổ ngắn và 16 GB nếu bạn muốn dùng cửa sổ dài.

Tại sao model chạy ở 100% CPU khi máy có GPU?

Chạy ollama ps và đọc cột PROCESSOR. 100% CPU hoặc kiểu phân bổ một phần như 48%/52% CPU/GPU nghĩa là weight và KV cache không vừa VRAM, nên Ollama đã đặt một phần hoặc toàn bộ model vào system memory. Nguyên nhân thường gặp là cửa sổ context lớn hơn dung lượng card có thể chứa, vì cache được cấp phát cho toàn bộ cửa sổ khi model load. Giảm cửa sổ bằng OLLAMA_CONTEXT_LENGTH, đặt OLLAMA_KV_CACHE_TYPE=q8_0 để giảm một nửa cache, hoặc tải quantization nhỏ hơn.