Skip to content

Commit fbeb316

Browse files
authored
[PyTorch] Fix fake kernel metadata mismatch for empty-input MoE permute ops (#3444)
Fix fake kernel metadata mismatch for empty-input MoE permute ops For empty input, moe_permute (mask and index map) returned row_id_map created with torch.tensor([]) (float32), while the registered fake kernels declare int32 with different shapes. PyTorch >= 2.14 inductor validates fallback output dtype metadata at runtime (pytorch#183731), so torch.compile'd empty-input permute now errors with 'expected dtype torch.int32 but got torch.float32'. Return correctly-typed empty tensors from the eager fast paths, align the index-map fake output shape with the empty-input fast path, and keep permuted_probs dtype consistent between eager and fake. Add an empty-input test for the index map path. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
1 parent 4fba94a commit fbeb316

2 files changed

Lines changed: 32 additions & 10 deletions

File tree

‎tests/pytorch/test_permutation.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,25 @@ def test_permutation_index_map(
17051705
)
17061706

17071707

1708+
@pytest.mark.parametrize("te_dtype", _te_dtypes)
1709+
@pytest.mark.parametrize("use_torch_compile", [False, True])
1710+
def test_permutation_index_map_empty_input(te_dtype, use_torch_compile):
1711+
with_probs = True
1712+
BENCHMARK = False
1713+
1714+
_test_permutation_index_map(
1715+
te_dtype=te_dtype,
1716+
num_tokens=0,
1717+
num_expert=8,
1718+
hidden_size=4096,
1719+
topK=2,
1720+
num_out_tokens=0,
1721+
with_probs=with_probs,
1722+
BENCHMARK=BENCHMARK,
1723+
use_torch_compile=use_torch_compile,
1724+
)
1725+
1726+
17081727
@pytest.mark.parametrize("te_dtype", _te_dtypes)
17091728
@pytest.mark.parametrize("num_tokens", [4096])
17101729
@pytest.mark.parametrize("num_expert", [7, 16])

‎transformer_engine/pytorch/permutation.py‎

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def moe_permute_index_map_forward(
4242
global _moe_permute_index_map_workspace, _moe_permute_index_map_max_expanded_token_num
4343

4444
if not inp.numel():
45-
return inp.clone(), torch.tensor([], device=inp.device)
45+
return inp.clone(), torch.empty(0, dtype=torch.int32, device=inp.device)
4646

4747
if not inp.is_cuda:
4848
raise ValueError(f"inp must be a CUDA tensor, but got tensor on {inp.device}.")
@@ -98,9 +98,10 @@ def _moe_permute_index_map_fake( # pylint: disable=unused-argument
9898
assert (
9999
num_out_tokens >= 0
100100
), f"moe_permute (index map) requires num_out_tokens >= 0, got {num_out_tokens}."
101-
102-
# Infer output shape
103-
output_tokens = num_out_tokens if num_out_tokens > 0 else num_tokens * topK
101+
output_tokens = num_out_tokens if num_out_tokens > 0 else num_tokens * topK
102+
else:
103+
# Match `moe_permute_index_map_forward` empty-input fast path (ignores num_out_tokens).
104+
output_tokens = 0
104105

105106
# row_id_map is 1D with size = num_tokens * topK
106107
fake_output = torch.empty((output_tokens, inp.shape[1]), dtype=inp.dtype, device=inp.device)
@@ -290,7 +291,13 @@ def moe_permute_mask_map_forward(
290291
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
291292
"""Forward pass for MoE permute with mask router map."""
292293
if not inp.numel():
293-
return inp.clone(), torch.tensor([], device=inp.device), torch.tensor([], device=inp.device)
294+
row_id_map = torch.empty(
295+
(0, routing_map.size(1) * 2 + 1), dtype=torch.int32, device=inp.device
296+
)
297+
permuted_probs = torch.empty(
298+
0, dtype=probs.dtype if probs is not None else torch.float32, device=inp.device
299+
)
300+
return inp.clone(), row_id_map, permuted_probs
294301

295302
if not inp.is_cuda:
296303
raise ValueError(f"inp must be a CUDA tensor, but got tensor on {inp.device}.")
@@ -450,11 +457,7 @@ def _moe_permute_mask_map_forward_fake( # pylint: disable=unused-argument
450457
(num_tokens, num_experts * 2 + 1), dtype=torch.int32, device=inp.device
451458
)
452459
if probs is not None:
453-
fake_permuted_probs = (
454-
torch.empty((out_rows,), dtype=probs.dtype, device=inp.device)
455-
if out_rows > 0
456-
else torch.empty(0, device=inp.device)
457-
)
460+
fake_permuted_probs = torch.empty((out_rows,), dtype=probs.dtype, device=inp.device)
458461
else:
459462
fake_permuted_probs = torch.empty(0, device=inp.device)
460463
return fake_output, fake_row_id_map, fake_permuted_probs

0 commit comments

Comments
 (0)