Skip to content

Commit fff2f71

Browse files
authored
[MLX] Small fixes to support HF runner (#23173)
As titled, to support huggingface/transformers#48986 It has two small fixes: 1. Accept empty tensors as input to support starting state for dynamic cache 2. Normalize symbolic ops
1 parent a1a43ff commit fff2f71

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

‎backends/mlx/partitioner.py‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,28 @@ def __init__(self, compile_specs: List[CompileSpec] | None = None) -> None:
117117
def transform_for_pre_decomposition(
118118
self, exported_program: ExportedProgram
119119
) -> ExportedProgram:
120-
"""Normalize SDPA ranks before deciding which ops to preserve."""
120+
"""Normalize symbolic ops and SDPA ranks before deciding which ops to preserve."""
121+
from executorch.exir.dialects.edge._ops import EdgeOpOverload
122+
from executorch.exir.passes.executorch_prim_ops_registry import (
123+
_EXECUTORCH_SYM_OPS,
124+
)
125+
126+
# Exporters may wrap symbolic primitives before this ATen-stage validation.
127+
for module in exported_program.graph_module.modules():
128+
if not isinstance(module, torch.fx.GraphModule):
129+
continue
130+
modified = False
131+
for node in module.graph.nodes:
132+
if (
133+
node.op == "call_function"
134+
and isinstance(node.target, EdgeOpOverload)
135+
and node.target in _EXECUTORCH_SYM_OPS
136+
):
137+
node.target = node.target._op
138+
modified = True
139+
if modified:
140+
module.recompile()
141+
121142
return ExportedProgramPassManager([NormalizeSDPAInputRankPass()])(
122143
exported_program
123144
).exported_program

‎backends/mlx/runtime/MLXBackend.cpp‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ namespace {
6868
array tensor_to_mlx(
6969
const ETTensor& t,
7070
const std::optional<TensorMeta>& expected_meta = std::nullopt) {
71-
if (!executorch::runtime::tensor_is_contiguous(t)) {
71+
if (t.numel() != 0 && !executorch::runtime::tensor_is_contiguous(t)) {
7272
throw std::runtime_error("tensor_to_mlx: input tensor is not contiguous");
7373
}
7474

@@ -97,6 +97,11 @@ array tensor_to_mlx(
9797
shape.push_back(static_cast<int>(dim_size));
9898
}
9999

100+
// Empty inputs have no storage to wrap, but retain their shape and dtype.
101+
if (t.numel() == 0) {
102+
return ::mlx::core::zeros(shape, dtype);
103+
}
104+
100105
// SAFETY: MLX reads this data during async_eval() Metal command encoding,
101106
// which completes before the lock is released. The ET tensor must remain
102107
// valid until async_eval returns.

0 commit comments

Comments
 (0)