Skip to content

Commit ed72896

Browse files
authored
Arm backend: Make Model Explorer dependencies optional (pytorch#22993)
### Summary Related to pytorch#22314. Default Arm setup installs Model Explorer adapters that require Python below 3.13, even when visualization is unused. Make visualization opt-in with `--enable-model-explorer` and install its complete dependency graph in an isolated directory so its FlatBuffers requirements do not conflict with the TOSA toolchain. Update `run.sh` to request the optional dependencies during automatic setup, validate only the selected adapter, and expose the isolated packages only during visualization. Resolve Python from the active environment and check its major/minor version instead of retaining an absolute interpreter path. Document supported versions and reject unsupported visualization configurations early. The core toolchain versions remain unchanged. The existing `tosa-tools` pin still prevents Python 3.14 installation and needs a separate dependency upgrade. The PTE adapter also retains its upstream transitive dependency on the VGF adapter; this change adds no separate VGF requirement. Authored with assistance from Codex. ### Test plan On Python 3.12, installed the complete optional dependency graph into an isolated directory. `pip check`, deep PTE/TOSA adapter imports, and the Model Explorer CLI passed. Repeated validation after replacing the virtual environment and moving the installed packages. To repeat the isolated dependency checks from the repository root: ```bash check_dir=$(mktemp -d) python3.12 -m venv "$check_dir/venv" "$check_dir/venv/bin/python" -m pip install \ --ignore-installed --no-warn-conflicts \ --target "$check_dir/packages" \ -r backends/arm/requirements-arm-model-explorer.txt PYTHONPATH="$check_dir/packages" "$check_dir/venv/bin/python" -m pip check PYTHONPATH="$check_dir/packages" "$check_dir/venv/bin/python" -c \ 'import pte_adapter_model_explorer.main, tosa_adapter_model_explorer.main' PYTHONPATH="$check_dir/packages" "$check_dir/venv/bin/python" \ -m model_explorer --help ``` Passed 15 local shell behavior checks using a temporary harness with stubbed setup/export: early rejection of unsupported Python versions, sourced-shell behavior, automatic setup with and without visualization, selected-adapter validation, Python minor-version mismatch, invalid flags, and isolation from model export. This harness is not added to the repository. Shell syntax and whitespace checks passed: ```bash bash -n examples/arm/setup.sh bash -n examples/arm/run.sh git diff --check HEAD^ HEAD ``` Lintrunner and the Arm pre-push checks also passed, including license checks, documentation checks, VGF operator coverage, and public API manifest validation. Full model export and FVP execution were not rerun for this dependency-isolation change. cc @digantdesai @freddan80 @per @zingo @oscarandersson8218 @mansnils @Sebastian-Larsson @robell @rascani Signed-off-by: Usamah Zaheer <usamah.zaheer@arm.com>
1 parent fd5069d commit ed72896

6 files changed

Lines changed: 188 additions & 21 deletions

File tree

‎backends/arm/requirements-arm-ethos-u.txt‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@
66
# These dependencies need to match pyproject.toml
77

88
ethos-u-vela == 5.1.0
9-
pte-adapter-model-explorer == 0.0.2
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2026 Arm Limited and/or its affiliates.
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
# Model Explorer adapters currently require Python >=3.10,<3.13. These are
7+
# installed in an isolated target directory by examples/arm/setup.sh because
8+
# their FlatBuffers requirement conflicts with the TOSA toolchain.
9+
10+
numpy >= 2.0, < 2.2
11+
ai-edge-model-explorer == 0.1.28
12+
pte-adapter-model-explorer == 0.0.2
13+
tosa-adapter-model-explorer == 0.1.0

‎backends/arm/requirements-arm-tosa.txt‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,5 @@
77

88
ml_dtypes == 0.5.1
99
flatbuffers == 24.3.25
10-
tosa-adapter-model-explorer == 0.1.0
11-
ai-edge-model-explorer >= 0.1.16
1210
pytest-timeout == 2.4.0
1311
tosa-tools == 2026.5.0

‎examples/arm/README.md‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,45 @@ Example to install the default Arm backend dependencies and add them to your cur
4242
source examples/arm/arm-scratch/setup_path.sh
4343
```
4444

45+
The Arm toolchain dependencies have their own Python constraints. In
46+
particular, the pinned `tosa-tools==2026.5.0` has no Python 3.14 distribution;
47+
making visualization optional does not remove that separate limitation.
48+
49+
Model Explorer visualization is optional and currently supports Python
50+
3.10-3.12. Add `--enable-model-explorer` to install it and the TOSA/PTE adapters in
51+
an isolated directory, keeping their dependencies separate from the TOSA
52+
toolchain:
53+
54+
```bash
55+
./examples/arm/setup.sh \
56+
--i-agree-to-the-contained-eula \
57+
--enable-model-explorer
58+
```
59+
60+
Run visualization from an ExecuTorch environment on the same platform and
61+
Python major/minor version used for setup. The interpreter is resolved from
62+
the active environment, allowing a replacement environment or a moved
63+
scratch directory without retaining the original interpreter path.
64+
The PTE adapter currently also brings in the VGF adapter as a transitive
65+
dependency; `run.sh` exposes only TOSA/PTE visualization.
66+
67+
Select the graph format explicitly when enabling Model Explorer. For example,
68+
to visualize the generated TOSA graph:
69+
70+
```bash
71+
./examples/arm/run.sh \
72+
--model_name=examples/arm/example_modules/add.py \
73+
--target=ethos-u55-128 \
74+
--build_only \
75+
--model_explorer \
76+
--visualize_tosa
77+
```
78+
79+
Use `--visualize_pte` instead of `--visualize_tosa` to visualize the generated
80+
PTE and its delegated graphs.
81+
When `run.sh` automatically invokes setup on a fresh checkout,
82+
`--model_explorer` also enables installation of the visualization dependencies.
83+
4584
## run.sh
4685

4786
`run.sh` is an end-to-end helper for building and executing an Arm backend

‎examples/arm/run.sh‎

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ toolchain="arm-none-eabi-gcc"
4646
select_ops_list="aten::_softmax.out"
4747
select_ops_list_overridden=false
4848
model_explorer=false
49+
model_explorer_dir=""
50+
model_explorer_pythonpath=""
4951
perf_overlay=false
5052
visualize_tosa=false
5153
visualize_pte=false
@@ -146,6 +148,26 @@ if [ "$perf_overlay" = true ] && [ "$visualize_tosa" != true ]; then
146148
exit 1
147149
fi
148150

151+
if [[ "$model_explorer" != true && ("$visualize_tosa" = true || "$visualize_pte" = true) ]]; then
152+
echo "Error: --visualize_tosa and --visualize_pte require --model_explorer" >&2
153+
exit 1
154+
fi
155+
156+
if [[ "$model_explorer" = true && "$visualize_tosa" = "$visualize_pte" ]]; then
157+
echo "Error: --model_explorer requires exactly one of --visualize_tosa or --visualize_pte" >&2
158+
exit 1
159+
fi
160+
161+
if [[ "$perf_overlay" = true && "$visualize_tosa" != true ]]; then
162+
echo "Error: --perf_overlay requires --visualize_tosa" >&2
163+
exit 1
164+
fi
165+
166+
if [[ "$perf_overlay" = true && ${target} != ethos-u* ]]; then
167+
echo "Error: --perf_overlay requires an Ethos-U target" >&2
168+
exit 1
169+
fi
170+
149171
# Cortex-M backend is an operator-library, not a delegate; force-disable
150172
# --delegate when targeting cortex-m so users don't need --no_delegate.
151173
if [[ ${target} == cortex-m* ]]; then
@@ -598,8 +620,12 @@ EOF
598620
#######
599621
if ! check_setup; then
600622
if [ "$scratch_dir_set" = false ] ; then
623+
setup_cmd=("${script_dir}/setup.sh")
624+
if [[ "$model_explorer" = true ]]; then
625+
setup_cmd+=(--enable-model-explorer)
626+
fi
601627
# check setup failed, no scratchdir given as parameter. trying to run setup.sh
602-
if ${script_dir}/setup.sh; then
628+
if "${setup_cmd[@]}"; then
603629
# and recheck setup. If this fails exit.
604630
if ! check_setup; then
605631
exit 1
@@ -611,6 +637,38 @@ if ! check_setup; then
611637
fi
612638
fi
613639

640+
if [[ "$model_explorer" = true ]]; then
641+
model_explorer_dir="${arm_scratch_dir}/model-explorer"
642+
if [[ ! -f "${model_explorer_dir}/.python-version" ]]; then
643+
echo "Error: Model Explorer dependencies not found at ${model_explorer_dir}." >&2
644+
echo "Rerun setup.sh with --enable-model-explorer and a matching --root-dir." >&2
645+
exit 1
646+
fi
647+
648+
IFS= read -r model_explorer_python_version < "${model_explorer_dir}/.python-version"
649+
if [[ "$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" \
650+
!= "${model_explorer_python_version}" ]]; then
651+
echo "Error: Model Explorer was installed for Python ${model_explorer_python_version}." >&2
652+
echo "Activate a matching Python environment or rerun setup.sh with --enable-model-explorer." >&2
653+
exit 1
654+
fi
655+
656+
model_explorer_pythonpath="${model_explorer_dir}"
657+
if [[ -n "${PYTHONPATH:-}" ]]; then
658+
model_explorer_pythonpath="${model_explorer_pythonpath}:${PYTHONPATH}"
659+
fi
660+
model_explorer_adapter="tosa_adapter_model_explorer.main"
661+
if [[ "$visualize_pte" = true ]]; then
662+
model_explorer_adapter="pte_adapter_model_explorer.main"
663+
fi
664+
if ! PYTHONPATH="${model_explorer_pythonpath}" python3 -c \
665+
'import importlib, sys; importlib.import_module(sys.argv[1])' "${model_explorer_adapter}"; then
666+
echo "Error: The Model Explorer installation failed its import check." >&2
667+
echo "Rerun setup.sh with --enable-model-explorer and a matching --root-dir." >&2
668+
exit 1
669+
fi
670+
fi
671+
614672
cd "${et_root_dir}"
615673

616674
bundleio_flag=""
@@ -676,6 +734,29 @@ configure_ethosu_scratch_if_requested() {
676734
"${cmake_cmd[@]}"
677735
}
678736

737+
visualize_model() {
738+
if [[ "$model_explorer" != true ]]; then
739+
return
740+
fi
741+
742+
local model_explorer_args=(--model_dir "${output_folder}")
743+
if [[ "$visualize_tosa" = true ]]; then
744+
model_explorer_args+=(--tosa)
745+
else
746+
model_explorer_args+=(--pte)
747+
fi
748+
if [[ "$perf_overlay" = true ]]; then
749+
model_explorer_args+=(
750+
--trace "${output_folder}/pmu_trace.gz"
751+
--tables "${output_folder}/output/out_debug.xml"
752+
)
753+
fi
754+
755+
PYTHONPATH="${model_explorer_pythonpath}" \
756+
python3 "${script_dir}/visualize.py" \
757+
"${model_explorer_args[@]}"
758+
}
759+
679760
if [[ -z "$model_name" ]]; then
680761
echo "[run.sh] WARNING: Built-in test models executed when --model_name is omitted are deprecated and will be removed after the ExecuTorch 1.2 release." >&2
681762
# the test models run, and whether to delegate
@@ -766,6 +847,7 @@ for i in "${!test_model[@]}"; do
766847

767848
if [[ ${target} == *"TOSA"* ]]; then
768849
echo "Build for ${target} skip generating a .elf and running it"
850+
visualize_model
769851
continue
770852
elif [[ ${target} == cortex-m* ]]; then
771853
# Cortex-M backend uses a semihosting executor_runner (built by
@@ -828,23 +910,7 @@ for i in "${!test_model[@]}"; do
828910
fi
829911
fi
830912

831-
if [ "$model_explorer" = true ]; then
832-
perf_flags=""
833-
if [ "$perf_overlay" = true ]; then
834-
perf_flags+=" --trace ${output_folder}/pmu_trace.gz --tables ${output_folder}/output/out_debug.xml"
835-
fi
836-
837-
visualization_file=""
838-
if [ "$visualize_tosa" = true ]; then
839-
visualization_file+=" --tosa"
840-
fi
841-
if [ "$visualize_pte" = true ]; then
842-
visualization_file+=" --pte"
843-
fi
844-
845-
me_flags="${visualization_file} ${perf_flags}"
846-
python3 ${script_dir}/visualize.py --model_dir ${output_folder} ${me_flags}
847-
fi
913+
visualize_model
848914
done
849915

850916
exit 0

‎examples/arm/setup.sh‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enable_model_converter=0 # model-converter tool for VGF output
3030
enable_vgf_lib=0 # vgf reader - runtime backend dependency
3131
enable_emulation_layer=0 # Vulkan layer driver - emulates Vulkan ML extensions
3232
enable_vulkan_sdk=0 # Download and export Vulkan SDK required by emulation layer
33+
enable_model_explorer=0
3334

3435
# Figure out if setup.sh was called or sourced and save it into "is_script_sourced"
3536
(return 0 2>/dev/null) && is_script_sourced=1 || is_script_sourced=0
@@ -55,6 +56,7 @@ OPTION_LIST=(
5556
"--enable-model-converter Enable MLSDK model converter setup"
5657
"--enable-vgf-lib Enable MLSDK vgf library setup"
5758
"--enable-emulation-layer Enable MLSDK Vulkan emulation layer"
59+
"--enable-model-explorer Install optional Model Explorer visualization dependencies"
5860
"--disable-ethos-u-deps Do not setup what is needed for Ethos-U"
5961
"--enable-mlsdk-deps Setup what is needed for MLSDK"
6062
"--install-mlsdk-deps-with-pip (default) Use MLSDK PyPI packages"
@@ -144,6 +146,10 @@ function check_options() {
144146
enable_vulkan_sdk=1
145147
shift
146148
;;
149+
--enable-model-explorer)
150+
enable_model_explorer=1
151+
shift
152+
;;
147153
--disable-ethos-u-deps)
148154
enable_baremetal_toolchain=0
149155
enable_fvps=0
@@ -234,6 +240,44 @@ function setup_cortex_m_tools() {
234240
pip install --no-dependencies -r $et_dir/backends/cortex_m/requirements-cortex-m.txt
235241
}
236242

243+
function check_model_explorer_python() {
244+
local py_version
245+
py_version="$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
246+
if ! python3 -c 'import sys; raise SystemExit(0 if (3, 10) <= sys.version_info < (3, 13) else 1)'; then
247+
log_step "model-explorer" \
248+
"Model Explorer adapters require Python 3.10-3.12; detected Python ${py_version}."
249+
return 1
250+
fi
251+
}
252+
253+
function setup_model_explorer() {
254+
check_model_explorer_python || return 1
255+
256+
local model_explorer_dir="${root_dir}/model-explorer"
257+
local staging_dir
258+
staging_dir="$(mktemp -d "${root_dir}/model-explorer.XXXXXX")"
259+
260+
log_step "model-explorer" "Installing optional visualization dependencies"
261+
if ! python3 -m pip install --ignore-installed --no-warn-conflicts \
262+
--target "${staging_dir}" \
263+
-r "${et_dir}/backends/arm/requirements-arm-model-explorer.txt"; then
264+
rm -rf "${staging_dir}"
265+
return 1
266+
fi
267+
if ! PYTHONPATH="${staging_dir}" python3 -c \
268+
'import pte_adapter_model_explorer.main, tosa_adapter_model_explorer.main' || \
269+
! PYTHONPATH="${staging_dir}" python3 -m model_explorer --help >/dev/null; then
270+
log_step "model-explorer" "Installed packages failed validation"
271+
rm -rf "${staging_dir}"
272+
return 1
273+
fi
274+
275+
python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' \
276+
> "${staging_dir}/.python-version"
277+
rm -rf "${model_explorer_dir}"
278+
mv "${staging_dir}" "${model_explorer_dir}"
279+
}
280+
237281
function warn_if_mlsdk_python_is_untested() {
238282
if [[ "${enable_model_converter}" -eq 0 && \
239283
"${enable_vgf_lib}" -eq 0 && \
@@ -336,6 +380,10 @@ if [[ $is_script_sourced -eq 0 ]]; then
336380

337381
check_options "$@"
338382

383+
if [[ "${enable_model_explorer}" -eq 1 ]]; then
384+
check_model_explorer_python
385+
fi
386+
339387
if [[ "${#target_toolchains[@]}" -eq 0 ]]; then
340388
target_toolchains=("gnu")
341389
fi
@@ -418,6 +466,10 @@ if [[ $is_script_sourced -eq 0 ]]; then
418466
setup_ethos_u_tools
419467
fi
420468

469+
if [[ "${enable_model_explorer}" -eq 1 ]]; then
470+
setup_model_explorer
471+
fi
472+
421473
log_step "main" "Setup complete"
422474
exit 0
423475
fi

0 commit comments

Comments
 (0)