Skip to content

[Ascend] Tensor.exponential_() produces 1024 NaNs for large tensors (n >= 65536) — breaks LLM random sampling #6446

Description

@Al2O3Al2O3

[Ascend] Tensor.exponential_() produces 1024 NaNs for large tensors (n ≥ 65536) — breaks all LLM random sampling

Repo: https://github.com/flagos-ai/FlagGems

Summary

FlagGems' exponential_ op (flag_gems/ops/exponential_.py, Triton kernel) on
the Ascend backend writes exactly 1024 NaN values into large output tensors.
For tensors with a trailing dimension n ≥ 65536 the last (or one) 1024-element
block comes out as NaN instead of an exponential-distributed value; smaller
tensors are fine.

This silently breaks all random sampling in vLLM on Ascend. vLLM's
random_sample does q = torch.empty_like(probs); q.exponential_(); probs.div_(q).argmax(-1).
With a vocab of 151936, q gets NaNs, probs / NaN = NaN, and argmax over an
all-NaN row returns index 0 — so every sampled token is id 0 and completions
degenerate to "!!!!". Greedy decoding (pure argmax, no exponential_) is
unaffected.

Environment

Component Version
flag_gems 5.4.0rc2.post3+gad89ec477
flagtree 0.7.0rc2+ascend3.5
vllm 0.20.2+flagos
torch / torch_npu 2.10.0
CANN 9.0.0
Device Ascend910_9382 (910C)

Minimal reproduction

import torch, torch_npu, flag_gems
flag_gems.enable()
d = torch.device("npu")

for n in [2048, 4096, 8192, 16384, 32768, 65536, 131072, 151936]:
    q = torch.empty((1, n), dtype=torch.float32, device=d)
    q.exponential_()
    print(n, "nan=", int(q.isnan().sum()))

Output:

2048   nan=0
4096   nan=0
8192   nan=0
16384  nan=0
32768  nan=0        # OK up to here
65536  nan=1024     # NaNs appear
131072 nan=1024
151936 nan=1024     # real Qwen3 vocab size

The NaN count is a constant 1024 regardless of tensor size once the
threshold (somewhere in 32768 < n ≤ 65536) is crossed — pointing at a
tiling / block-boundary bug in the kernel (one 1024-element block's philox /
safe_fast_log output is not written correctly). uniform_() on the identical
tensor is fine, so this is specific to exponential_, not a general RNG or
memory-layout issue.

How it was found (in a live vLLM server)

Instrumenting random_sample in a running TP=2 server, for a
temperature=1.0 request:

[DIAG] q_dtype=float32 q_contig=True q_isnan=1024 exp_nan=1024 uni_nan=0 \
       pmax=0.41 psum=1.0 pnan=0 arg=[0]

i.e. probs is correct (sums to 1, no NaN), but q from exponential_() has
1024 NaNs, so the sampled token collapses to 0. uniform_() on the same tensor
in the same process returns valid values.

Impact

No usable random sampling on Ascend for any model with a large vocab (Qwen3,
etc.). Combined with the separate Triton top-k/top-p compile crash
(FlagTree issue: _topk_topp_kernel / ConvertTritonIRToLinalgIR PassManager),
there is currently no working sampling path on this Ascend stack — only
greedy decoding works.

Ask

Fix the block-boundary handling in the Ascend exponential_ Triton kernel so
large tensors don't emit NaN. Happy to provide the dumped kernel or run further
diagnostics.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1Priority 1 - highbugSomething isn't workingflagos2.2-rc2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions