Fix frozen PRNG in categorical_sampling under repeated sampling#1444
Fix frozen PRNG in categorical_sampling under repeated sampling#1444utkarshtiwari-24 wants to merge 1 commit into
Conversation
|
Thanks for the fix. Can you please give tokens per second numbers with/without compile for categorical sampling? |
Thanks for your comment. Here are the numbers: Benchmarks on an Apple M4 Pro (24GB), temp 1.0, 512 tokens, 5 runs each (generation tokens/sec): Qwen2.5-0.5B-4bit Qwen3.5-2B-4bit Qwen3.5-9B-4bit categorical_sampling only runs one op per token, so compiling it saves a tiny fixed amount per token. On a small model that's noticeable because each token is so fast (0.5B, ~3%), but on bigger models most of the time goes into the model itself, so it basically vanishes (~0.6% at 2B, ~0.3% at 9B). At normal model sizes it doesn't really affect speed. |
|
@nastya236 please review and merge the PR if approved. |
Problem
With
temperature > 0, repeated requests tomlx_lm.serverreturn identical text. The sampling stops being random after the first request.Root cause
categorical_samplingis decorated with@partial(mx.compile, inputs=mx.random.state, outputs=mx.random.state). In the server's generation loop the RNG state stops advancing after the first request, so every sample reuses the same state. Callingcategorical_samplingorgenerate()directly does not hit this (the state advances normally), so it only appears in the long-running compiled server path.Fix
Remove the decorator. The function is a single
mx.random.categoricalcall, so the compile gives little benefit, and without it the function uses the live global RNG state on each call.Repro
Start the server:
mlx_lm.server --model mlx-community/Qwen2.5-0.5B-Instruct-4bit
Run the below curl cmd twice:
curl -s localhost:8080/v1/chat/completions -H "Content-Type: application/json"
-d '{"messages":[{"role":"user","content":"Tell me a one-sentence story."}],"temperature":1.0,"max_tokens":40}'
Before, two identical requests return byte-identical completions:
After, they differ:
cached_tokensis still 36 on the second call after the fix, so prompt cache reuse is unaffected; only the RNG state changed.Testing
tests/test_sample_utils.pypasses. No unit test added: the freeze only reproduces in the compiled server loop, not a direct call, so a unit test would pass on the unfixed code too. Happy to add an integration test if preferred.Note:
apply_top_k,apply_top_p, andapply_min_pcarry the samerandom.statedecorator but do not use randomness. Left unchanged here.Fixes #1439