What Metrics Should You Validate When Using Quantized Models to Reduce VRAM?
This guide explains how to evaluate quantized large language models by measuring VRAM reduction, inference performance (latency, throughput), and model quality (perplexity, accuracy, BLEU/ROUGE), providing step‑by‑step procedures, code examples, and best‑practice recommendations for deployment.
Problem Background
Large language model (LLM) inference is often limited by GPU memory. A LLaMA2‑70B model in FP16 requires about 140 GB of VRAM, which cannot fit on a single 40 GB A100. Even a 7 B model in FP16 needs roughly 14 GB, restricting batch size and concurrency.
Quantization reduces parameter precision (FP16 → INT8 → INT4), dramatically lowering VRAM usage and enabling:
Running LLMs on consumer‑grade GPUs
Deploying larger models on a single card
Increasing batch size and throughput
Reducing inference cost
However, quantization can degrade accuracy, so a comprehensive validation covering VRAM, performance, and quality is required.
Applicable Scenarios
Insufficient VRAM to load the original model
Need to deploy larger models on a single GPU
Require higher inference throughput and concurrency
Need to lower inference cost
Acceptable tolerance for some quality loss
Deployment on edge devices or consumer GPUs
Core Knowledge Points
Quantization Method Categories
By Precision : FP16 (16‑bit float), INT8 (8‑bit integer, 75 % memory reduction), INT4 (4‑bit integer, 87.5 % reduction), Mixed Precision (high‑precision for critical layers)
By Timing : Post‑Training Quantization (PTQ) – simple, larger accuracy loss; Quantization‑Aware Training (QAT) – simulates quantization during training, lower loss but requires retraining
By Scope : Weight‑only (weights quantized, activations stay FP16) vs Activation Quantization (both weights and activations quantized)
Common Quantization Tools
GPTQ – 4‑bit weight quantization for Transformers
AWQ – Activation‑aware weight quantization, balances performance and quality
GGUF – llama.cpp format for CPU inference
bitsandbytes (BNB) – dynamic 8‑bit/4‑bit quantization
SmoothQuant – smooth activation quantization for very large models
VRAM Consumption Estimation
Model VRAM ≈ parameter count × bytes per value × 1.2 (for caches and intermediate tensors).
Examples:
LLaMA2‑7B FP16: 7 B × 2 bytes × 1.2 ≈ 16.8 GB
LLaMA2‑7B INT8: 7 B × 1 byte × 1.2 ≈ 8.4 GB
LLaMA2‑7B INT4: 7 B × 0.5 byte × 1.2 ≈ 4.2 GB
End‑to‑End Validation Process
Record baseline metrics (FP16)
Apply quantization
Measure and compare:
VRAM usage (model load, inference peak, batch‑size impact)
Inference performance (TTFT, TPOT, end‑to‑end latency, QPS/TPS)
Model quality (perplexity, task accuracy, BLEU/ROUGE, human scores)
Perform cost‑benefit analysis and decide whether to adopt the quantized model
Practical Steps
Step 1 – Prepare Baseline Model
Load the FP16 model with vLLM and record baseline metrics.
python -m vllm.entrypoints.openai.api_server \
--model /path/to/llama2-7b \
--dtype float16 \
--max-model-len 4096 \
--gpu-memory-utilization 0.9 \
--port 8000Observe GPU memory via nvidia-smi (e.g., 16 GB used).
Step 2 – Perform Quantization
GPTQ 4‑bit
pip install auto-gptq optimum transformers accelerate
python - <<'PY'
from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig
model_id = "/path/to/llama2-7b"
quant_cfg = GPTQConfig(bits=4, dataset="c4", tokenizer=None)
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=quant_cfg,
device_map="auto",
)
model.save_pretrained("/path/to/llama2-7b-gptq-4bit")
tokenizer.save_pretrained("/path/to/llama2-7b-gptq-4bit")
PYAWQ 4‑bit
pip install autoawq
python - <<'PY'
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
model_path = "/path/to/llama2-7b"
quant_path = "/path/to/llama2-7b-awq-4bit"
model = AutoAWQForCausalLM.from_pretrained(model_path, safetensors=True)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
quant_config = {"zero_point": True, "q_group_size": 128, "w_bit": 4, "version": "GEMM"}
model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)
PYBitsAndBytes Dynamic 8‑bit / 4‑bit
# 8‑bit
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
model_id = "/path/to/llama2-7b"
quant_cfg = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quant_cfg, device_map="auto")
# 4‑bit
quant_cfg = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quant_cfg, device_map="auto")
PYStep 3 – Load Quantized Model and Measure VRAM
python -m vllm.entrypoints.openai.api_server \
--model /path/to/llama2-7b-awq-4bit \
--quantization awq \
--dtype float16 \
--max-model-len 4096 \
--gpu-memory-utilization 0.9 \
--port 8001After startup, nvidia-smi shows ~5 GB VRAM usage (≈68.75 % reduction).
Step 4 – Validate Inference Performance
First‑Token Latency (TTFT)
import time, requests
url = "http://localhost:8001/v1/completions"
payload = {"model": "llama2-7b", "prompt": "Once upon a time", "max_tokens": 100, "stream": True}
start = time.time()
resp = requests.post(url, json=payload, stream=True)
for line in resp.iter_lines():
if line:
ttft = time.time() - start
print(f"TTFT: {ttft:.3f}s")
break
PYObserved TTFT: 0.15 s (≈25 % slower than FP16 0.12 s).
Per‑Token Latency (TPOT)
import time, requests
url = "http://localhost:8001/v1/completions"
payload = {"model": "llama2-7b", "prompt": "Once upon a time", "max_tokens": 100, "stream": True}
start = time.time()
resp = requests.post(url, json=payload, stream=True)
token_cnt = 0
first_token_time = None
for line in resp.iter_lines():
if line:
token_cnt += 1
if first_token_time is None:
first_token_time = time.time()
ttft = first_token_time - start
end = time.time()
if token_cnt > 1:
tpot = (end - first_token_time) / (token_cnt - 1)
else:
tpot = 0
print(f"TPOT: {tpot:.3f}s/token")
PYObserved TPOT: 0.032 s/token (≈28 % slower than FP16 0.025 s/token).
End‑to‑End Latency
FP16: 0.12 s + 0.025 s × 100 ≈ 2.62 s
4‑bit: 0.15 s + 0.032 s × 100 ≈ 3.35 s (≈27.9 % increase).
Throughput (QPS/TPS)
# FP16 benchmark
hey -n 100 -c 4 -m POST http://localhost:8000/v1/completions
# Quantized benchmark
hey -n 100 -c 4 -m POST http://localhost:8001/v1/completions
PYResults: FP16 QPS ≈ 1.2, TPS ≈ 60; Quantized QPS ≈ 1.0, TPS ≈ 50 (≈16.7 % drop). Batch‑size scaling raised quantized QPS to ~2.5, a 108 % improvement over FP16 batch‑size‑limited throughput.
Step 5 – Validate Model Quality
Perplexity
lm_eval --model hf \
--model_args pretrained=/path/to/llama2-7b,dtype=float16 \
--tasks lambada_openai \
--device cuda:0 \
--batch_size 8FP16 perplexity: 3.82; 4‑bit perplexity: 4.15 (≈8.6 % increase).
Task Accuracy (HellaSwag, Winogrande, ARC)
lm_eval --model hf \
--model_args pretrained=/path/to/llama2-7b,dtype=float16 \
--tasks hellaswag,winogrande,arc_easy,arc_challenge \
--device cuda:0 \
--batch_size 8FP16 HellaSwag acc_norm: 0.756; Quantized: 0.742 (‑1.9 pp). Similar small drops for other tasks (≈1‑2 pp).
BLEU (Translation) and ROUGE‑L (Summarization)
# BLEU
sacrebleu reference.txt -i hypothesis_fp16.txt -m bleu
sacrebleu reference.txt -i hypothesis_4bit.txt -m bleu
# ROUGE-L
python -m rouge reference.txt hypothesis_fp16.txt
python -m rouge reference.txt hypothesis_4bit.txt
PYBLEU: FP16 = 32.5, 4‑bit = 31.2 (‑4 %). ROUGE‑L: FP16 = 0.45, 4‑bit = 0.43 (‑4.4 %).
Human Evaluation (100 samples)
Scoring on factual accuracy, fluency, relevance, completeness (1‑5). FP16 average = 4.2, 4‑bit average = 3.9 (‑7.1 %).
Step 6 – Comprehensive Comparison
VRAM
Model load: FP16 ≈ 16 GB → 4‑bit ≈ 5 GB (‑68.75 %)
Single‑request peak: FP16 ≈ 16.8 GB → 4‑bit ≈ 5.5 GB (‑67 %)
4‑concurrent peak: FP16 ≈ 20.5 GB → 4‑bit ≈ 8.2 GB (‑60 %)
Maximum batch size: FP16 = 6 → 4‑bit = 16 (↑166 %)
Performance
TTFT: 0.12 s → 0.15 s (+25 %)
TPOT: 0.025 s → 0.032 s (+28 %)
End‑to‑end latency: 2.62 s → 3.35 s (+27.9 %)
QPS (single‑card): 1.2 → 1.0 (‑16.7 %)
QPS (batch‑optimized): 1.2 → 2.5 (+108 %)
Quality
Perplexity: 3.82 → 4.15 (+8.6 %)
HellaSwag acc_norm: 0.756 → 0.742 (‑1.9 %)
Winogrande acc: 0.694 → 0.681 (‑1.9 %)
Human score: 4.2 → 3.9 (‑7.1 %)
BLEU: 32.5 → 31.2 (‑4 %)
ROUGE‑L: 0.45 → 0.43 (‑4.4 %)
Cost
GPU hourly cost unchanged ($2.00/hr)
Per‑request cost drops from $0.0005 to $0.0002 (‑60 %) due to higher batch capacity
Step 7 – Quantization Method Comparison
FP16 (baseline)
VRAM: 16 GB
TTFT: 0.12 s
TPOT: 0.025 s
Perplexity: 3.82
Accuracy loss: 0 %
GPTQ 4‑bit
VRAM: 5.2 GB
TTFT: 0.16 s
TPOT: 0.035 s
Perplexity: 4.28
Accuracy loss: –2.5 %
AWQ 4‑bit
VRAM: 5.0 GB
TTFT: 0.15 s
TPOT: 0.032 s
Perplexity: 4.15
Accuracy loss: –1.9 %
BNB 4‑bit
VRAM: 5.3 GB
TTFT: 0.18 s
TPOT: 0.038 s
Perplexity: 4.42
Accuracy loss: –3.2 %
BNB 8‑bit
VRAM: 8.5 GB
TTFT: 0.14 s
TPOT: 0.028 s
Perplexity: 3.95
Accuracy loss: –0.8 %
Conclusion : AWQ offers the best overall trade‑off (smallest quality loss, good speed). GPTQ is a balanced choice. BNB 4‑bit provides the simplest workflow but incurs the highest quality degradation. BNB 8‑bit retains near‑FP16 quality with 47 % VRAM savings.
Configuration Examples
vLLM Deployment of a Quantized Model
#!/bin/bash
MODEL_PATH="/data/models/llama2-7b-awq-4bit"
python -m vllm.entrypoints.openai.api_server \
--model ${MODEL_PATH} \
--quantization awq \
--dtype float16 \
--tensor-parallel-size 1 \
--max-model-len 4096 \
--gpu-memory-utilization 0.9 \
--max-num-batched-tokens 8192 \
--max-num-seqs 32 \
--port 8000 \
--host 0.0.0.0 \
--served-model-name llama2-7b \
--trust-remote-code \
--enable-prefix-caching \
--disable-log-requests \
2>&1 | tee vllm.logKubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: llama2-7b-quant
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: llama2-7b-quant
template:
metadata:
labels:
app: llama2-7b-quant
spec:
containers:
- name: vllm
image: vllm/vllm-openai:v0.3.0
args:
- --model
- /models/llama2-7b-awq-4bit
- --quantization
- awq
- --dtype
- float16
- --max-model-len
- "4096"
- --gpu-memory-utilization
- "0.9"
- --max-num-seqs
- "32"
- --port
- "8000"
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "8"
memory: 32Gi
nvidia.com/gpu: 1
ports:
- containerPort: 8000
name: http
volumeMounts:
- name: models
mountPath: /models
- name: shm
mountPath: /dev/shm
volumes:
- name: models
persistentVolumeClaim:
claimName: model-storage
- name: shm
emptyDir:
medium: Memory
sizeLimit: 10Gi
nodeSelector:
nvidia.com/gpu: "true"
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoScheduleMonitoring and Logging
GPU Memory Trend
while true; do
nvidia-smi --query-gpu=timestamp,memory.used,memory.total,utilization.gpu \
--format=csv,noheader >> gpu_memory.csv
sleep 1
doneInference Latency Logging (Python)
import logging, time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def log_request_metrics(prompt, response, start_time):
latency = time.time() - start_time
logger.info({
"prompt_length": len(prompt),
"response_length": len(response),
"latency": latency,
"timestamp": start_time,
})
PYPrometheus Exporter for Latency
from prometheus_client import Histogram
request_latency = Histogram('request_latency_seconds', 'Request latency')
@request_latency.time()
def handle_request(prompt):
pass
PYRisk Mitigation
Quality loss too high : Perform thorough evaluation (perplexity, task accuracy, human scoring) before production; use A/B testing; keep FP16 model for rollback.
Performance slowdown : Test different quantization methods; ensure hardware supports INT4; prefer optimized kernels (vLLM, TensorRT‑LLM).
Compatibility issues : Verify CUDA, library versions, and model format (Safetensors, GGUF) in the target environment.
Insufficient VRAM after quantization : Consider deeper quantization (INT2), model parallelism, KV‑cache reduction, CPU offloading, or a smaller model.
New bugs introduced by quantization : Check quantization config, calibration data, and model integrity; test with multiple tools; report issues to maintainers.
Validation Methods
VRAM reduction : Compare nvidia-smi memory.used before and after quantization; compute percentage saved.
Performance : Measure TTFT, TPOT, end‑to‑end latency, and P95/P99 latency with hey or custom scripts.
Quality : Run lm_eval for perplexity and benchmark tasks; compute BLEU/ROUGE for translation/summary; conduct human evaluation.
Batch capacity : Increment concurrent requests and observe memory and latency to find maximum stable batch size.
Common Commands Summary
Quantization
GPTQ:
python quantize_gptq.py --model /path/to/fp16 --output /path/to/gptqAWQ:
python quantize_awq.py --model /path/to/fp16 --output /path/to/awqGGUF conversion:
python convert_to_gguf.py --model /path/to/fp16 --output /path/to/ggufVRAM monitoring watch -n 1 nvidia-smi Record history:
nvidia-smi --query-gpu=timestamp,memory.used --format=csv --loop=1 > memory.csvPerformance testing
Single request latency:
time curl -X POST http://localhost:8000/v1/completions -d '{"prompt": "Test"}'Load test: hey -n 100 -c 4 -m POST http://localhost:8000/v1/completions Quality evaluation
Run evaluation:
lm_eval --model hf --model_args pretrained=/path/to/model --tasks allPerplexity:
python -m lm_eval --model hf --model_args pretrained=/path/to/model --tasks lambada_openai --device cuda:0Diff two models:
diff <(lm_eval ... --model_args pretrained=/path/to/fp16 ...) <(lm_eval ... --model_args pretrained=/path/to/quant ...)Summary and Recommendations
Quantization is an effective technique to cut VRAM usage for LLM inference, but it must be validated across three dimensions:
VRAM : model load, inference peak, batch‑size impact, maximum batch size.
Performance : TTFT, TPOT, end‑to‑end latency, QPS/TPS, batch capacity.
Quality : perplexity, task accuracy, BLEU/ROUGE, human scores, business‑level metrics.
Method selection guidelines:
AWQ provides the best overall trade‑off (small quality loss, good speed).
GPTQ offers a balanced middle ground.
BNB 8‑bit retains near‑FP16 quality with 47 % VRAM savings.
BNB 4‑bit is the simplest but incurs the highest quality loss.
Implementation advice:
Validate thoroughly in a test environment before production.
Compare multiple quantization methods for your hardware and workload.
Keep the original FP16 model for quick rollback.
Roll out using a gray‑scale deployment (5 % → 10 % → … → 100 %).
Continuously monitor VRAM, latency, and quality metrics.
Periodically re‑evaluate when models or business requirements change.
By following this systematic validation framework, you can safely adopt quantized models, achieve significant VRAM savings, maintain acceptable performance, and ensure that model quality meets the needs of your applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
