Pull requests / #2955
#2955 engine: f32 -> bf16 conversions in PLE and prefill keep a NaN a NaN (as bf16_bits.hpp does)
open · @sergqwer · 0 コメント · GitHub で見る
Setup & installServer & APINVIDIA / CUDAModels & quantsSecurityWindows
本文
The engine has private f32 -> bf16 helpers that round to nearest even. Unlike `bf16_bits.hpp` (`bf16_from_f32`) and `dequant_bf16.cu`, they have no NaN test. The rounding add carries a NaN out of the mantissa, so the NaN is masked instead of reaching the NaN guard. For example, 0x7FFFFFFF (the NaN pattern in #879) becomes 0x8000, i.e. -0. **The fix** is sebastianrcnt's (sebastianrcnt/Strata ef1a7ef5, co-author of this commit). Each helper tests the magnitude bits first and returns the top half with the quiet bit set (`(i >> 16) | 64`), sign kept. It applies to: - `src/kernels/cuda/ple.cu` `bf16_bits` (`to_bf16_kernel`); - `src/prefill/kernels.cu` `bf`: the BF16 activation image of every prefill norm on CUDA, plus `bf_lo` and dequant. The two host dumps in `src/prefill/prefill.cpp` get the same test: - `STRATA_PREFILL_DUMP_R_ALL`, which rounds to nearest even; - the `STRATA_DBG_FEAT` route record, which rounds half up. That rounding is kept; only the NaN test is new. Left alone: - host references in parity tests and benches, which see finite data; - `fused_gr.cu` `hc_q8_bf16_kernel`: weights x scales, and its comment says the values are finite; - `sycl/`. **Proof over all 2^32 f32 bit patterns.** - How: a generator copies the four helpers verbatim from 477ac13c and from this branch into one CUDA file. That file compares old with new on the host (all four helpers) and on the device (the two device helpers, RTX 5090, sm_120, nvcc 13.3). | check | host | device | | --- | --- | --- | | non-NaN inputs that convert differently, old vs new | 0 | 0 | | NaN inputs that do not give a quiet NaN of the same sign (new) | 0 | 0 | | new round-to-nearest-even helpers != `bf16_from_f32` | 0 | 0 | | NaN inputs the old `bf16_bits` / `bf` masked (of 16,777,214) | 131,072 / 131,072 | 131,072 / 131,072 | **Engine identity.** - Builds: 477ac13c (upstream/main, v0.1.45) vs this branch, the same configure (MSVC 2022, CUDA 13.3, portable, `75-real;86-real;89-real;120-real`). - Machine: RTX 5090, Ryzen 9 9950X3D, 128 GB, Windows 11. - Model: the NVFP4 GPTQ pack (Maximilian228/Qwen3.8-Flash-Next-NVFP4-GPTQ-Strata). - Result: the first-token logits are byte-identical, and so are the greedy tokens (32 max; both stop at the end of turn), for a 2K and a 32K prompt: | prompt | sha256 of the first-token logits, both builds | greedy tokens | | --- | --- | --- | | 2K | `1e9c612c2e6c7a32...` | identical (4) | | 32K | `f5b2872c7ac30b17...` | identical (20) | **How to reproduce.** - Install with upstream's `python setup.py --family nvfp4 --model NVFP4`. - Start `strata --serve` with the model arguments setup writes, plus: - flags: `--expert-cache 3000 --prefill auto --spec 6 --spec-min-p 0.7 --max-context 262144 --kv int8 --pcie-frac 0 --adapt-every 1000000`; - env: `STRATA_PREFILL_CPU_SHARE=0 STRATA_PCIE_BALANCE=0 STRATA_IQ_MT_MIN=1 STRATA_DUMP_FIRST_LOGITS=<file>`. - Send a 2K and a 32K prompt, greedy, 32 tokens each, and compare the dumps. - All numbers above were measured on that pack with an upstream/main build. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01VZy1yKaDDiA8a7svdwaHio
関連リンク
インストール・モデル・リリースへの站内リンク。