Skip to content

Commit a548635

Browse files
Add android target recipes and extensive model tests using ios and android recipes (#14290)
1 parent 6fed762 commit a548635

File tree

7 files changed

+607
-102
lines changed

7 files changed

+607
-102
lines changed

.ci/scripts/test_wheel_package_qnn.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ run_core_tests () {
145145
echo "=== [$LABEL] Import smoke tests ==="
146146
"$PYBIN" -c "import executorch; print('executorch imported successfully')"
147147
"$PYBIN" -c "import executorch.backends.qualcomm; print('executorch.backends.qualcomm imported successfully')"
148+
"$PYBIN" -c "from executorch.export.target_recipes import get_android_recipe; recipe = get_android_recipe('android-arm64-snapdragon-fp16'); print(f'executorch.export.target_recipes imported successfully: {recipe}')"
148149

149150
echo "=== [$LABEL] List installed executorch/backends/qualcomm/python ==="
150151
local SITE_DIR

backends/qualcomm/_passes/TARGETS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ runtime.python_library(
1515
"//executorch/backends/transforms:decompose_sdpa",
1616
"//executorch/exir/backend:backend_details",
1717
"//executorch/exir/backend:compile_spec_schema",
18+
"//executorch/backends/qualcomm/quantizer:quantizer",
1819
],
1920
)

export/TARGETS

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,19 @@ runtime.python_library(
117117
"target_recipes.py",
118118
],
119119
deps = [
120+
":export_utils",
120121
"fbsource//third-party/pypi/coremltools:coremltools",
121122
"//executorch/export:recipe",
122123
"//executorch/backends/xnnpack/recipes:xnnpack_recipes",
123124
"//executorch/backends/apple/coreml:coreml_recipes",
125+
"//executorch/backends/qualcomm/recipes:qnn_recipes",
126+
]
127+
)
128+
129+
runtime.python_library(
130+
name = "export_utils",
131+
srcs = ["utils.py"],
132+
deps = [
133+
"//caffe2:torch",
124134
]
125135
)

export/target_recipes.py

Lines changed: 94 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,14 @@
1111
selection and combine multiple backends optimally for target hardware.
1212
"""
1313

14-
import sys
14+
import os
1515
from typing import Dict, List
1616

17-
if sys.platform != "win32":
18-
import coremltools as ct
19-
from executorch.backends.apple.coreml.recipes import CoreMLRecipeType
20-
21-
# pyre-ignore
2217
from executorch.backends.xnnpack.recipes import XNNPackRecipeType
2318
from executorch.export.recipe import ExportRecipe, RecipeType
24-
25-
26-
## IOS Target configs
27-
# The following list of recipes are not exhaustive for CoreML; refer to CoreMLRecipeType for more detailed recipes.
28-
IOS_CONFIGS: Dict[str, List[RecipeType]] = (
29-
{
30-
# pyre-ignore
31-
"ios-arm64-coreml-fp32": [CoreMLRecipeType.FP32, XNNPackRecipeType.FP32],
32-
# pyre-ignore
33-
"ios-arm64-coreml-fp16": [CoreMLRecipeType.FP16],
34-
# pyre-ignore
35-
"ios-arm64-coreml-int8": [CoreMLRecipeType.PT2E_INT8_STATIC],
36-
}
37-
if sys.platform != "win32"
38-
else {}
19+
from executorch.export.utils import (
20+
is_supported_platform_for_coreml_lowering,
21+
is_supported_platform_for_qnn_lowering,
3922
)
4023

4124

@@ -46,7 +29,7 @@ def _create_target_recipe(
4629
Create a combined recipe for a target.
4730
4831
Args:
49-
target: Human-readable hardware configuration name
32+
target_config: Human-readable hardware configuration name
5033
recipes: List of backend recipe types to combine
5134
**kwargs: Additional parameters - each backend will use what it needs
5235
@@ -67,7 +50,6 @@ def _create_target_recipe(
6750
f"Failed to create {recipe_type.value} recipe for {target_config}: {e}"
6851
) from e
6952

70-
# Combine into single recipe
7153
if len(backend_recipes) == 1:
7254
return backend_recipes[0]
7355

@@ -100,8 +82,24 @@ def get_ios_recipe(
10082
recipe = get_ios_recipe('ios-arm64-coreml-int8')
10183
session = export(model, recipe, example_inputs)
10284
"""
103-
if target_config not in IOS_CONFIGS:
104-
supported = list(IOS_CONFIGS.keys())
85+
86+
if not is_supported_platform_for_coreml_lowering():
87+
raise ValueError("CoreML is not supported on this platform")
88+
89+
import coremltools as ct
90+
from executorch.backends.apple.coreml.recipes import CoreMLRecipeType
91+
92+
ios_configs: Dict[str, List[RecipeType]] = {
93+
# pyre-ignore
94+
"ios-arm64-coreml-fp32": [CoreMLRecipeType.FP32, XNNPackRecipeType.FP32],
95+
# pyre-ignore
96+
"ios-arm64-coreml-fp16": [CoreMLRecipeType.FP16],
97+
# pyre-ignore
98+
"ios-arm64-coreml-int8": [CoreMLRecipeType.PT2E_INT8_STATIC],
99+
}
100+
101+
if target_config not in ios_configs:
102+
supported = list(ios_configs.keys())
105103
raise ValueError(
106104
f"Unsupported iOS configuration: '{target_config}'. "
107105
f"Supported: {supported}"
@@ -113,5 +111,75 @@ def get_ios_recipe(
113111
if "minimum_deployment_target" not in kwargs:
114112
kwargs["minimum_deployment_target"] = ct.target.iOS17
115113

116-
backend_recipes = IOS_CONFIGS[target_config]
114+
backend_recipes = ios_configs[target_config]
115+
return _create_target_recipe(target_config, backend_recipes, **kwargs)
116+
117+
118+
# Android Recipe
119+
def get_android_recipe(
120+
target_config: str = "android-arm64-snapdragon-fp16", **kwargs
121+
) -> ExportRecipe:
122+
"""
123+
Get Android-optimized recipe for specified hardware configuration.
124+
125+
Supported configurations:
126+
- 'android-arm64-snapdragon-fp16': QNN fp16 recipe
127+
128+
Args:
129+
target_config: Android configuration string
130+
**kwargs: Additional parameters for backend recipes
131+
132+
Returns:
133+
ExportRecipe configured for Android deployment
134+
135+
Raises:
136+
ValueError: If target configuration is not supported
137+
138+
Example:
139+
recipe = get_android_recipe('android-arm64-snapdragon-fp16')
140+
session = export(model, recipe, example_inputs)
141+
"""
142+
143+
if not is_supported_platform_for_qnn_lowering():
144+
raise ValueError(
145+
"QNN is not supported or not properly configured on this platform"
146+
)
147+
148+
try:
149+
# Qualcomm QNN backend runs QNN sdk download on first use
150+
# with a pip install, so wrap it in a try/except
151+
# pyre-ignore
152+
from executorch.backends.qualcomm.recipes import QNNRecipeType
153+
154+
# (1) if this is called from a pip install, the QNN SDK will be available
155+
# (2) if this is called from a source build, check if qnn is available otherwise, had to run build.sh
156+
if os.getenv("QNN_SDK_ROOT", None) is None:
157+
raise ValueError(
158+
"QNN SDK not found, cannot use QNN recipes. First run `./backends/qualcomm/scripts/build.sh`, if building from source"
159+
)
160+
except Exception as e:
161+
raise ValueError(
162+
"QNN backend is not available. Please ensure the Qualcomm backend "
163+
"is properly installed and configured, "
164+
) from e
165+
166+
android_configs: Dict[str, List[RecipeType]] = {
167+
# pyre-ignore
168+
"android-arm64-snapdragon-fp16": [QNNRecipeType.FP16],
169+
}
170+
171+
if target_config not in android_configs:
172+
supported = list(android_configs.keys())
173+
raise ValueError(
174+
f"Unsupported Android configuration: '{target_config}'. "
175+
f"Supported: {supported}"
176+
)
177+
178+
kwargs = kwargs or {}
179+
180+
if target_config == "android-arm64-snapdragon-fp16":
181+
if "soc_model" not in kwargs:
182+
kwargs["soc_model"] = "SM8650"
183+
184+
backend_recipes = android_configs[target_config]
117185
return _create_target_recipe(target_config, backend_recipes, **kwargs)

export/tests/TARGETS

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")
2+
load("@fbsource//xplat/executorch/backends/qualcomm/qnn_version.bzl", "get_qnn_library_version")
23

34
oncall("executorch")
45

@@ -37,11 +38,23 @@ runtime.python_test(
3738
srcs = [
3839
"test_target_recipes.py",
3940
],
41+
env = {
42+
"LD_LIBRARY_PATH": "$(location fbsource//third-party/qualcomm/qnn/qnn-{0}:qnn_offline_compile_libs)".format(get_qnn_library_version()),
43+
"QNN_SDK_ROOT": "$(location fbsource//third-party/qualcomm/qnn/qnn-{0}:__dir__)".format(get_qnn_library_version()),
44+
"HTTP_PROXY": "http://fwdproxy:8080",
45+
"HTTPS_PROXY": "http://fwdproxy:8080",
46+
},
47+
labels = ["long_running"],
4048
deps = [
4149
"//executorch/export:lib",
4250
"//executorch/export:target_recipes",
51+
"//executorch/export:export_utils",
4352
"//executorch/runtime:runtime",
4453
"//executorch/backends/xnnpack/recipes:xnnpack_recipes",
4554
"//executorch/backends/apple/coreml:coreml_recipes",
55+
"//executorch/backends/qualcomm/recipes:qnn_recipes",
56+
"//executorch/examples/models:models",
57+
"//executorch/backends/xnnpack/test/tester:tester",
58+
"fbsource//third-party/pypi/coremltools:coremltools"
4659
]
4760
)

0 commit comments

Comments
 (0)