Glyd

Report · · Glyd

Qwen3-32B on one 48 GB GPU, bit for bit

Glyd holds Qwen3-32B's weights in 44.5 GB instead of 65.5, so it runs on one 48 GB RTX A6000 instead of two, every weight exact and faster.

Qwen3-32B’s weights take 65.5 GB in bf16, more than one 48 GB GPU holds. Glyd stores the same weights in 44.5 GB and decodes them inside the matrix multiply, so the model runs on one RTX A6000 instead of two. Every weight decodes to exactly the bf16 value it was, and on one GPU Glyd generates more tokens a second than bf16 does on two.

What nvidia-smi showed

The runs took nvidia-smi with the model loaded (e2e.py --smi). In bf16 the model spills onto a second GPU: 44,554 MiB on the first and 18,514 MiB on the second. With Glyd it runs on one, at 43,338 of the 49,140 MiB an RTX A6000 has, which leaves 5,802 MiB to spare.1

GPU memory in use with Qwen3-32B loaded, as nvidia-smi reports it. The black line is one RTX A6000's 49,140 MiB. Lambda Cloud, 4× RTX A6000 (48 GB each), Sep 26, 2026.

The results

The same runs, bf16 and Glyd side by side on the same machine. Qwen2.5-72B went the same way: four 48 GB GPUs in bf16, three with Glyd.

The same runs bf16 Glyd
Qwen3-32B: weights 65.5 GB 44.5 GB
Qwen3-32B: 48 GB GPUs it takes 2 1
Qwen3-32B: tokens/s at 1 / 8 / 32 sequences 9.5 / 74 / 276 11.8 / 95 / 290
Qwen3-32B: MMLU, 1,000 questions 78.5% 78.0%
Qwen2.5-72B: weights 145.4 GB 97.8 GB
Qwen2.5-72B: 48 GB GPUs it takes 4 3
Qwen2.5-72B: tokens/s at 1 / 8 / 32 sequences 4.5 / 35 / 135 6.4 / 49 / 154
Qwen2.5-72B: MMLU, 1,000 questions 81.9% 81.8%
KV cache, Qwen2.5-7B, 16K tokens 947 MB 651 MB

On one GPU, Glyd’s Qwen3-32B generates 24% more tokens a second than bf16 across two at one sequence, 28% more at 8 and 5% more at 32.

Tokens per second at 1, 8 and 32 sequences: bf16 on two GPUs 9.5, 74 and 276; Glyd on one GPU 11.8, 95 and 290.
Sequences a stepbf16, two GPUsGlyd, one GPU
19.511.8
87495
32276290
Tokens per second, Qwen3-32B on RTX A6000s: bf16 across two GPUs, Glyd on one. Higher is better; log scale. Lambda Cloud, Sep 26, 2026.

On an H100 SXM, where both fit on one GPU, the model’s GPU time a token with q, k, v and gate, up merged as vLLM runs them was 12% lower with Glyd at one sequence and 10% lower at 8. At 32 and 64 sequences a step the decode work shows and Glyd took 6% and 11% more time.

GPU time per generated token, Qwen3-32B on an H100 SXM. Lower is better. Sep 26, 2026.

Same weights, same model

Glyd changes how the weights are stored, not what they are: every weight decodes to exactly the bf16 value it was. The scores still move a hair, because the matrix products add their terms in a different order than cuBLAS does, as any two GPU kernels do, so a few close answers can flip either way.2 On 1,000 MMLU questions Qwen3-32B scored 78.5% in bf16 and 78.0% with Glyd; Qwen2.5-72B scored 81.9% and 81.8%.

Method

  • Speed: tokens per second at 1, 8 and 32 sequences a step, with greedy decoding. On the H100, GPU time of a generated token apart from the prompt: 17 steps less 1, over 16.
  • Like a server: q, k, v as one product and gate, up as another, for bf16 and Glyd alike, as vLLM runs them.
  • Memory: nvidia-smi during the runs, taken by e2e.py --smi.
  • Quality: MMLU, 1,000 questions, bf16 against Glyd in the same run.
  • Exactness: every matrix packed, unpacked and compared bit for bit.
  • Hardware: Lambda Cloud, 4× RTX A6000 (48 GB each). The driver, CUDA and PyTorch versions are in the log.

Reproduce it

The harness packs the weights, checks every one bit for bit, and runs bf16 and Glyd side by side:

git clone https://github.com/surya-koritala/Glyd
cd Glyd/gpu
python e2e.py /models/Qwen3-32B --format auto --fused \
  --merge --baseline --batch 1,8,32

Raw logs

Every run’s log and the nvidia-smi output are in the repository: benchmarks/gpu/lambda-gpu_4x_a6000-20260926-084757.

Footnotes

  1. nvidia-smi counts in MiB: 49,140 MiB is 51.5 GB in decimal units, while Hugging Face lists the weights in decimal GB. ↩

  2. Floating-point addition is not associative, so two kernels that sum the same products in a different order can round the last bit differently. The weights themselves are identical. ↩