Skip to content

Commit 113c70a

Browse files
committed
Update base for Update on "Arm backend: Add 16A8W support for view and transpose operations"
Add 16A8W quantization support for view and transpose operations in ExecutorTorch ARM backend. This follows the pattern established for linear, mul, sigmoid, tanh, and slice operations, extending int16 support to view and transpose operations. Changes: - Add INT16 dtype validation support in op_transpose.py - Add test_view_tensor_16a8w_tosa_INT test function - Enable test_view.py in test targets configuration The 16A8W configuration uses 16-bit activations with 8-bit weights, enabling higher precision for activations while maintaining weight efficiency. Differential Revision: [D80511313](https://our.internmc.facebook.com/intern/diff/D80511313/) cc digantdesai freddan80 per zingo oscarandersson8218 [ghstack-poisoned]
2 parents 032108d + 1d37845 commit 113c70a

File tree

158 files changed

+4202
-1624
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

158 files changed

+4202
-1624
lines changed

.ci/scripts/test_model.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function ExportModel-Xnnpack {
3434
[bool]$quantize
3535
)
3636

37-
if $(quantize) {
37+
if ($quantize) {
3838
python -m examples.xnnpack.aot_compiler --model_name="${MODEL_NAME}" --delegate --quantize | Write-Host
3939
$modelFile = "$($modelName)_xnnpack_q8.pte"
4040
} else {
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
#!/bin/bash
2+
# === CI Wheel Build & Test Script ===
3+
4+
# Exit immediately on error, print each command, and capture all output to build.log
5+
set -e
6+
set -x
7+
exec > >(tee -i build.log) 2>&1
8+
9+
# Save repo root
10+
REPO_ROOT=$(pwd)
11+
12+
# ----------------------------
13+
# Dynamically create script_qnn_wheel_test.py
14+
# ----------------------------
15+
cat > "/tmp/script_qnn_wheel_test.py" << 'EOF'
16+
# pyre-ignore-all-errors
17+
import argparse
18+
19+
import torch
20+
from executorch.backends.qualcomm.quantizer.quantizer import QnnQuantizer
21+
from executorch.backends.qualcomm.utils.utils import (
22+
generate_htp_compiler_spec,
23+
generate_qnn_executorch_compiler_spec,
24+
get_soc_to_chipset_map,
25+
to_edge_transform_and_lower_to_qnn,
26+
)
27+
from executorch.exir.backend.utils import format_delegated_graph
28+
from executorch.examples.models.model_factory import EagerModelFactory
29+
from executorch.exir.capture._config import ExecutorchBackendConfig
30+
from executorch.extension.export_util.utils import save_pte_program
31+
from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e, prepare_qat_pt2e
32+
33+
def main() -> None:
34+
parser = argparse.ArgumentParser()
35+
parser.add_argument("-f", "--output_folder", type=str, default="", help="The folder to store the exported program")
36+
parser.add_argument("--soc", type=str, default="SM8650", help="Specify the SoC model.")
37+
parser.add_argument("-q", "--quantization", choices=["ptq", "qat"], help="Run post-traininig quantization.")
38+
args = parser.parse_args()
39+
40+
class LinearModule(torch.nn.Module):
41+
def __init__(self):
42+
super().__init__()
43+
self.linear = torch.nn.Linear(3, 3)
44+
def forward(self, arg):
45+
return self.linear(arg)
46+
def get_example_inputs(self):
47+
return (torch.randn(3, 3),)
48+
49+
model = LinearModule()
50+
example_inputs = model.get_example_inputs()
51+
52+
if args.quantization:
53+
quantizer = QnnQuantizer()
54+
m = torch.export.export(model.eval(), example_inputs, strict=True).module()
55+
if args.quantization == "qat":
56+
m = prepare_qat_pt2e(m, quantizer)
57+
m(*example_inputs)
58+
elif args.quantization == "ptq":
59+
m = prepare_pt2e(m, quantizer)
60+
m(*example_inputs)
61+
m = convert_pt2e(m)
62+
else:
63+
m = model
64+
65+
use_fp16 = True if args.quantization is None else False
66+
backend_options = generate_htp_compiler_spec(use_fp16=use_fp16)
67+
compile_spec = generate_qnn_executorch_compiler_spec(
68+
soc_model=get_soc_to_chipset_map()[args.soc],
69+
backend_options=backend_options,
70+
)
71+
delegated_program = to_edge_transform_and_lower_to_qnn(m, example_inputs, compile_spec)
72+
output_graph = format_delegated_graph(delegated_program.exported_program().graph_module)
73+
# Ensure QnnBackend is in the output graph
74+
assert "QnnBackend" in output_graph
75+
executorch_program = delegated_program.to_executorch(
76+
config=ExecutorchBackendConfig(extract_delegate_segments=False)
77+
)
78+
save_pte_program(executorch_program, "linear", args.output_folder)
79+
80+
if __name__ == "__main__":
81+
main()
82+
EOF
83+
84+
# ----------------------------
85+
# Wheel build and .so checks
86+
# ----------------------------
87+
echo "=== Building Wheel Package ==="
88+
source .ci/scripts/utils.sh
89+
install_executorch
90+
EXECUTORCH_BUILDING_WHEEL=1 python setup.py bdist_wheel
91+
unset EXECUTORCH_BUILDING_WHEEL
92+
93+
WHEEL_FILE=$(ls dist/*.whl | head -n 1)
94+
echo "Found wheel: $WHEEL_FILE"
95+
96+
PYTHON_VERSION=$1
97+
# ----------------------------
98+
# Check wheel does NOT contain qualcomm/sdk
99+
# ----------------------------
100+
echo "Checking wheel does not contain qualcomm/sdk..."
101+
SDK_FILES=$(unzip -l "$WHEEL_FILE" | awk '{print $4}' | grep "executorch/backends/qualcomm/sdk" || true)
102+
if [ -n "$SDK_FILES" ]; then
103+
echo "ERROR: Wheel package contains unexpected qualcomm/sdk files:"
104+
echo "$SDK_FILES"
105+
exit 1
106+
else
107+
echo "OK: No qualcomm/sdk files found in wheel"
108+
fi
109+
110+
# ----------------------------
111+
# Check .so files in the wheel
112+
# ----------------------------
113+
echo "Checking for .so files inside the wheel..."
114+
WHEEL_SO_FILES=$(unzip -l "$WHEEL_FILE" | awk '{print $4}' | grep "executorch/backends/qualcomm/python" || true)
115+
if [ -z "$WHEEL_SO_FILES" ]; then
116+
echo "ERROR: No .so files found in wheel under executorch/backends/qualcomm/python"
117+
exit 1
118+
else
119+
echo "Wheel contains the following .so files:"
120+
echo "$WHEEL_SO_FILES"
121+
fi
122+
123+
# ----------------------------
124+
# Helpers
125+
# ----------------------------
126+
get_site_packages_dir () {
127+
local PYBIN="$1"
128+
"$PYBIN" - <<'PY'
129+
import sysconfig, sys
130+
print(sysconfig.get_paths().get("purelib") or sysconfig.get_paths().get("platlib"))
131+
PY
132+
}
133+
134+
run_core_tests () {
135+
local PYBIN="$1" # path to python
136+
local PIPBIN="$2" # path to pip
137+
local LABEL="$3" # label to print (conda/venv)
138+
139+
echo "=== [$LABEL] Installing wheel & deps ==="
140+
"$PIPBIN" install --upgrade pip
141+
"$PIPBIN" install "$WHEEL_FILE"
142+
"$PIPBIN" install torch=="2.9.0.dev20250906" --index-url "https://download.pytorch.org/whl/nightly/cpu"
143+
"$PIPBIN" install --pre torchao --index-url "https://download.pytorch.org/whl/nightly/cpu"
144+
145+
echo "=== [$LABEL] Import smoke tests ==="
146+
"$PYBIN" -c "import executorch; print('executorch imported successfully')"
147+
"$PYBIN" -c "import executorch.backends.qualcomm; print('executorch.backends.qualcomm imported successfully')"
148+
149+
echo "=== [$LABEL] List installed executorch/backends/qualcomm/python ==="
150+
local SITE_DIR
151+
SITE_DIR="$(get_site_packages_dir "$PYBIN")"
152+
local SO_DIR="$SITE_DIR/executorch/backends/qualcomm/python"
153+
ls -l "$SO_DIR" || echo "Folder does not exist!"
154+
155+
echo "=== [$LABEL] Run export script to generate linear.pte ==="
156+
(cd "$REPO_ROOT" && "$PYBIN" "/tmp/script_qnn_wheel_test.py")
157+
158+
if [ -f "$REPO_ROOT/linear.pte" ]; then
159+
echo "[$LABEL] Model file linear.pte successfully created"
160+
else
161+
echo "ERROR: [$LABEL] Model file linear.pte was not created"
162+
exit 1
163+
fi
164+
}
165+
166+
# ----------------------------
167+
# Conda environment setup & tests
168+
# ----------------------------
169+
echo "=== Testing in Conda env ==="
170+
TEMP_ENV_DIR=$(mktemp -d)
171+
echo "Using temporary directory for conda: $TEMP_ENV_DIR"
172+
conda create -y -p "$TEMP_ENV_DIR/env" python=$PYTHON_VERSION
173+
# derive python/pip paths inside the conda env
174+
CONDA_PY="$TEMP_ENV_DIR/env/bin/python"
175+
CONDA_PIP="$TEMP_ENV_DIR/env/bin/pip"
176+
# Some images require conda run; keep pip/python direct to simplify path math
177+
run_core_tests "$CONDA_PY" "$CONDA_PIP" "conda"
178+
179+
# Cleanup conda env
180+
conda env remove -p "$TEMP_ENV_DIR/env" -y || true
181+
rm -rf "$TEMP_ENV_DIR"
182+
183+
# ----------------------------
184+
# Python venv setup & tests
185+
# ----------------------------
186+
echo "=== Testing in Python venv ==="
187+
TEMP_VENV_DIR=$(mktemp -d)
188+
echo "Using temporary directory for venv: $TEMP_VENV_DIR"
189+
python3 -m venv "$TEMP_VENV_DIR/venv"
190+
VENV_PY="$TEMP_VENV_DIR/venv/bin/python"
191+
VENV_PIP="$TEMP_VENV_DIR/venv/bin/pip"
192+
193+
# Ensure venv has wheel/build basics if needed
194+
"$VENV_PIP" install --upgrade pip
195+
196+
run_core_tests "$VENV_PY" "$VENV_PIP" "venv"
197+
198+
# Cleanup venv
199+
rm -rf "$TEMP_VENV_DIR"
200+
201+
echo "=== All tests completed! ==="

.ci/scripts/wheel/pre_build_script.sh

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,26 @@ set -euxo pipefail
99

1010
# This script is run before building ExecuTorch binaries
1111

12+
# Clone nested submodules for tokenizers - this is a workaround for recursive
13+
# submodule clone failing due to path length limitations on Windows. Eventually,
14+
# we should update the core job in test-infra to enable long paths before
15+
# checkout to avoid needing to do this.
16+
pushd extension/llm/tokenizers
17+
git submodule update --init
18+
popd
19+
20+
# On Windows, enable symlinks and re-checkout the current revision to create
21+
# the symlinked src/ directory. This is needed to build the wheel.
22+
UNAME_S=$(uname -s)
23+
if [[ $UNAME_S == *"MINGW"* || $UNAME_S == *"MSYS"* ]]; then
24+
echo "Enabling symlinks on Windows"
25+
git config core.symlinks true
26+
git checkout -f HEAD
27+
fi
28+
1229
# Manually install build requirements because `python setup.py bdist_wheel` does
1330
# not install them. TODO(dbort): Switch to using `python -m build --wheel`,
1431
# which does install them. Though we'd need to disable build isolation to be
1532
# able to see the installed torch package.
1633

17-
"${GITHUB_WORKSPACE}/${REPOSITORY}/install_requirements.sh" --example
34+
"${GITHUB_WORKSPACE}/${REPOSITORY}/install_requirements.sh" --example

.ci/scripts/wheel/test_windows.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
from typing import List
9+
10+
import torch
11+
from executorch.backends.xnnpack.partition.xnnpack_partitioner import XnnpackPartitioner
12+
from executorch.examples.models import Backend, Model, MODEL_NAME_TO_MODEL
13+
from executorch.examples.models.model_factory import EagerModelFactory
14+
from executorch.examples.xnnpack import MODEL_NAME_TO_OPTIONS
15+
from executorch.examples.xnnpack.quantization.utils import quantize as quantize_xnn
16+
from executorch.exir import EdgeCompileConfig, to_edge_transform_and_lower
17+
from executorch.extension.pybindings.portable_lib import (
18+
_load_for_executorch_from_buffer,
19+
)
20+
from test_base import ModelTest
21+
22+
23+
def test_model_xnnpack(model: Model, quantize: bool) -> None:
24+
model_instance, example_inputs, _, _ = EagerModelFactory.create_model(
25+
*MODEL_NAME_TO_MODEL[str(model)]
26+
)
27+
28+
model_instance.eval()
29+
ref_outputs = model_instance(*example_inputs)
30+
31+
if quantize:
32+
quant_type = MODEL_NAME_TO_OPTIONS[str(model)].quantization
33+
model_instance = torch.export.export_for_training(
34+
model_instance, example_inputs
35+
)
36+
model_instance = quantize_xnn(
37+
model_instance.module(), example_inputs, quant_type
38+
)
39+
40+
lowered = to_edge_transform_and_lower(
41+
torch.export.export(model_instance, example_inputs),
42+
partitioner=[XnnpackPartitioner()],
43+
compile_config=EdgeCompileConfig(
44+
_check_ir_validity=False,
45+
),
46+
).to_executorch()
47+
48+
loaded_model = _load_for_executorch_from_buffer(lowered.buffer)
49+
et_outputs = loaded_model([*example_inputs])
50+
51+
if isinstance(ref_outputs, torch.Tensor):
52+
ref_outputs = (ref_outputs,)
53+
54+
assert len(ref_outputs) == len(et_outputs)
55+
for i in range(len(ref_outputs)):
56+
torch.testing.assert_close(ref_outputs[i], et_outputs[i], atol=1e-4, rtol=1e-5)
57+
58+
59+
def run_tests(model_tests: List[ModelTest]) -> None:
60+
for model_test in model_tests:
61+
if model_test.backend == Backend.Xnnpack:
62+
test_model_xnnpack(model_test.model, quantize=False)
63+
else:
64+
raise RuntimeError(f"Unsupported backend {model_test.backend}.")
65+
66+
67+
if __name__ == "__main__":
68+
run_tests(
69+
model_tests=[
70+
ModelTest(
71+
model=Model.Mv3,
72+
backend=Backend.Xnnpack,
73+
),
74+
]
75+
)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
REM This is lightly modified from the torchvision Windows build logic.
2+
REM See https://github.com/pytorch/vision/blob/main/packaging/windows/internal/vc_env_helper.bat
3+
4+
@echo on
5+
6+
set VC_VERSION_LOWER=17
7+
set VC_VERSION_UPPER=18
8+
9+
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -legacy -products * -version [%VC_VERSION_LOWER%^,%VC_VERSION_UPPER%^) -property installationPath`) do (
10+
if exist "%%i" if exist "%%i\VC\Auxiliary\Build\vcvarsall.bat" (
11+
set "VS15INSTALLDIR=%%i"
12+
set "VS15VCVARSALL=%%i\VC\Auxiliary\Build\vcvarsall.bat"
13+
goto vswhere
14+
)
15+
)
16+
17+
:vswhere
18+
if "%VSDEVCMD_ARGS%" == "" (
19+
call "%VS15VCVARSALL%" x64 || exit /b 1
20+
) else (
21+
call "%VS15VCVARSALL%" x64 %VSDEVCMD_ARGS% || exit /b 1
22+
)
23+
24+
@echo on
25+
26+
if "%CU_VERSION%" == "xpu" call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat"
27+
28+
set DISTUTILS_USE_SDK=1
29+
30+
set args=%1
31+
shift
32+
:start
33+
if [%1] == [] goto done
34+
set args=%args% %1
35+
shift
36+
goto start
37+
38+
:done
39+
if "%args%" == "" (
40+
echo Usage: vc_env_helper.bat [command] [args]
41+
echo e.g. vc_env_helper.bat cl /c test.cpp
42+
)
43+
44+
set work_dir=%CD%
45+
if exist setup.py (
46+
echo "Creating symlink..."
47+
REM Setup a symlink to shorten the path length.
48+
REM Note that the ET directory has to be named "executorch".
49+
cd %GITHUB_WORKSPACE%
50+
if not exist et\ (
51+
mkdir et
52+
)
53+
cd et
54+
echo Work dir: %work_dir%
55+
if not exist executorch\ (
56+
mklink /d executorch %work_dir%
57+
)
58+
cd executorch
59+
)
60+
61+
%args% || exit /b 1

0 commit comments

Comments
 (0)