Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ed80f41
DFlash Phase 2: draft model definition, HF weight loading, and .pte e…
cthotti Jul 4, 2026
e0420a3
DFlash: consolidate tests
cthotti Jul 5, 2026
7be25cd
Add DFlash speculative decoding support for Qwen3
cthotti Jul 10, 2026
01c4e82
Address code review: drop dead Makefile target, fix pytest-collection…
cthotti Jul 14, 2026
8e6b664
Benchmarking on different Apple hardware.
cthotti Jul 16, 2026
962ce9c
Creating Dflash_experiments.md to document every experiment run for n…
cthotti Jul 21, 2026
9f86c90
Implementing Dflash_experiments.md for next users.
cthotti Jul 21, 2026
d0ff89f
Remove accidently generated MLX artifacts
cthotti Jul 22, 2026
dee17b9
Making some changes with the review
cthotti Jul 23, 2026
604fdce
Add Gemma-4-31B dflash hidden-state export wrapper
cthotti Jul 23, 2026
1e0912b
Fix stale MLX nax.h patch
cthotti Jul 23, 2026
9c7af26
Merge branch 'dflash-qwen3-4b' of https://github.com/cthotti/executor…
cthotti Jul 23, 2026
40da064
Gemma4-31B DFlash target export
cthotti Jul 24, 2026
f2f05f7
Gemma4-31B dflash draft model export script
cthotti Jul 24, 2026
2c42ab3
Dflash draft model: incremental KV caching
cthotti Jul 24, 2026
5a5769f
Dflash draft model
cthotti Jul 24, 2026
d7d7c65
incremental draft kv caching implementation
cthotti Jul 24, 2026
113346f
revert incremental draft kv caching
cthotti Jul 24, 2026
809f327
Add Gemma4-31B DFlash experiments write-up
cthotti Jul 24, 2026
85a967c
Standalone C++ Dflash driver for Gemma4-31B
cthotti Jul 24, 2026
2c082a0
Gemma4-31B DFlash export files and cleanup
cthotti Jul 28, 2026
182f2bc
Fetching and merging upstream changes
cthotti Jul 28, 2026
41de477
Resolving linting errors and other dependency issues
cthotti Jul 28, 2026
1f0894b
Apply lintrunner auto-fixes more
cthotti Jul 28, 2026
5529555
Adapt draft to HF Qwen3 modules, dynamic block_len, draft KV cache
cthotti Aug 6, 2026
7261f77
Remove gemma4-31b dflash implementations
cthotti Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ xcuserdata/
/src/executorch/include/
/src/executorch/share/
/src/executorch/version.py
/dflash_benchmarks.md
*_etdump

# Android
Expand All @@ -85,3 +86,6 @@ zephyr_dev_root.backup.*/
# Agents
.claude/*.local.*
extension/pybindings/mlx.metallib

# Scratch/WIP work not ready for review -- never committed
/wip/
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,8 @@ clean:
rm -rf cmake-out \
extension/llm/tokenizers/build \
extension/llm/tokenizers/pytorch_tokenizers.egg-info

# qwen3_dflash-mlx target removed: it depended on the C++ engine sources
# (CMakeLists.txt, CMakePresets.json, qwen3_dflash_engine.*), which are
# gitignored/not yet landed. Restore this target in the follow-up PR that
# actually lands the C++ engine.
9 changes: 9 additions & 0 deletions backends/mlx/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Auto-generated by backends/mlx/serialization/generate.py — do not commit.
# See backends/mlx/serialization/README.md for regeneration instructions.
runtime/MLXLoader.cpp
runtime/MLXLoader.h
runtime/schema_generated.h
serialization/_generated/
serialization/_generated_serializers.py
serialization/mlx_graph_schema.py
_generated_inspector.py
70 changes: 70 additions & 0 deletions backends/mlx/examples/llm/dflash_draft_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

"""Persistent per-layer KV cache for the DFlash draft model.

Follows the TorchExportableModuleWithStaticCache pattern (per review): cache
tensors are registered as mutable buffers and cache_position is passed
through the call rather than tracked internally. Built on the existing
KVCache (backends/mlx/llm/cache.py), so writes go through
torch.ops.mlx.kv_cache_update instead of a Python slice (avoids the
GuardOnDataDependentSymNode failure hit by an earlier attempt).
"""

from typing import Tuple, Union

import torch
import torch.nn as nn

from executorch.backends.mlx.llm.cache import KVCache


class DFlashDraftKVCache(nn.Module):
def __init__(
self,
num_layers: int,
num_heads: int,
head_dim: int,
max_seq_len: int,
dtype: torch.dtype = torch.float32,
):
super().__init__()
self.max_seq_len = max_seq_len
self.layers = nn.ModuleList(
[
KVCache(
max_batch_size=1,
max_context_length=max_seq_len,
n_heads=num_heads,
head_dim=head_dim,
enable_dynamic_shape=True,
dtype=dtype,
)
for _ in range(num_layers)
]
)

def write(
self,
layer_idx: int,
key_states: torch.Tensor,
value_states: torch.Tensor,
cache_position: Union[torch.Tensor, int],
) -> Tuple[torch.Tensor, torch.Tensor]:
# Write K/V at cache_position and return the FULL buffer for this
# layer. Caller masks the unwritten tail via valid_mask(). Extract
# cache_position once and reuse across layers, not once per layer.
return self.layers[layer_idx].update(cache_position, key_states, value_states)

def valid_mask(self, valid_len: Union[torch.Tensor, int], device=None) -> torch.Tensor:
# True for positions [0, valid_len), False for the unwritten tail.
positions = torch.arange(self.max_seq_len, device=device)
return positions < valid_len

def reset(self) -> None:
for layer in self.layers:
layer.k_cache.zero_()
layer.v_cache.zero_()
Loading
Loading