Skip to content

Benchmark: Gemma4 ORT GenAI inference — f16 vs Q4_K_M vs NF4 (CUDA + CPU) #346

Description

@justinchuby

Summary

Benchmark of Gemma4 inference through onnxruntime-genai on ONNX models exported with mobius, comparing full-precision vs INT4-quantized decoders across CUDA and CPU. Quantization is done with Olive (OnnxKQuantQuantization / OnnxBnb4Quantization).

TL;DR: Q4_K_M is the recommended format — it is the fastest on CPU (+80% tok/s) and slightly faster than f16 on CUDA (+4% tok/s), at ~3.1x smaller decoder. NF4 should be avoided — it is slower than f16 on both EPs.

Environment

GPU NVIDIA H200 (143 GB)
onnxruntime 1.27.0
onnxruntime-genai 0.14.0-dev (commit 9b875c3, + per-layer-KV patch)
mobius 44fdbd0
Model google/gemma-4-E2B-it (text-only decode path)
Quantizer Olive — Q4_K_M (OnnxKQuantQuantization, bits=4, block_size=32), NF4 (OnnxBnb4Quantization)

Methodology: 92-token prompt, forced 64-token decode (min_length==max_length, greedy), 2 warmup runs + best of 3. TTFT = prefill + first token. Decode tok/s = steady-state after first token.

Results — gemma-4-E2B-it

CUDA EP (H200)

Dtype Decode tok/s TTFT (ms) Decoder size vs f16 (decode)
f16 148.0 7.5 4.73 GB baseline
Q4_K_M 153.5 10.4 1.51 GB +3.7%
NF4 127.8 11.6 1.41 GB −13.6%

CPU EP

Dtype Decode tok/s TTFT (ms) vs f16 (decode)
f16 15.8 327 baseline
Q4_K_M 28.5 494 +80.4%
NF4 8.3 443 −47.5%

Key findings

  1. Q4_K_M wins overall. Fastest decode on CPU (+80%) and slightly faster than f16 on CUDA (+4%), with a ~3.1x smaller decoder (4.73 GB → 1.51 GB). No quality regression observed in spot checks (consistent with the L4/L5 golden tests).
  2. NF4 is not worth it for inference. Slower than f16 on both CUDA (−14%) and CPU (−47%) despite similar size to Q4_K_M.
  3. Quantization raises TTFT but lowers decode latency. Prefill is compute-bound and pays a dequant cost (TTFT f16 7.5 ms → Q4_K_M 10.4 ms on CUDA), while decode is memory-bandwidth-bound and benefits from the smaller weights. For typical chat workloads (decode-dominated) the net effect is a win.
  4. Single-token batch=1 decode underutilizes the H200 — throughput is memory-bound, so the absolute CUDA tok/s would not improve much on a larger GPU. Batching would.

gemma-4-12B (unified multimodal) — status

12B was exported (bf16 + Q4_K_M, decoder 23 GB → 6.8 GB) and the files load, but end-to-end genai generation is not yet runnable here: the global-attention layers (head_dim=512) emit the standard Attention op, which has no CUDA kernel and falls back to the CPU EP, where it fails on the mixed-KV-cache total_sequence_length check. Tracking separately; not included in the throughput numbers above. (A bf16 loadability fix for the unified vision/audio Compress op landed in 44fdbd0.)

Reproduction

# Export
mobius build --model google/gemma-4-E2B-it --dtype f16 --ep cuda \
  --runtime ort-genai /tmp/g4e2b/f16/cuda/
# Quantize (Olive, decoder only) — see examples/gemma4_unified_ort_genai.py:quantize_decoder
# Benchmark: 92-tok prompt, 64-tok forced greedy decode, 2 warmup + best-of-3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions