Skip to content

Commit 910ac24

Browse files
committed
Add some basic xnnpack recipes
Differential Revision: [D72085170](https://our.internmc.facebook.com/intern/diff/D72085170/) [ghstack-poisoned]
1 parent e42c965 commit 910ac24

File tree

8 files changed

+129
-2
lines changed

8 files changed

+129
-2
lines changed

backends/transforms/duplicate_dynamic_quant_chain.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import operator
99

1010
import torch
11+
from executorch.exir.program._program import _update_exported_program_graph_module
1112

1213
from torch.ao.quantization.pt2e.utils import (
1314
_filter_sym_size_users,
@@ -194,3 +195,10 @@ def call(self, graph_module: torch.fx.GraphModule) -> PassResult:
194195
graph_module.graph.eliminate_dead_code()
195196
graph_module.recompile()
196197
return PassResult(graph_module, True)
198+
199+
def duplicate_dynamic_quant_chain_pass(
200+
ep: torch.export.ExportedProgram,
201+
) -> torch.export.ExportedProgram:
202+
res = DuplicateDynamicQuantChainPass()(ep.graph_module)
203+
assert res is not None
204+
return _update_exported_program_graph_module(ep, res.graph_module)

backends/xnnpack/TARGETS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,6 @@ runtime.python_library(
3737
":xnnpack_preprocess",
3838
"//executorch/backends/xnnpack/partition:xnnpack_partitioner",
3939
"//executorch/backends/xnnpack/utils:xnnpack_utils",
40+
"//executorch/backends/xnnpack/recipes:xnnpack_recipes"
4041
],
4142
)

backends/xnnpack/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@
2222

2323
# XNNPACK Backend
2424
from .xnnpack_preprocess import XnnpackBackend
25-
25+
from .recipes.recipes import get_xnnpack_recipe
2626

2727
__all__ = [
2828
"XnnpackDynamicallyQuantizedPartitioner",
2929
"XnnpackPartitioner",
3030
"XnnpackBackend",
3131
"capture_graph_for_xnnpack",
32+
"get_xnnpack_recipe",
3233
"get_xnnpack_capture_config",
3334
"get_xnnpack_edge_compile_config",
3435
"get_xnnpack_executorch_backend_config",

backends/xnnpack/recipes/TARGETS

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
load("@fbcode_macros//build_defs:python_library.bzl", "python_library")
2+
3+
4+
oncall("executorch")
5+
6+
python_library(
7+
name = "xnnpack_recipes",
8+
srcs = [
9+
"recipes.py",
10+
],
11+
deps = [
12+
"//caffe2:torch",
13+
"//executorch/exir:lib",
14+
"//executorch/backends/transforms:duplicate_dynamic_quant_chain",
15+
"//executorch/backends/xnnpack/quantizer:xnnpack_quantizer",
16+
"//executorch/backends/xnnpack/partition:xnnpack_partitioner",
17+
],
18+
)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
# pyre-strict
4+
from typing import Any, Callable
5+
6+
from executorch.backends.transforms.duplicate_dynamic_quant_chain import (
7+
duplicate_dynamic_quant_chain_pass,
8+
DuplicateDynamicQuantChainPass,
9+
)
10+
11+
from executorch.backends.xnnpack.partition.xnnpack_partitioner import XnnpackPartitioner
12+
13+
from executorch.backends.xnnpack.quantizer.xnnpack_quantizer import (
14+
get_symmetric_quantization_config,
15+
XNNPACKQuantizer,
16+
)
17+
from executorch.exir import ExportRecipe
18+
19+
def get_generic_fp32_cpu_recipe() -> ExportRecipe:
20+
quantizer = XNNPACKQuantizer()
21+
operator_config = get_symmetric_quantization_config(is_per_channel=False)
22+
quantizer.set_global(operator_config)
23+
return ExportRecipe(
24+
name = "fp32_recipe",
25+
quantizer = None,
26+
partitioners=[XnnpackPartitioner()],
27+
28+
)
29+
30+
def get_dynamic_quant_recipe() -> ExportRecipe:
31+
quantizer = XNNPACKQuantizer()
32+
operator_config = get_symmetric_quantization_config(
33+
is_per_channel=True, is_dynamic=True
34+
)
35+
quantizer.set_global(operator_config)
36+
DuplicateDynamicQuantChainPass
37+
return ExportRecipe(
38+
name = "dynamic_quant_recipe",
39+
quantizer = quantizer,
40+
partitioners=[XnnpackPartitioner()],
41+
pre_edge_transform_passes=duplicate_dynamic_quant_chain_pass,
42+
)
43+
44+
RECIPE_MAP: dict[str, Callable[[], ExportRecipe]] = {
45+
"FP32_CPU_ACCELERATED_RECIPE": get_generic_fp32_cpu_recipe,
46+
"DYNAMIC_QUANT_CPU_ACCELERATED_RECIPE": get_dynamic_quant_recipe,
47+
}
48+
49+
def get_xnnpack_recipe(recipe_name:str, **kwargs: Any) -> ExportRecipe:
50+
assert recipe_name in RECIPE_MAP, f"Recipe {recipe_name} not found."
51+
return RECIPE_MAP[recipe_name](**kwargs)

backends/xnnpack/targets.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ def define_common_targets():
6464
"//executorch/backends/xnnpack/serialization:xnnpack_flatbuffer_header",
6565
"//executorch/extension/threadpool:threadpool",
6666
"//executorch/runtime/core/exec_aten/util:tensor_util",
67-
"//executorch/runtime/executor:pte_data_map"
67+
"//executorch/runtime/executor:pte_data_map",
68+
"//executorch/backends/xnnpack/recipes:xnnpack_recipes",
6869
],
6970
# XnnpackBackend.cpp needs to compile with executor as whole
7071
# @lint-ignore BUCKLINT: Avoid `link_whole=True` (https://fburl.com/avoid-link-whole)

backends/xnnpack/test/TARGETS

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,13 @@ runtime.python_test(
9393
"libtorch",
9494
],
9595
)
96+
97+
runtime.python_test(
98+
name = "test_xnnpack_recipes",
99+
srcs = glob([
100+
"recipes/*.py",
101+
]),
102+
deps = [
103+
"//executorch/backends/xnnpack:xnnpack_delegate",
104+
],
105+
)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
# pyre-strict
4+
5+
import unittest
6+
7+
import torch
8+
from executorch.backends.xnnpack import get_xnnpack_recipe
9+
from executorch.export import export
10+
from torch.testing._internal.common_quantization import TestHelperModules
11+
12+
class TestXnnpackRecipes(unittest.TestCase):
13+
def setUp(self) -> None:
14+
super().setUp()
15+
16+
def tearDown(self) -> None:
17+
super().tearDown()
18+
19+
def test_basic_recipe(self) -> None:
20+
m_eager = TestHelperModules.TwoLinearModule().eval()
21+
example_inputs = [(torch.randn(9, 8),)]
22+
export_session = export(
23+
model=m_eager,
24+
example_inputs=example_inputs,
25+
export_recipe=get_xnnpack_recipe("FP32_CPU_ACCELERATED_RECIPE")
26+
)
27+
export_session.export()
28+
29+
def test_dynamic_quant_recipe(self) -> None:
30+
m_eager = TestHelperModules.TwoLinearModule().eval()
31+
example_inputs = [(torch.randn(9, 8),)]
32+
export_session = export(
33+
model=m_eager,
34+
example_inputs=example_inputs,
35+
export_recipe=get_xnnpack_recipe("DYNAMIC_QUANT_CPU_ACCELERATED_RECIPE")
36+
)
37+
export_session.export()

0 commit comments

Comments
 (0)