Skip to content

Commit 85a6ac6

Browse files
committed
Update on "bump pt core pin to 0723"
Differential Revision: [D78579692](https://our.internmc.facebook.com/intern/diff/D78579692/) [ghstack-poisoned]
2 parents 0501f16 + 56dcc9f commit 85a6ac6

File tree

9 files changed

+296
-10
lines changed

9 files changed

+296
-10
lines changed

backends/test/suite/flow.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,13 @@ def all_flows() -> dict[str, TestFlow]:
6262
except Exception as e:
6363
logger.info(f"Skipping Core ML flow registration: {e}")
6464

65+
try:
66+
from executorch.backends.test.suite.flows.vulkan import VULKAN_TEST_FLOW
67+
68+
flows += [
69+
VULKAN_TEST_FLOW,
70+
]
71+
except Exception as e:
72+
logger.info(f"Skipping Vulkan flow registration: {e}")
73+
6574
return {f.name: f for f in flows if f is not None}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from executorch.backends.test.suite.flow import TestFlow
2+
from executorch.backends.vulkan.test.tester import VulkanTester
3+
4+
5+
def _create_vulkan_flow(
6+
name: str,
7+
quantize: bool = False,
8+
) -> TestFlow:
9+
return TestFlow(
10+
name,
11+
backend="vulkan",
12+
tester_factory=VulkanTester,
13+
quantize=quantize,
14+
)
15+
16+
17+
VULKAN_TEST_FLOW = _create_vulkan_flow("vulkan")

backends/vulkan/test/TARGETS

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest")
2+
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")
23

34
oncall("executorch")
45

@@ -57,3 +58,12 @@ python_unittest(
5758
"//executorch/backends/vulkan:vulkan_preprocess",
5859
],
5960
)
61+
62+
runtime.python_library(
63+
name = "tester",
64+
srcs = ["tester.py"],
65+
deps = [
66+
"//executorch/backends/vulkan/partitioner:vulkan_partitioner",
67+
"//executorch/backends/vulkan:vulkan_preprocess",
68+
]
69+
)

backends/vulkan/test/tester.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
from typing import Any, List, Optional, Tuple
8+
9+
import executorch
10+
import executorch.backends.test.harness.stages as BaseStages
11+
12+
import torch
13+
from executorch.backends.test.harness import Tester as TesterBase
14+
from executorch.backends.test.harness.stages import StageType
15+
from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner
16+
from executorch.exir import EdgeCompileConfig
17+
from executorch.exir.backend.partitioner import Partitioner
18+
19+
20+
class Partition(BaseStages.Partition):
21+
def __init__(self, partitioner: Optional[Partitioner] = None):
22+
super().__init__(
23+
partitioner=partitioner or VulkanPartitioner(),
24+
)
25+
26+
27+
class ToEdgeTransformAndLower(BaseStages.ToEdgeTransformAndLower):
28+
def __init__(
29+
self,
30+
partitioners: Optional[List[Partitioner]] = None,
31+
edge_compile_config: Optional[EdgeCompileConfig] = None,
32+
):
33+
super().__init__(
34+
default_partitioner_cls=VulkanPartitioner,
35+
partitioners=partitioners,
36+
edge_compile_config=edge_compile_config
37+
or EdgeCompileConfig(_check_ir_validity=False),
38+
)
39+
40+
41+
class VulkanTester(TesterBase):
42+
def __init__(
43+
self,
44+
module: torch.nn.Module,
45+
example_inputs: Tuple[torch.Tensor],
46+
dynamic_shapes: Optional[Tuple[Any]] = None,
47+
):
48+
stage_classes = (
49+
executorch.backends.test.harness.Tester.default_stage_classes()
50+
| {
51+
StageType.PARTITION: Partition,
52+
StageType.TO_EDGE_TRANSFORM_AND_LOWER: ToEdgeTransformAndLower,
53+
}
54+
)
55+
56+
super().__init__(
57+
module=module,
58+
stage_classes=stage_classes,
59+
example_inputs=example_inputs,
60+
dynamic_shapes=dynamic_shapes,
61+
)

docs/source/backends-arm-ethos-u.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,12 @@ from executorch.exir import (
3535
)
3636
from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e
3737
from torchvision.models import mobilenetv2
38+
import executorch.kernels.quantized
3839

3940
mobilenet_v2 = mobilenetv2.mobilenet_v2(
4041
weights=mobilenetv2.MobileNet_V2_Weights.DEFAULT
4142
).eval()
4243
example_inputs = (torch.randn(1, 3, 224, 224),)
43-
# .so suffix is .dylib on MacOS.
44-
torch.ops.load_library(
45-
"cmake-out-aot-lib/kernels/quantized/libquantized_ops_aot_lib.so"
46-
)
4744

4845
compile_spec = ArmCompileSpecBuilder().ethosu_compile_spec(
4946
"ethos-u55-128",

exir/passes/quantize_io_pass.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
# Copyright (c) Meta Platforms, Inc. and affiliates.
22
# All rights reserved.
3+
# Copyright 2025 Arm Limited and/or its affiliates.
34
#
45
# This source code is licensed under the BSD-style license found in the
56
# LICENSE file in the root directory of this source tree
67

8+
#
9+
# This source code is licensed under the BSD-style license found in the
10+
# LICENSE file in the root directory of this source tree.
11+
712
import logging
8-
from typing import Any, Dict, List, Optional, Union
13+
from typing import Any, Dict, List, Optional, Sequence, Union
914

1015
import numpy as np
1116

1217
import torch
18+
import torch.fx as fx
1319

1420
from executorch.exir import EdgeProgramManager, ExportedProgram
1521
from executorch.exir.dialects._ops import ops as exir_ops
@@ -316,3 +322,93 @@ def call(self, graph_module: torch.fx.GraphModule):
316322
self.edge_manager_update_quant_config_method(i, self.dequant_args[i])
317323

318324
return PassResult(graph_module, True)
325+
326+
327+
def extract_io_quant_params(
328+
edge_prog: EdgeProgramManager,
329+
*,
330+
input_idxs: Sequence[int] = (0,),
331+
output_idxs: Sequence[int] = (0,),
332+
) -> Dict[str, Dict[str, Dict[str, Any]]]:
333+
"""
334+
Returns quantization parameters such as scale/zero_point:
335+
{
336+
"inputs": {
337+
<placeholder_name>: {"scale": float, "zero_point": int}
338+
},
339+
"outputs": {
340+
<node_name>: {"scale": float, "zero_point": int}
341+
}
342+
}
343+
344+
Note that this function will strip out the IO quantize/dequantize ops as
345+
it records their parameters, so if you need to preserve the original graph
346+
you need to make a copy with copy.deepcopy before.
347+
348+
Note that `to_edge_transform_and_lower` should be called before.
349+
"""
350+
# Use IO passes
351+
passes = []
352+
for idx in input_idxs:
353+
passes.append(QuantizeInputs(edge_prog, [idx]))
354+
for idx in output_idxs:
355+
passes.append(QuantizeOutputs(edge_prog, [idx]))
356+
357+
# Apply them
358+
edge_prog = edge_prog.transform(passes)
359+
360+
cfg = getattr(edge_prog, "_config_methods", {}) or {}
361+
362+
# We need GraphModule to find node names
363+
gm = edge_prog.exported_program().graph_module
364+
365+
input_names = _gather_io_names(gm, side="input")
366+
output_names = _gather_io_names(gm, side="output")
367+
368+
# Build the result dict
369+
result = {"inputs": {}, "outputs": {}}
370+
for key, val in cfg.items():
371+
if key.startswith("input"):
372+
prefix, section, names = "input", "inputs", input_names
373+
elif key.startswith("output"):
374+
prefix, section, names = "output", "outputs", output_names
375+
else:
376+
continue
377+
378+
idx_str, param = key[len(prefix) :].split("_", 1)
379+
idx = int(idx_str)
380+
name = names[idx]
381+
# We need to map 'zp' to 'zero_point'
382+
out_param = "zero_point" if param in ("zp", "zero_point") else param
383+
result[section].setdefault(name, {})[out_param] = val
384+
385+
return result
386+
387+
388+
def _gather_io_names(gm: fx.GraphModule, side: str):
389+
"""
390+
For 'input', returns placeholder names in graph order.
391+
For 'output', returns names of output nodes.
392+
"""
393+
if side == "input":
394+
return [n.name for n in gm.graph.nodes if n.op == "placeholder"]
395+
396+
if side == "output":
397+
398+
def _flatten(args):
399+
out = []
400+
401+
def rec(x):
402+
if isinstance(x, (tuple, list)):
403+
for y in x:
404+
rec(y)
405+
elif isinstance(x, fx.Node):
406+
out.append(x)
407+
408+
rec(args)
409+
return out
410+
411+
output_node = next(n for n in gm.graph.nodes if n.op == "output")
412+
return [n.name for n in _flatten(output_node.args)]
413+
414+
raise ValueError(f"Unknown side: {side}")
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright 2025 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+
import copy
7+
import unittest
8+
9+
import torch
10+
from executorch.backends.xnnpack.quantizer.xnnpack_quantizer import (
11+
get_symmetric_quantization_config,
12+
XNNPACKQuantizer,
13+
)
14+
from executorch.exir import to_edge_transform_and_lower
15+
from executorch.exir.passes.quantize_io_pass import extract_io_quant_params
16+
17+
from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e
18+
19+
20+
class SimpleAdd(torch.nn.Module):
21+
def forward(self, x, y):
22+
return x + y
23+
24+
25+
class TestExtractIOQuantParamsPT2E(unittest.TestCase):
26+
def setUp(self):
27+
self.example_inputs = (
28+
torch.ones(1, 5),
29+
torch.full(
30+
(
31+
1,
32+
5,
33+
),
34+
2.0,
35+
),
36+
)
37+
self.mod = SimpleAdd().eval()
38+
39+
# Setup XNNPACK quantizer for example
40+
self.quantizer = XNNPACKQuantizer()
41+
operator_config = get_symmetric_quantization_config()
42+
self.quantizer.set_global(operator_config)
43+
44+
exported = torch.export.export_for_training(
45+
self.mod,
46+
copy.deepcopy(self.example_inputs),
47+
strict=True,
48+
)
49+
prepared = prepare_pt2e(exported.module(), self.quantizer)
50+
51+
# Call observers to calibrate
52+
_ = prepared(*self.example_inputs)
53+
54+
converted = convert_pt2e(prepared)
55+
56+
# Export again with quant parameters
57+
final_export = torch.export.export_for_training(
58+
converted,
59+
self.example_inputs,
60+
strict=True,
61+
)
62+
63+
# Lower to EdgeProgramManager
64+
self.edge_prog = to_edge_transform_and_lower(final_export)
65+
66+
def test_roundtrip_extracts_io_params(self):
67+
# Get dict with quant parameters
68+
q = extract_io_quant_params(
69+
self.edge_prog,
70+
input_idxs=(0, 1),
71+
output_idxs=(0,),
72+
)
73+
74+
# Validate structure
75+
self.assertIn("inputs", q)
76+
self.assertIn("outputs", q)
77+
self.assertEqual(len(q["inputs"]), 2)
78+
self.assertEqual(len(q["outputs"]), 1)
79+
80+
# Each entry must have a float 'scale' and int 'zero_point'
81+
for name, params in q["inputs"].items():
82+
self.assertIsInstance(name, str)
83+
self.assertIsInstance(params["scale"], float)
84+
self.assertIsInstance(params["zero_point"], int)
85+
86+
out_name, out_params = next(iter(q["outputs"].items()))
87+
self.assertIsInstance(out_name, str)
88+
self.assertIsInstance(out_params["scale"], float)
89+
self.assertIsInstance(out_params["zero_point"], int)
90+
91+
92+
if __name__ == "__main__":
93+
unittest.main()

extension/data_loader/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ if(NOT EXECUTORCH_ROOT)
1616
set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../..)
1717
endif()
1818

19+
include(CheckIncludeFile)
20+
check_include_file(sys/mman.h ET_HAVE_SYS_MMAN_H)
21+
22+
if(NOT ET_HAVE_SYS_MMAN_H AND NOT WIN32)
23+
list(REMOVE_ITEM _extension_data_loader__srcs
24+
"extension/data_loader/mmap_data_loader.cpp"
25+
)
26+
endif()
1927
list(TRANSFORM _extension_data_loader__srcs PREPEND "${EXECUTORCH_ROOT}/")
2028
add_library(extension_data_loader ${_extension_data_loader__srcs})
2129
target_link_libraries(extension_data_loader executorch_core)

extension/llm/runner/text_decoder_runner.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,6 @@ ::executorch::runtime::Result<executorch::aten::Tensor> TextDecoderRunner::step(
6666
start_pos_tensor = from_blob(
6767
&start_pos, sizes_vec, ::executorch::aten::ScalarType::Long);
6868
}
69-
ET_LOG(
70-
Info,
71-
"Start pos tensor numel: %zu, tokens numel: %zu",
72-
start_pos_tensor->numel(),
73-
tokens->numel());
7469
auto outputs_res = module_->forward({tokens, start_pos_tensor});
7570
ET_CHECK_OK_OR_RETURN_ERROR(outputs_res.error());
7671
ET_CHECK_MSG(

0 commit comments

Comments
 (0)