Skip to content

Commit b9b16d4

Browse files
[executorch][muse-glimmer] Export DFlash sampling methods (pytorch#23145)
This PR was created by the merge bot to help merge the original PR into the main branch. ghstack PR number: pytorch#23086 by @Gasoonjia ^ Please use this as the source of truth for the PR details, comments, and reviews ghstack PR base: https://github.com/pytorch/executorch/tree/gh/Gasoonjia/30/base ghstack PR head: https://github.com/pytorch/executorch/tree/gh/Gasoonjia/30/head Merge bot PR base: https://github.com/pytorch/executorch/tree/gh/Gasoonjia/29/orig Merge bot PR head: https://github.com/pytorch/executorch/tree/gh/Gasoonjia/30/orig Differential Revision: [D119463646](https://our.internmc.facebook.com/intern/diff/D119463646/) @diff-train-skip-merge --------- Co-authored-by: gasoonjia <gasoonjia@icloud.com>
1 parent 03b6e9d commit b9b16d4

3 files changed

Lines changed: 79 additions & 1 deletion

File tree

‎examples/models/muse-glimmer/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ advanced inputs.
119119
|---|---|---|
120120
| Target | CUDA | `embed_text`, `forward_from_embeddings`, `decode_from_embedding` |
121121
| Target | MLX | `embed_text`, `forward_from_embeddings` |
122-
| DFlash | CUDA | `target_forward_from_embeddings`, `target_prefill_from_embeddings`, `embed_text`, `draft_forward`, `draft_prefill` |
122+
| DFlash | CUDA | `target_forward_from_embeddings`, `target_prefill_from_embeddings`, `embed_text`, `draft_forward`, `draft_prefill`, `dflash_sample_tokens`, `dflash_verify_speculative` |
123123
| DFlash | MLX | `target_forward_from_embeddings`, `embed_text`, `draft_forward` |
124124

125125
Vision adds `vision_encoder` to each method set.

‎examples/models/muse-glimmer/export/export_dflash.py‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,51 @@ def _max_draft_prefill_len(draft_config, max_target_prefill: int) -> int:
4747
return max_target_prefill
4848

4949

50+
def _export_cuda_sampler_methods(
51+
max_draft_tokens: int, vocab_size: int
52+
) -> dict[str, torch.export.ExportedProgram]:
53+
from executorch.examples.models.muse_glimmer.model.dflash_token_sampler import (
54+
DFlashSpeculativeVerifier,
55+
DFlashTokenSampler,
56+
)
57+
from torch.export import Dim, export
58+
59+
proposals = Dim("dflash_proposals", min=1, max=max_draft_tokens)
60+
temperature = torch.tensor([1.0])
61+
top_k = torch.tensor([0], dtype=torch.long)
62+
top_p = torch.tensor([1.0])
63+
return {
64+
"dflash_sample_tokens": export(
65+
DFlashTokenSampler(),
66+
(torch.zeros(max_draft_tokens, vocab_size), temperature, top_k, top_p),
67+
dynamic_shapes=({0: proposals}, None, None, None),
68+
strict=True,
69+
),
70+
"dflash_verify_speculative": export(
71+
DFlashSpeculativeVerifier(),
72+
(
73+
torch.zeros(max_draft_tokens + 1, vocab_size),
74+
torch.zeros(max_draft_tokens, vocab_size),
75+
torch.zeros(max_draft_tokens + 1, dtype=torch.long),
76+
temperature,
77+
top_k,
78+
top_p,
79+
torch.tensor([False]),
80+
),
81+
dynamic_shapes=(
82+
{0: proposals + 1},
83+
{0: proposals},
84+
{0: proposals + 1},
85+
None,
86+
None,
87+
None,
88+
None,
89+
),
90+
strict=True,
91+
),
92+
}
93+
94+
5095
def export_dflash(
5196
output_dir: str,
5297
target_gguf: str | None = None,
@@ -606,6 +651,14 @@ def _export_dflash_cuda(
606651
strict=True,
607652
)
608653

654+
print("=" * 60)
655+
print("Exporting DFlash sampling methods...")
656+
print("=" * 60)
657+
sampler_methods = _export_cuda_sampler_methods(
658+
max_draft_tokens=exported_block_size - 1,
659+
vocab_size=target_config.vocab_size,
660+
)
661+
609662
mutable_buffer_metadata = common.mutable_buffer_metadata(combined)
610663
del combined, target_model, draft_model
611664
if vision_model is not None:
@@ -636,6 +689,7 @@ def cuda_partitioner(method: str) -> CudaPartitioner:
636689
"embed_text": embed_text_ep,
637690
"draft_forward": draft_ep,
638691
"draft_prefill": draft_prefill_ep,
692+
**sampler_methods,
639693
}
640694
if vision_ep is not None:
641695
methods["vision_encoder"] = vision_ep
@@ -677,6 +731,7 @@ def cuda_partitioner(method: str) -> CudaPartitioner:
677731
embed_text_ep,
678732
draft_ep,
679733
draft_prefill_ep,
734+
sampler_methods,
680735
vision_ep,
681736
)
682737
gc.collect()

‎examples/models/muse-glimmer/tests/test_export_dflash.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
from unittest import TestCase
1010

11+
import torch
12+
1113
from executorch.examples.models.muse_glimmer.export import export_dflash
1214

1315

@@ -49,3 +51,24 @@ def test_mlx_vision_options_are_valid(self) -> None:
4951
def test_callable_rejects_unknown_backend(self) -> None:
5052
with self.assertRaisesRegex(ValueError, "Unsupported DFlash backend: cpu"):
5153
export_dflash.validate_dflash_export_options("cpu")
54+
55+
def test_cuda_sampler_methods_accept_any_proposal_count(self) -> None:
56+
methods = export_dflash._export_cuda_sampler_methods(
57+
max_draft_tokens=3, vocab_size=5
58+
)
59+
scalars = (torch.tensor([0.0]), torch.tensor([0]), torch.tensor([1.0]))
60+
for proposals in (1, 3):
61+
with self.subTest(proposals=proposals):
62+
tokens, probabilities = methods["dflash_sample_tokens"].module()(
63+
torch.randn(proposals, 5), *scalars
64+
)
65+
result = methods["dflash_verify_speculative"].module()(
66+
torch.randn(proposals + 1, 5),
67+
probabilities,
68+
torch.cat([torch.tensor([4]), tokens]),
69+
*scalars,
70+
torch.tensor([False]),
71+
)
72+
self.assertEqual(tokens.shape, torch.Size([proposals]))
73+
self.assertEqual(result.shape, torch.Size([proposals + 3]))
74+
self.assertEqual(result.dtype, torch.int64)

0 commit comments

Comments
 (0)