Repository navigation
Conversation
- Add the copyright header. - Use RotatingKVCache and create_attention_mask for the sliding-window layers instead of a custom cache (also enables batched generation). - Narrow the tokenizer fallback to the errors Transformers raises for a config it cannot parse. - Add a test for a sliding-window layer decoded past the window. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Independent M1 Pro numbers from nace-ai/kapitsa#296: with this PR, Dory 4-bit decode holds ~28 tok/s at 1K context and ~19 tok/s at 32K (−31%). On an M5 Max (128 GB), plain mlx-lm at this PR (208065f), 8-bit, 2 loops, per-loop KV, temp 0, no speculation, medians of 3 runs (1 GiB MLX cache limit, which costs ~5–7% of prefill speed; decode unaffected):
So 8-bit decode drops ~22% from a short prompt to 32K. The PR runner and the dory-mlx package agree within ~3%. Earlier single run with the snsnc 4-bit weights, short prompt: 103 tok/s decode, 2.5 GB peak. Edit: updated with a rerun using exact 4K/16K/32K prompts and medians of 3. Happy to add anything else you need for review. |
|
Tested this PR on an M3 Pro (18 GB) with bf16, 8-bit, 6-bit and 4-bit builds at k = 1, 2, 4. Works well; full results and charts are on the model card here: https://huggingface.co/xquantize/nemotron-labs-dory1.0-4b-mlx-6bit One thing I noticed in If only the recurrent layers need a full cache for the slot-overwriting, something like this might work (untested): recurrent = a.n_input_layers <= i < a.n_input_layers + a.n_recurrent_layers
if a.layer_types[i] == "sliding_attention" and (use_sliding or not recurrent):
caches[idx] = RotatingKVCache(max_size=a.sliding_window)Related question: in Other small notes: the transformers tokenizer warning about |
…op mode In last_loop mode every attention layer got a full KVCache, including the input/output sliding-window layers that never loop. Only the recurrent layers need a full cache (later loops rewind cache.offset and overwrite the same slots); the others now use RotatingKVCache, as in per_loop mode. Outputs are unchanged: the window was already enforced by the attention mask. Add tests for the cache types in both modes and for chunked prefill plus decoding past the window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y3oaigHexmLYKR4qtodemx
|
Thanks @xquantize, good catch, and thanks for the multi-quant testing. Pushed 986ab63: in Is the window still enforced in KV cache after prefill (sum of keys + values), 8-bit, M5 Max:
The recurrent layers still hold most of the Tests added in
Thanks also for the tokenizer and 4-bit KL notes. |
Seed before building the attention layer and set its scale parameters to initializer_range, as test_dory_last_loop_past_window does; with unseeded all-ones scales the attention was sharp enough to fail the 1e-3 tolerance on some draws (4/10 runs on mlx 0.32.4, 1/10 on mlx main, Apple M5 Max). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y3oaigHexmLYKR4qtodemx
|
Pushed a small fix for a flaky test (test_dory_sliding_window_cache now seeds before building the layer; 50/50 passes on mlx 0.32.4 and main). Also checked against current main: rebases cleanly, and Dory tests and real-weight parity pass on mlx main (which includes #4734); the fused sliding-window path also matches Dory's window mask exactly, so it can be adopted once it ships. Could a maintainer approve the CI workflow run? Thanks! |
In last_loop mode every attention layer got a full KVCache, including the input/output sliding layers that never loop. They now use RingKVCache, as in per_loop mode; recurrent layers keep a full KVCache because later loops rewind cache.offset. Same fix as ml-explore/mlx-lm#1988 (986ab63), reported by xquantize. Outputs are unchanged; the default per_loop mode is unaffected. Adds tests/test_cache.py (tiny model, CPU or Metal): cache types per mode, chunked prefill + decode past the window for chunk sizes 5 and 12. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018fMGCd4TGVaMDBJ2NMDk8E
|
Quick status update:
The CI workflow is still waiting for approval. Could a maintainer approve the run when convenient? Happy to make any changes. |
Requirements
Model information
dory), a looped nGPT-style reasoning model (16 input layers, 40 shared layers runn_recurrent_loopstimes, 16 output layers; 72 layers alternating attention and MLP, sliding window 1024 with a full-attention layer every 8)Supported checkpoints
sanitizefuses the q/k/v/gate and MLP gate/up weights when loading)Verification
Run mlx-lm command:
mlx_lm.generate --model netprojects/nemotron-dory1.0-4b-mlx-8bit -p "The secret to baking a good cake is" -m 1024Output (shortened; the model reasons first, and the 1024-token limit stopped it before the final answer):
Other checks:
test_doryadded totests/test_models.py(passes).Note on the tokenizer: the released Transformers (5.20.1) does not know
doryand rejects themlpentries inlayer_types, soAutoTokenizerfails on this checkpoint. This PR therefore adds a fallback intokenizer_utils.loadthat loads the fast tokenizer directly from the checkpoint's tokenizer files whenAutoTokenizerfails. Token ids match the rawtokenizer.jsonon the texts I tried.Reference output (if you have access to CUDA hardware)
No CUDA hardware, not run.