Skip to content

Commit 2b3a32d

Browse files
Export an MLX model for the iOS demo build (pytorch#22297)
## Problem The mv3 demo app is gaining an MLX option. Its Xcode project will bundle `mv3_mlx.pte`, so the iOS CI job that stages models for the demo has to produce that file, or the build fails on a missing resource. ## Change Lower the model to MLX inline, the same way the script already drives the portable, Core ML and XNNPACK exports (there is no generic `examples/` entry point that takes a model name and lowers it to MLX). The same export is added to both iOS scripts. The check reads the delegates directly off the program and fails unless the model produced an MLX delegate. The MLX partitioner only logs a warning when it delegates nothing and still returns a valid program, so without this a model with no MLX delegate would be staged under an MLX name and the demo would still pass on the portable kernels. The check runs before the file is written. ## Landing order This change must land first. It produces `mv3_mlx.pte`; the demo change consumes it. The scripts clone the demo's default branch, so if the demo landed first its project would require a model this script does not yet produce and the iOS build would break. ## Test Plan Ran the lowering and the delegate check against a delegated model: the count is 1 and the file is written; a non-delegated program gives 0 and the check fails before writing anything. Runtime execution of the staged model is not exercised here; delegate presence is. Co-authored-by: PyTorch Bot <pytorchbot@users.noreply.github.com>
1 parent beb5b16 commit 2b3a32d

2 files changed

Lines changed: 74 additions & 0 deletions

File tree

‎.ci/scripts/test_ios_ci.sh‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,43 @@ python3 -m examples.portable.scripts.export --model_name="$MODEL_NAME" --segment
4949
python3 -m examples.apple.coreml.scripts.export --model_name="$MODEL_NAME"
5050
python3 -m examples.xnnpack.aot_compiler --model_name="$MODEL_NAME" --delegate
5151

52+
# No generic examples/ entry point takes a model name and lowers it to MLX, so do
53+
# it here. Lowering is ahead of time and imports no mlx runtime package. Assert MLX
54+
# claimed the graph before writing: the partitioner only warns when it delegates
55+
# nothing, so without this a program with no MLX delegate would be staged.
56+
python3 - "$MODEL_NAME" <<'PY'
57+
import sys
58+
59+
import torch
60+
from executorch.backends.mlx import MLXPartitioner
61+
from executorch.examples.models import MODEL_NAME_TO_MODEL
62+
from executorch.examples.models.model_factory import EagerModelFactory
63+
from executorch.exir import EdgeCompileConfig, to_edge_transform_and_lower
64+
65+
model_name = sys.argv[1]
66+
model, example_inputs, _, _ = EagerModelFactory.create_model(
67+
*MODEL_NAME_TO_MODEL[model_name]
68+
)
69+
program = to_edge_transform_and_lower(
70+
torch.export.export(model.eval(), example_inputs),
71+
partitioner=[MLXPartitioner()],
72+
compile_config=EdgeCompileConfig(_skip_dim_order=True),
73+
).to_executorch()
74+
75+
segments = sum(
76+
delegate.id == "MLXBackend"
77+
for plan in program.executorch_program.execution_plan
78+
for delegate in plan.delegates
79+
)
80+
if segments == 0:
81+
raise SystemExit(f"error: {model_name} produced no MLX delegate")
82+
83+
path = f"{model_name}_mlx.pte"
84+
with open(path, "wb") as file:
85+
program.write_to_file(file)
86+
print(f"{path}: {segments} MLX delegate segment(s)")
87+
PY
88+
5289
mkdir -p "$APP_PATH/Resources/Models/MobileNet/"
5390
mv $MODEL_NAME*.pte "$APP_PATH/Resources/Models/MobileNet/"
5491

‎scripts/test_ios.sh‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,43 @@ python3 -m examples.portable.scripts.export --model_name="$MODEL_NAME"
6666
python3 -m examples.apple.coreml.scripts.export --model_name="$MODEL_NAME"
6767
python3 -m examples.xnnpack.aot_compiler --model_name="$MODEL_NAME" --delegate
6868

69+
# No generic examples/ entry point takes a model name and lowers it to MLX, so do
70+
# it here. Assert MLX claimed the graph before writing: the partitioner only warns
71+
# when it delegates nothing. This needs the MLX backend built, which the installer
72+
# does only on Apple Silicon with the Metal compiler present.
73+
python3 - "$MODEL_NAME" <<'PY'
74+
import sys
75+
76+
import torch
77+
from executorch.backends.mlx import MLXPartitioner
78+
from executorch.examples.models import MODEL_NAME_TO_MODEL
79+
from executorch.examples.models.model_factory import EagerModelFactory
80+
from executorch.exir import EdgeCompileConfig, to_edge_transform_and_lower
81+
82+
model_name = sys.argv[1]
83+
model, example_inputs, _, _ = EagerModelFactory.create_model(
84+
*MODEL_NAME_TO_MODEL[model_name]
85+
)
86+
program = to_edge_transform_and_lower(
87+
torch.export.export(model.eval(), example_inputs),
88+
partitioner=[MLXPartitioner()],
89+
compile_config=EdgeCompileConfig(_skip_dim_order=True),
90+
).to_executorch()
91+
92+
segments = sum(
93+
delegate.id == "MLXBackend"
94+
for plan in program.executorch_program.execution_plan
95+
for delegate in plan.delegates
96+
)
97+
if segments == 0:
98+
raise SystemExit(f"error: {model_name} produced no MLX delegate")
99+
100+
path = f"{model_name}_mlx.pte"
101+
with open(path, "wb") as file:
102+
program.write_to_file(file)
103+
print(f"{path}: {segments} MLX delegate segment(s)")
104+
PY
105+
69106
mkdir -p "$APP_PATH/Resources/Models/MobileNet/"
70107
mv $MODEL_NAME*.pte "$APP_PATH/Resources/Models/MobileNet/"
71108

0 commit comments

Comments
 (0)