From 2acf1c0f757dc6b904ca0c7736799dfea1c6408e Mon Sep 17 00:00:00 2001 From: Jiseong Oh Date: Wed, 4 Mar 2026 16:20:31 +0800 Subject: [PATCH 1/5] Register samsung backend in test suite -Add samsung backend in TestSuite of ExecuTorch Signed-off-by: Jiseong Oh Co-authored-by: Guochao Yang --- .../samsung/test/tester/samsung_tester.py | 12 +++++- backends/test/suite/flow.py | 13 ++++++ backends/test/suite/flows/samsung.py | 41 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 backends/test/suite/flows/samsung.py diff --git a/backends/samsung/test/tester/samsung_tester.py b/backends/samsung/test/tester/samsung_tester.py index 258aef191d0..001b7e3bb0d 100644 --- a/backends/samsung/test/tester/samsung_tester.py +++ b/backends/samsung/test/tester/samsung_tester.py @@ -11,8 +11,12 @@ import torch from executorch.backends.samsung.partition.enn_partitioner import EnnPartitioner from executorch.backends.samsung.quantizer.quantizer import EnnQuantizer, Precision +from executorch.backends.samsung.serialization.compile_options import ( + gen_samsung_backend_compile_spec, +) from executorch.backends.samsung.test.utils import RuntimeExecutor from executorch.backends.samsung.test.utils.quant_checkers import get_checker +from executorch.backends.samsung.test.utils.utils import TestConfig from executorch.backends.samsung.utils.export_utils import get_edge_compile_config from executorch.backends.test.harness import Tester as TesterBase from executorch.backends.test.harness.stages import StageType @@ -112,6 +116,7 @@ def run( transform_passes=self.transform_passes, partitioner=self.partitioners, compile_config=self.edge_compile_config, + generate_etrecord=generate_etrecord, ) @@ -145,6 +150,8 @@ def __init__( self.original_module = module self.exported_module = module self.example_inputs = example_inputs + if compile_specs is None: + compile_specs = [gen_samsung_backend_compile_spec(TestConfig.chipset)] self.compile_specs = compile_specs def quantize( @@ -167,9 +174,12 @@ def quantize( def to_edge_transform_and_lower( self, edge_compile_config: Optional[EdgeCompileConfig] = None, + generate_etrecord: bool = False, ): to_edge_transform_and_lower_stage = ToEdgeTransformAndLower( self.compile_specs, edge_compile_config ) - return super().to_edge_transform_and_lower(to_edge_transform_and_lower_stage) + return super().to_edge_transform_and_lower( + to_edge_transform_and_lower_stage, generate_etrecord + ) diff --git a/backends/test/suite/flow.py b/backends/test/suite/flow.py index 547c79326e6..7331adc4a49 100644 --- a/backends/test/suite/flow.py +++ b/backends/test/suite/flow.py @@ -227,4 +227,17 @@ def all_flows() -> dict[str, TestFlow]: except Exception as e: logger.info(f"Skipping MLX flow registration: {e}") + try: + from executorch.backends.test.suite.flows.samsung import ( + SAMSUNG_A8W8_TEST_FLOW, + SAMSUNG_TEST_FLOW, + ) + + flows += [ + SAMSUNG_TEST_FLOW, + SAMSUNG_A8W8_TEST_FLOW, + ] + except Exception as e: + logger.info(f"Skipping SAMSUNG flow registration: {e}") + return {f.name: f for f in flows if f is not None} diff --git a/backends/test/suite/flows/samsung.py b/backends/test/suite/flows/samsung.py new file mode 100644 index 00000000000..b43a1f770c2 --- /dev/null +++ b/backends/test/suite/flows/samsung.py @@ -0,0 +1,41 @@ +import logging + +from executorch.backends.samsung.quantizer.quantizer import EnnQuantizer, Precision +from executorch.backends.samsung.test.tester.samsung_tester import SamsungTester +from executorch.backends.test.harness.stages import Quantize +from executorch.backends.test.suite.flow import TestFlow + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + + +def _create_samsung_flow( + name: str, + quantize: bool = False, + quant_dtype: Precision | None = None, + is_per_channel: bool = True, + is_qat: bool = False, +) -> TestFlow: + if quantize and quant_dtype is None: + raise RuntimeError("Quant dtype must be provided when quantize is true.") + + def create_quantize_stage() -> Quantize: + quantizer = EnnQuantizer() + quantizer.setup_quant_params(quant_dtype, is_per_channel, is_qat) + return Quantize(quantizer=quantizer) + + return TestFlow( + name, + backend="samsung", + tester_factory=SamsungTester, + quantize=quantize, + quantize_stage_factory=create_quantize_stage if quantize else None, + supports_serialize=False, + ) + + +SAMSUNG_TEST_FLOW = _create_samsung_flow("samsung") + +SAMSUNG_A8W8_TEST_FLOW = _create_samsung_flow( + "samsung_a8w8", quantize=True, quant_dtype=Precision.A8W8 +) From 446b78457a5805f4de11423e232dd4a82e1ec38d Mon Sep 17 00:00:00 2001 From: Jiseong Oh Date: Tue, 24 Mar 2026 17:04:13 +0800 Subject: [PATCH 2/5] Fix issues for models in test suite 1. Support ceil_mode for pool op 2. Handle the output connect to "getitem" 3. Remove first inference because test suite reuses inputs buffer. After first inference executed, the inputs buffer will be changed if there are aten ops. 4. Add exp builder Signed-off-by: Jiseong Oh Co-authored-by: Jingya Zhang --- .../samsung/_passes/remove_useless_ops.py | 1 - backends/samsung/builders/__init__.py | 4 +++ backends/samsung/builders/op_avg_pool2d.py | 4 --- backends/samsung/builders/op_batch_norm.py | 4 +++ backends/samsung/builders/op_conv2d.py | 2 +- backends/samsung/builders/op_exp.py | 31 ++++++++++++++++++ backends/samsung/builders/op_max_pool2d.py | 4 --- backends/samsung/builders/op_reshape.py | 8 +++-- backends/samsung/builders/op_skip.py | 32 +++++++++++++++++++ .../builders/op_split_with_sizes_copy.py | 4 +++ backends/test/suite/models/test_torchaudio.py | 2 +- .../executor_runner/enn_executor_runner.cpp | 20 ++---------- 12 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 backends/samsung/builders/op_exp.py create mode 100644 backends/samsung/builders/op_skip.py diff --git a/backends/samsung/_passes/remove_useless_ops.py b/backends/samsung/_passes/remove_useless_ops.py index c88a2d4a5d8..9c965844749 100644 --- a/backends/samsung/_passes/remove_useless_ops.py +++ b/backends/samsung/_passes/remove_useless_ops.py @@ -15,7 +15,6 @@ class RemoveUselessOpPass(ExportPass): USELESS_OP_SET = { exir_ops.edge.aten._to_copy.default, exir_ops.edge.aten.clone.default, - exir_ops.edge.aten.clone.default, exir_ops.edge.aten.alias.default, exir_ops.edge.aten.lift_fresh_copy.default, exir_ops.edge.dim_order_ops._to_dim_order_copy.default, diff --git a/backends/samsung/builders/__init__.py b/backends/samsung/builders/__init__.py index 14b9a17a6c9..60f97cf60f7 100644 --- a/backends/samsung/builders/__init__.py +++ b/backends/samsung/builders/__init__.py @@ -18,6 +18,7 @@ op_dequantize, op_div, op_embedding, + op_exp, op_expand_copy, op_gelu, op_getitem, @@ -48,6 +49,7 @@ op_select, op_sigmoid, op_sin, + op_skip, op_slice_copy, op_softmax, op_split_with_sizes_copy, @@ -77,6 +79,7 @@ op_dequantize, op_div, op_embedding, + op_exp, op_expand_copy, op_gelu, op_getitem, @@ -107,6 +110,7 @@ op_select, op_sigmoid, op_sin, + op_skip, op_slice_copy, op_softmax, op_split_with_sizes_copy, diff --git a/backends/samsung/builders/op_avg_pool2d.py b/backends/samsung/builders/op_avg_pool2d.py index bfca8b89b22..b2e6e160830 100644 --- a/backends/samsung/builders/op_avg_pool2d.py +++ b/backends/samsung/builders/op_avg_pool2d.py @@ -52,10 +52,6 @@ def define_node( params["explicit_padding"] = explicit_padding self._update_params_qdtype(node, params) - if len(node.args) > 4: - ceil_mode = cast(bool, node.args[4]) - assert not ceil_mode, "Not support ceil_mode = True." - if len(node.args) > 5: params["count_include_pad"] = cast(bool, node.args[5]) else: diff --git a/backends/samsung/builders/op_batch_norm.py b/backends/samsung/builders/op_batch_norm.py index e5373a8223a..d8c893e128e 100644 --- a/backends/samsung/builders/op_batch_norm.py +++ b/backends/samsung/builders/op_batch_norm.py @@ -51,6 +51,10 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids, output_idx=0) + users = list(node.users.keys()) + if len(users) > 0 and users[0].target.__name__ == "getitem": + vals_to_ids[users[0]] = output_id + enn_graph.define_op( node.name, "BatchNormalization", all_input_tensors, [output_id], params ) diff --git a/backends/samsung/builders/op_conv2d.py b/backends/samsung/builders/op_conv2d.py index ab77d8df626..2ff80b1b011 100644 --- a/backends/samsung/builders/op_conv2d.py +++ b/backends/samsung/builders/op_conv2d.py @@ -72,7 +72,7 @@ def define_node( params["explicit_padding"] = explicit_padding params["in_channels"] = input_shape[1] params["out_channels"] = kernel_shape[0] * kernel_shape[1] * groups - params["out_channels"] //= input_shape[1] * input_shape[0] + params["out_channels"] //= input_shape[1] output_id = self.define_tensor(node, enn_graph, vals_to_ids) diff --git a/backends/samsung/builders/op_exp.py b/backends/samsung/builders/op_exp.py new file mode 100644 index 00000000000..a93f4b9be02 --- /dev/null +++ b/backends/samsung/builders/op_exp.py @@ -0,0 +1,31 @@ +# Copyright (c) 2026 Samsung Electronics Co. LTD +# All rights reserved +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict + +import torch +from executorch.backends.samsung.builders.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.samsung.serialization.enn_graph_schema import EnnGraph + + +@register_node_visitor +class ExpVisitor(NodeVisitor): + target = "aten.exp.default" + + def define_node( + self, + node: torch.fx.Node, + enn_graph: EnnGraph, + vals_to_ids: Dict[torch.Tensor, int], + ) -> None: + input_id = self.define_tensor(node.args[0], enn_graph, vals_to_ids) + + output_id = self.define_tensor(node, enn_graph, vals_to_ids) + + enn_graph.define_op(node.name, "Exp", [input_id], [output_id]) diff --git a/backends/samsung/builders/op_max_pool2d.py b/backends/samsung/builders/op_max_pool2d.py index 57b716fcb34..805f68fd929 100644 --- a/backends/samsung/builders/op_max_pool2d.py +++ b/backends/samsung/builders/op_max_pool2d.py @@ -75,10 +75,6 @@ def define_node( params["dilation_w"] = dilation[1] self._update_params_qdtype(node, params) - if len(node.args) > 5: - ceil_mode = cast(bool, node.args[5]) - assert not ceil_mode, "Not support ceil_mode = True." - if not is_indices: output_id = self.define_tensor( node, diff --git a/backends/samsung/builders/op_reshape.py b/backends/samsung/builders/op_reshape.py index 1f4e85ac059..4ec45383cb1 100644 --- a/backends/samsung/builders/op_reshape.py +++ b/backends/samsung/builders/op_reshape.py @@ -7,6 +7,7 @@ NodeVisitor, register_node_visitor, ) +from executorch.backends.samsung.builders.utils import get_tensor from executorch.backends.samsung.serialization.enn_graph_schema import EnnGraph @@ -28,7 +29,10 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) - new_shape = node.args[1] + # node.args[1] may contain "sym_size" + tensor = get_tensor(self.exported_program, node) + shape = [1] if len(tensor.size()) == 0 else list(tensor.size()) + enn_graph.define_op( - node.name, "RESHAPE", [input_id], [output_id], {"new_shape": new_shape} + node.name, "RESHAPE", [input_id], [output_id], {"new_shape": shape} ) diff --git a/backends/samsung/builders/op_skip.py b/backends/samsung/builders/op_skip.py new file mode 100644 index 00000000000..16da4bdd289 --- /dev/null +++ b/backends/samsung/builders/op_skip.py @@ -0,0 +1,32 @@ +# Copyright (c) 2026 Samsung Electronics Co. LTD +# All rights reserved +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from typing import Dict + +import torch +from executorch.backends.samsung.builders.node_visitor import ( + NodeVisitor, + register_node_visitor, +) +from executorch.backends.samsung.serialization.enn_graph_schema import EnnGraph + + +@register_node_visitor +class OpSkipVisitor(NodeVisitor): + target = ["sym_size.int", "add", "floordiv"] + """ + do nothing + """ + + def __init__(self, *args) -> None: + super().__init__(*args) + + def define_node( + self, + node: torch.fx.Node, + enn_graph: EnnGraph, + vals_to_ids: Dict[torch.Tensor, int], + ) -> None: + return diff --git a/backends/samsung/builders/op_split_with_sizes_copy.py b/backends/samsung/builders/op_split_with_sizes_copy.py index b67b5331627..e6caaf0ba7a 100644 --- a/backends/samsung/builders/op_split_with_sizes_copy.py +++ b/backends/samsung/builders/op_split_with_sizes_copy.py @@ -39,6 +39,10 @@ def define_node( ) all_output_tensors.append(output_id) + for user in node.users.keys(): + if user.target.__name__ == "getitem" and len(user.args) > 1: + vals_to_ids[user] = all_output_tensors[user.args[1]] + axis = node.args[2] if len(node.args) > 2 else 0 params = {} diff --git a/backends/test/suite/models/test_torchaudio.py b/backends/test/suite/models/test_torchaudio.py index 2287b226c37..b6879162297 100644 --- a/backends/test/suite/models/test_torchaudio.py +++ b/backends/test/suite/models/test_torchaudio.py @@ -62,7 +62,7 @@ def test_conformer(test_runner, dtype: torch.dtype, use_dynamic_shapes: bool): encoder_padding_mask, ) - test_runner.lower_and_run_model(model, inputs) + test_runner.lower_and_run_model(model, inputs, generate_random_test_inputs=False) @pytest.mark.parametrize("dtype", [torch.float32], ids=dtype_to_str) diff --git a/examples/samsung/executor_runner/enn_executor_runner.cpp b/examples/samsung/executor_runner/enn_executor_runner.cpp index bdbff74088c..82a34411ef8 100644 --- a/examples/samsung/executor_runner/enn_executor_runner.cpp +++ b/examples/samsung/executor_runner/enn_executor_runner.cpp @@ -304,23 +304,12 @@ int main(int argc, char** argv) { status = method->execute(); } - // Run the model. - ET_LOG(Info, "Start 1st inference."); - auto before_exec = std::chrono::high_resolution_clock::now(); - status = method->execute(); - auto after_exec = std::chrono::high_resolution_clock::now(); - double interval_1st_infs = - std::chrono::duration_cast( - after_exec - before_exec) - .count() / - 1000.0; - ET_LOG(Info, "Start inference."); - before_exec = std::chrono::high_resolution_clock::now(); + auto before_exec = std::chrono::high_resolution_clock::now(); for (int i = 0; i < FLAGS_num_executions; ++i) { status = method->execute(); } - after_exec = std::chrono::high_resolution_clock::now(); + auto after_exec = std::chrono::high_resolution_clock::now(); double interval_infs = std::chrono::duration_cast( after_exec - before_exec) .count() / @@ -331,11 +320,8 @@ int main(int argc, char** argv) { std::ofstream fout(output_file_name); fout << "init: " + std::to_string(interval_init) << "\nload: " + std::to_string(interval_load) - << "\n1st: " + std::to_string(interval_1st_infs) << "\navg: " + - std::to_string( - (interval_infs + interval_1st_infs) / - ((float)FLAGS_num_executions + 1.f)) + std::to_string(interval_infs / (float)FLAGS_num_executions) << std::endl; fout.close(); } From 97eb3fe74e0f925e64383f8cd2b67d889d2663aa Mon Sep 17 00:00:00 2001 From: Jiseong Oh Date: Thu, 2 Apr 2026 09:13:17 +0800 Subject: [PATCH 3/5] Add bool return for NodeVisitor::define_node fixed to return bool for NodeVisitor::define_node Signed-off-by: Jiseong Oh Co-authored-by: Guochao Yang --- backends/samsung/builders/node_visitor.py | 6 ++- backends/samsung/builders/op_add.py | 4 +- backends/samsung/builders/op_avg_pool2d.py | 4 +- backends/samsung/builders/op_batch_norm.py | 4 +- backends/samsung/builders/op_bmm.py | 4 +- backends/samsung/builders/op_cat.py | 4 +- backends/samsung/builders/op_clamp.py | 4 +- .../samsung/builders/op_constant_pad_nd.py | 4 +- backends/samsung/builders/op_conv2d.py | 10 ++++- backends/samsung/builders/op_cos.py | 4 +- backends/samsung/builders/op_div.py | 4 +- backends/samsung/builders/op_embedding.py | 4 +- backends/samsung/builders/op_exp.py | 4 +- backends/samsung/builders/op_expand_copy.py | 14 +++++-- backends/samsung/builders/op_gelu.py | 4 +- backends/samsung/builders/op_getitem.py | 4 +- backends/samsung/builders/op_group_norm.py | 4 +- backends/samsung/builders/op_hardsigmoid.py | 4 +- backends/samsung/builders/op_hardswish.py | 4 +- backends/samsung/builders/op_hardtanh.py | 4 +- backends/samsung/builders/op_index.py | 4 +- backends/samsung/builders/op_layer_norm.py | 4 +- backends/samsung/builders/op_leaky_relu.py | 4 +- backends/samsung/builders/op_linear.py | 4 +- backends/samsung/builders/op_log.py | 4 +- backends/samsung/builders/op_log_softmax.py | 4 +- backends/samsung/builders/op_max_pool2d.py | 4 +- backends/samsung/builders/op_maximum.py | 4 +- backends/samsung/builders/op_mean_dim.py | 8 +++- backends/samsung/builders/op_minimum.py | 4 +- backends/samsung/builders/op_mul.py | 4 +- backends/samsung/builders/op_permute.py | 6 ++- backends/samsung/builders/op_pixel_shuffle.py | 4 +- backends/samsung/builders/op_placeholder.py | 4 +- backends/samsung/builders/op_pow.py | 15 ++++--- backends/samsung/builders/op_quantize.py | 41 +++++++++++-------- backends/samsung/builders/op_relu.py | 4 +- backends/samsung/builders/op_reshape.py | 4 +- backends/samsung/builders/op_rms_norm.py | 4 +- backends/samsung/builders/op_rsqrt.py | 4 +- backends/samsung/builders/op_select.py | 4 +- backends/samsung/builders/op_sigmoid.py | 4 +- backends/samsung/builders/op_sin.py | 4 +- backends/samsung/builders/op_skip.py | 4 +- backends/samsung/builders/op_slice_copy.py | 4 +- backends/samsung/builders/op_softmax.py | 4 +- .../builders/op_split_with_sizes_copy.py | 4 +- backends/samsung/builders/op_sqrt.py | 4 +- backends/samsung/builders/op_squeeze.py | 4 +- backends/samsung/builders/op_sub.py | 4 +- backends/samsung/builders/op_sum_int_list.py | 4 +- backends/samsung/builders/op_tanh.py | 4 +- backends/samsung/builders/op_to_copy.py | 4 +- backends/samsung/builders/op_topk.py | 4 +- backends/samsung/builders/op_unsqueeze.py | 4 +- .../builders/op_upsample_bilinear2d.py | 8 +++- .../samsung/builders/op_upsample_nearest2d.py | 8 +++- backends/samsung/partition/enn_partitioner.py | 10 ++++- 58 files changed, 235 insertions(+), 83 deletions(-) diff --git a/backends/samsung/builders/node_visitor.py b/backends/samsung/builders/node_visitor.py index 0d2707da8f5..cb7d4db690a 100644 --- a/backends/samsung/builders/node_visitor.py +++ b/backends/samsung/builders/node_visitor.py @@ -31,7 +31,7 @@ def __init__(self, exported_program: ExportedProgram) -> None: def exported_program(self) -> ExportedProgram: return self._exported_program - def define_node(self, node: torch.fx.Node, enn_graph: EnnGraph): + def define_node(self, node: torch.fx.Node, enn_graph: EnnGraph) -> bool: raise NotImplementedError("NodeVisitor must be extended!") def define_tensor( @@ -58,7 +58,9 @@ def define_tensor( if is_param_node(self.exported_program, node): if swap_nc_for_weights: tensor = torch.swapdims(tensor, 0, 1) - const_data = tensor.contiguous().detach().numpy() + if not isinstance(tensor, torch._subclasses.fake_tensor.FakeTensor): + # .numpy() is not supported for tensor subclasses if the tensor is a fake tensor. + const_data = tensor.contiguous().detach().numpy() dims = [1] if len(tensor.size()) == 0 else list(tensor.size()) diff --git a/backends/samsung/builders/op_add.py b/backends/samsung/builders/op_add.py index a6eb79897dd..acfa3070698 100644 --- a/backends/samsung/builders/op_add.py +++ b/backends/samsung/builders/op_add.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input1 = node.args[0] input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) params = {} @@ -39,3 +39,5 @@ def define_node( enn_graph.define_op( node.name, "ELTSUM", [input_id_1, input_id_2], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_avg_pool2d.py b/backends/samsung/builders/op_avg_pool2d.py index b2e6e160830..529a3156030 100644 --- a/backends/samsung/builders/op_avg_pool2d.py +++ b/backends/samsung/builders/op_avg_pool2d.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -64,3 +64,5 @@ def define_node( ), "Not supported divisor_override which is not equal to pooling region." output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "AVGPOOL2D", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_batch_norm.py b/backends/samsung/builders/op_batch_norm.py index d8c893e128e..49840580f4e 100644 --- a/backends/samsung/builders/op_batch_norm.py +++ b/backends/samsung/builders/op_batch_norm.py @@ -25,7 +25,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: all_input_tensors = [] input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -58,3 +58,5 @@ def define_node( enn_graph.define_op( node.name, "BatchNormalization", all_input_tensors, [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_bmm.py b/backends/samsung/builders/op_bmm.py index 13e0d19cb14..2ac96a4a1b7 100644 --- a/backends/samsung/builders/op_bmm.py +++ b/backends/samsung/builders/op_bmm.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input1 = node.args[0] input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) @@ -41,3 +41,5 @@ def define_node( enn_graph.define_op( node.name, "BATCH_MATMUL", [input_id_1, input_id_2], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_cat.py b/backends/samsung/builders/op_cat.py index 09387f2e361..82762cfcdbf 100644 --- a/backends/samsung/builders/op_cat.py +++ b/backends/samsung/builders/op_cat.py @@ -28,7 +28,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: tensors = cast(List[torch.fx.Node], node.args[0]) input_tensor_ids = [] constant_idx = None @@ -48,3 +48,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "CONCAT", input_tensor_ids, [output_id], params) + + return True diff --git a/backends/samsung/builders/op_clamp.py b/backends/samsung/builders/op_clamp.py index 74af83212a5..78ec1a08a47 100644 --- a/backends/samsung/builders/op_clamp.py +++ b/backends/samsung/builders/op_clamp.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -45,3 +45,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "CLIP", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_constant_pad_nd.py b/backends/samsung/builders/op_constant_pad_nd.py index 006f52619ff..bc72305bc13 100644 --- a/backends/samsung/builders/op_constant_pad_nd.py +++ b/backends/samsung/builders/op_constant_pad_nd.py @@ -29,7 +29,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -54,3 +54,5 @@ def define_node( } self._update_params_qdtype(node, params) enn_graph.define_op(node.name, "PAD", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_conv2d.py b/backends/samsung/builders/op_conv2d.py index 2ff80b1b011..557e6c36427 100644 --- a/backends/samsung/builders/op_conv2d.py +++ b/backends/samsung/builders/op_conv2d.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import cast, Dict, List import torch @@ -27,7 +28,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: all_input_tensors = [] input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -52,6 +53,11 @@ def define_node( padding = cast(List[int], node.args[4]) dilation = cast(List[int], node.args[5]) groups = cast(int, node.args[8]) + if len(padding) < 2: + logging.warning( + "For conv1d decomposed to conv2d(with conv1d params), Conv1dToConv2d pass will update the params." + ) + return True explicit_padding = [padding[0], padding[1], padding[0], padding[1]] input_shape = get_shape(input) @@ -87,3 +93,5 @@ def define_node( enn_graph.define_op( node.name, conv_type, all_input_tensors, [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_cos.py b/backends/samsung/builders/op_cos.py index bd746db91cd..f1d4d917b7d 100644 --- a/backends/samsung/builders/op_cos.py +++ b/backends/samsung/builders/op_cos.py @@ -23,9 +23,11 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input_id = self.define_tensor(node.args[0], enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "Cos", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_div.py b/backends/samsung/builders/op_div.py index 8b0e7cdd5af..7afc23220fe 100644 --- a/backends/samsung/builders/op_div.py +++ b/backends/samsung/builders/op_div.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input1 = node.args[0] input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) @@ -40,3 +40,5 @@ def define_node( enn_graph.define_op( node.name, "ELTDIV", [input_id_1, input_id_2], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_embedding.py b/backends/samsung/builders/op_embedding.py index a500ea051fd..bc28ae4e55e 100644 --- a/backends/samsung/builders/op_embedding.py +++ b/backends/samsung/builders/op_embedding.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: weight_node = node.args[0] weight_id = self.define_tensor(weight_node, enn_graph, vals_to_ids) @@ -40,3 +40,5 @@ def define_node( enn_graph.define_op( node.name, "GATHER", [weight_id, input_id], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_exp.py b/backends/samsung/builders/op_exp.py index a93f4b9be02..63dd9ca3219 100644 --- a/backends/samsung/builders/op_exp.py +++ b/backends/samsung/builders/op_exp.py @@ -23,9 +23,11 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input_id = self.define_tensor(node.args[0], enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "Exp", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_expand_copy.py b/backends/samsung/builders/op_expand_copy.py index f4c707b8e62..5fb6b6c5166 100644 --- a/backends/samsung/builders/op_expand_copy.py +++ b/backends/samsung/builders/op_expand_copy.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import cast, Dict, List import torch @@ -27,7 +28,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ): + ) -> bool: # inputs input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -35,6 +36,8 @@ def define_node( in_shape = get_shape(input) sizes = cast(List[int], node.args[1]) expand_dims = self.check_expand_dims(sizes, in_shape) + if expand_dims is None: + return False # output output_id = self.define_tensor(node, enn_graph, vals_to_ids) @@ -53,7 +56,10 @@ def define_node( params, ) else: - raise NotImplementedError("Don't support expanding at more than one axes.") + logging.warning("Don't support expanding at more than one axes.") + return False + + return True def check_expand_dims(self, sizes, in_shape): expand_dims = [] @@ -72,6 +78,8 @@ def check_expand_dims(self, sizes, in_shape): while new_size_index > 0: new_size_index -= 1 - assert sizes[new_size_index] == 1, "Current expand is unsupported!" + if sizes[new_size_index] != 1: + logging.warning("Current expand is unsupported!") + return None return expand_dims diff --git a/backends/samsung/builders/op_gelu.py b/backends/samsung/builders/op_gelu.py index 88417f688f9..6a064194561 100644 --- a/backends/samsung/builders/op_gelu.py +++ b/backends/samsung/builders/op_gelu.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: # input1 input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -38,3 +38,5 @@ def define_node( self._update_params_qdtype(node, params) enn_graph.define_op(node.name, "GELU", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_getitem.py b/backends/samsung/builders/op_getitem.py index 901ec73cf7d..bc7c0441e3c 100644 --- a/backends/samsung/builders/op_getitem.py +++ b/backends/samsung/builders/op_getitem.py @@ -28,5 +28,5 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: - return + ) -> bool: + return True diff --git a/backends/samsung/builders/op_group_norm.py b/backends/samsung/builders/op_group_norm.py index 55c7bb6732a..b0509005053 100644 --- a/backends/samsung/builders/op_group_norm.py +++ b/backends/samsung/builders/op_group_norm.py @@ -23,7 +23,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: all_input_tensors = [] input_id = self.define_tensor(node.args[0], enn_graph, vals_to_ids) all_input_tensors.append(input_id) @@ -44,3 +44,5 @@ def define_node( enn_graph.define_op( node.name, "GROUPNORM", all_input_tensors, [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_hardsigmoid.py b/backends/samsung/builders/op_hardsigmoid.py index 3a50d65da41..58cc0a12d5b 100644 --- a/backends/samsung/builders/op_hardsigmoid.py +++ b/backends/samsung/builders/op_hardsigmoid.py @@ -26,10 +26,12 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) params = {} self._update_params_qdtype(node, params) enn_graph.define_op(node.name, "HardSigmoid", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_hardswish.py b/backends/samsung/builders/op_hardswish.py index 8c30125e8a4..fc9ec134418 100644 --- a/backends/samsung/builders/op_hardswish.py +++ b/backends/samsung/builders/op_hardswish.py @@ -26,10 +26,12 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) params = {} self._update_params_qdtype(node, params) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "HARDSWISH", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_hardtanh.py b/backends/samsung/builders/op_hardtanh.py index 7d65e97a566..4c60d7227dc 100644 --- a/backends/samsung/builders/op_hardtanh.py +++ b/backends/samsung/builders/op_hardtanh.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -40,3 +40,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "CLIP", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_index.py b/backends/samsung/builders/op_index.py index b7765e35b3f..0145616de56 100644 --- a/backends/samsung/builders/op_index.py +++ b/backends/samsung/builders/op_index.py @@ -23,7 +23,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -47,3 +47,5 @@ def define_node( enn_graph.define_op( node.name, "GATHER", [input_id, indices_id], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_layer_norm.py b/backends/samsung/builders/op_layer_norm.py index 098bc92dc84..937168c36e9 100644 --- a/backends/samsung/builders/op_layer_norm.py +++ b/backends/samsung/builders/op_layer_norm.py @@ -25,7 +25,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: all_input_tensors = [] input_node = node.args[0] input_id = self.define_tensor(input_node, enn_graph, vals_to_ids) @@ -51,3 +51,5 @@ def define_node( enn_graph.define_op( node.name, "LAYERNORM", all_input_tensors, [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_leaky_relu.py b/backends/samsung/builders/op_leaky_relu.py index c7ed37d12e5..28f4a7851d4 100644 --- a/backends/samsung/builders/op_leaky_relu.py +++ b/backends/samsung/builders/op_leaky_relu.py @@ -27,7 +27,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: all_input_tensors = [] input_id = self.define_tensor(node.args[0], enn_graph, vals_to_ids) all_input_tensors.append(input_id) @@ -56,3 +56,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "PRELU", all_input_tensors, [output_id]) + + return True diff --git a/backends/samsung/builders/op_linear.py b/backends/samsung/builders/op_linear.py index 720439de976..dffb6b0108c 100644 --- a/backends/samsung/builders/op_linear.py +++ b/backends/samsung/builders/op_linear.py @@ -27,7 +27,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: all_input_tensors = [] input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -49,3 +49,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "FC", all_input_tensors, [output_id], params) + + return True diff --git a/backends/samsung/builders/op_log.py b/backends/samsung/builders/op_log.py index 97127dd94ba..a20de9bd95d 100644 --- a/backends/samsung/builders/op_log.py +++ b/backends/samsung/builders/op_log.py @@ -23,10 +23,12 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "LOG", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_log_softmax.py b/backends/samsung/builders/op_log_softmax.py index f2d87601cbb..f26a36e2af7 100644 --- a/backends/samsung/builders/op_log_softmax.py +++ b/backends/samsung/builders/op_log_softmax.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ): + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -37,3 +37,5 @@ def define_node( meta_data = {"axis": axis} enn_graph.define_op(node.name, "LOGSOFTMAX", [input_id], [output_id], meta_data) + + return True diff --git a/backends/samsung/builders/op_max_pool2d.py b/backends/samsung/builders/op_max_pool2d.py index 805f68fd929..bec8da5f683 100644 --- a/backends/samsung/builders/op_max_pool2d.py +++ b/backends/samsung/builders/op_max_pool2d.py @@ -25,7 +25,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -90,3 +90,5 @@ def define_node( ) enn_graph.define_op(node.name, "MAXPOOL2D", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_maximum.py b/backends/samsung/builders/op_maximum.py index d3358d736f3..d81dfdd4a35 100644 --- a/backends/samsung/builders/op_maximum.py +++ b/backends/samsung/builders/op_maximum.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: # inputs input_id_1 = self.define_tensor(node.args[0], enn_graph, vals_to_ids) input_id_2 = self.define_tensor(node.args[1], enn_graph, vals_to_ids) @@ -35,3 +35,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "MAXIMUM", [input_id_1, input_id_2], [output_id]) + + return True diff --git a/backends/samsung/builders/op_mean_dim.py b/backends/samsung/builders/op_mean_dim.py index 3d0377703a7..46d56058ceb 100644 --- a/backends/samsung/builders/op_mean_dim.py +++ b/backends/samsung/builders/op_mean_dim.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import cast, Dict, List import torch @@ -27,7 +28,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: # input input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -37,6 +38,9 @@ def define_node( dims = cast(List[int], node.args[1]) reduce_axes = [] in_shape = get_shape(input) + if dims is None: + logging.warning("dims is None for this case.") + return False for dim in dims: reduce_axes.append(dim % len(in_shape)) @@ -47,3 +51,5 @@ def define_node( params = {"keep_dims": keep_dim, "axis": reduce_axes} self._update_params_qdtype(node, params) enn_graph.define_op(node.name, "REDUCEMEAN", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_minimum.py b/backends/samsung/builders/op_minimum.py index a32b462d45f..4c612df34c7 100644 --- a/backends/samsung/builders/op_minimum.py +++ b/backends/samsung/builders/op_minimum.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: # inputs input1 = node.args[0] input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) @@ -37,3 +37,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "MIN", [input_id_1, input_id_2], [output_id]) + + return True diff --git a/backends/samsung/builders/op_mul.py b/backends/samsung/builders/op_mul.py index 6dd7c0dd9f0..e703ddff253 100644 --- a/backends/samsung/builders/op_mul.py +++ b/backends/samsung/builders/op_mul.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input1 = node.args[0] input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) @@ -41,3 +41,5 @@ def define_node( enn_graph.define_op( node.name, "ELTMUL", [input_id_1, input_id_2], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_permute.py b/backends/samsung/builders/op_permute.py index 646eac4c06a..42286dddfef 100644 --- a/backends/samsung/builders/op_permute.py +++ b/backends/samsung/builders/op_permute.py @@ -25,13 +25,17 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) # permutation permute_order = cast(List[int], node.args[1]) + # to prevent negative values + permute_order = [x % len(permute_order) for x in permute_order] params = {"perm": permute_order} output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "TRANSPOSE", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_pixel_shuffle.py b/backends/samsung/builders/op_pixel_shuffle.py index 28259299c81..db0aaaaef08 100644 --- a/backends/samsung/builders/op_pixel_shuffle.py +++ b/backends/samsung/builders/op_pixel_shuffle.py @@ -25,7 +25,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input_id = self.define_tensor(node.args[0], enn_graph, vals_to_ids) scale_factor = cast(int, node.args[1]) @@ -36,3 +36,5 @@ def define_node( enn_graph.define_op( node.name, "DEPTH_TO_SPACE", [input_id], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_placeholder.py b/backends/samsung/builders/op_placeholder.py index b4b606f56ea..8c6a89a5eb5 100644 --- a/backends/samsung/builders/op_placeholder.py +++ b/backends/samsung/builders/op_placeholder.py @@ -31,7 +31,9 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: if is_param_node(self.exported_program, node): return self.define_tensor(node, enn_graph, vals_to_ids) + + return True diff --git a/backends/samsung/builders/op_pow.py b/backends/samsung/builders/op_pow.py index cd6ec7f81ef..d417685126e 100644 --- a/backends/samsung/builders/op_pow.py +++ b/backends/samsung/builders/op_pow.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import Dict import torch @@ -24,15 +25,17 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input1 = node.args[0] input2 = node.args[1] input_tensor_1 = get_tensor(self.exported_program, input1) input_tensor_2 = get_tensor(self.exported_program, input2) - assert ( - input_tensor_1.dtype == torch.float32 - and input_tensor_2.dtype == torch.float32 - ), "Requires the two inputs are all float type" + if ( + input_tensor_1.dtype != torch.float32 + or input_tensor_2.dtype != torch.float32 + ): + logging.warning("Requires the two inputs are all float type.") + return False input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) input_id_2 = self.define_tensor(input2, enn_graph, vals_to_ids) @@ -40,3 +43,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "POW", [input_id_1, input_id_2], [output_id]) + + return True diff --git a/backends/samsung/builders/op_quantize.py b/backends/samsung/builders/op_quantize.py index dcf30e291f9..771ab419888 100644 --- a/backends/samsung/builders/op_quantize.py +++ b/backends/samsung/builders/op_quantize.py @@ -24,32 +24,39 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: # input input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) scales = node.args[1] - if isinstance(scales, torch.Tensor): - scales = scales.tolist() - elif not isinstance(scales, list): - scales = torch.tensor(scales).reshape([1]).tolist() zero_points = node.args[2] - if isinstance(zero_points, torch.Tensor): - zero_points = zero_points.tolist() - elif not isinstance(zero_points, list): - zero_points = torch.tensor(zero_points).reshape([1]).tolist() + if not isinstance(scales, torch.fx.Node) and not isinstance( + zero_points, torch.fx.Node + ): + if isinstance(scales, torch.Tensor): + scales = scales.tolist() + elif not isinstance(scales, list): + scales = torch.tensor(scales).reshape([1]).tolist() + if isinstance(zero_points, torch.Tensor): + zero_points = zero_points.tolist() + elif not isinstance(zero_points, list): + zero_points = torch.tensor(zero_points).reshape([1]).tolist() - output_id = self.define_tensor(node, enn_graph, vals_to_ids) + output_id = self.define_tensor(node, enn_graph, vals_to_ids) - params = {"scales": scales, "zero_points": zero_points} + params = {"scales": scales, "zero_points": zero_points} - if node.target in QuantConstants.QUANT_OPS_KEY_MAP: - enn_graph.define_op(node.name, "QUANTIZE", [input_id], [output_id], params) - else: - enn_graph.define_op( - node.name, "DEQUANTIZE", [input_id], [output_id], params - ) + if node.target in QuantConstants.QUANT_OPS_KEY_MAP: + enn_graph.define_op( + node.name, "QUANTIZE", [input_id], [output_id], params + ) + else: + enn_graph.define_op( + node.name, "DEQUANTIZE", [input_id], [output_id], params + ) + + return True @register_node_visitor diff --git a/backends/samsung/builders/op_relu.py b/backends/samsung/builders/op_relu.py index a4a2b6bc4f0..fb2668e46fc 100644 --- a/backends/samsung/builders/op_relu.py +++ b/backends/samsung/builders/op_relu.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -35,3 +35,5 @@ def define_node( self._update_params_qdtype(node, params) enn_graph.define_op(node.name, "RELU", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_reshape.py b/backends/samsung/builders/op_reshape.py index 4ec45383cb1..bb413ed793d 100644 --- a/backends/samsung/builders/op_reshape.py +++ b/backends/samsung/builders/op_reshape.py @@ -23,7 +23,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -36,3 +36,5 @@ def define_node( enn_graph.define_op( node.name, "RESHAPE", [input_id], [output_id], {"new_shape": shape} ) + + return True diff --git a/backends/samsung/builders/op_rms_norm.py b/backends/samsung/builders/op_rms_norm.py index 6a58d62a5ce..0ff01701d1b 100644 --- a/backends/samsung/builders/op_rms_norm.py +++ b/backends/samsung/builders/op_rms_norm.py @@ -24,7 +24,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: # args of node : ['input', 'normalized_shape', 'weight', 'eps'] input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -50,3 +50,5 @@ def define_node( enn_graph.define_op( node.name, "RMSNORM", [input_id, gamma_id], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_rsqrt.py b/backends/samsung/builders/op_rsqrt.py index b3600d41ee2..55e9ddf54f9 100644 --- a/backends/samsung/builders/op_rsqrt.py +++ b/backends/samsung/builders/op_rsqrt.py @@ -26,10 +26,12 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "RSQRT", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_select.py b/backends/samsung/builders/op_select.py index 26f455b2548..3f3550d3cf8 100644 --- a/backends/samsung/builders/op_select.py +++ b/backends/samsung/builders/op_select.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ): + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -50,3 +50,5 @@ def define_node( } enn_graph.define_op(node.name, "STRIDEDSLICE", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_sigmoid.py b/backends/samsung/builders/op_sigmoid.py index e87973f9a85..aef9d90ec52 100644 --- a/backends/samsung/builders/op_sigmoid.py +++ b/backends/samsung/builders/op_sigmoid.py @@ -23,10 +23,12 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "SIGMOID", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_sin.py b/backends/samsung/builders/op_sin.py index 5fd22e8275e..11dc6bccb46 100644 --- a/backends/samsung/builders/op_sin.py +++ b/backends/samsung/builders/op_sin.py @@ -23,9 +23,11 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input_id = self.define_tensor(node.args[0], enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "Sin", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_skip.py b/backends/samsung/builders/op_skip.py index 16da4bdd289..3413e603983 100644 --- a/backends/samsung/builders/op_skip.py +++ b/backends/samsung/builders/op_skip.py @@ -28,5 +28,5 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: - return + ) -> bool: + return True diff --git a/backends/samsung/builders/op_slice_copy.py b/backends/samsung/builders/op_slice_copy.py index e85b6bf60c3..4b837db1b12 100644 --- a/backends/samsung/builders/op_slice_copy.py +++ b/backends/samsung/builders/op_slice_copy.py @@ -27,7 +27,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ): + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -61,3 +61,5 @@ def define_node( params = {"begin": begin, "end": end, "strides": strides} enn_graph.define_op(node.name, "STRIDEDSLICE", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_softmax.py b/backends/samsung/builders/op_softmax.py index 7f569cea6fc..e96b5638db3 100644 --- a/backends/samsung/builders/op_softmax.py +++ b/backends/samsung/builders/op_softmax.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ): + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -37,3 +37,5 @@ def define_node( params = {"axis": axis} self._update_params_qdtype(node, params) enn_graph.define_op(node.name, "SOFTMAX", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_split_with_sizes_copy.py b/backends/samsung/builders/op_split_with_sizes_copy.py index e6caaf0ba7a..48612ba9a6d 100644 --- a/backends/samsung/builders/op_split_with_sizes_copy.py +++ b/backends/samsung/builders/op_split_with_sizes_copy.py @@ -23,7 +23,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -50,3 +50,5 @@ def define_node( params["point"] = node.args[1] enn_graph.define_op(node.name, "SPLIT", [input_id], all_output_tensors, params) + + return True diff --git a/backends/samsung/builders/op_sqrt.py b/backends/samsung/builders/op_sqrt.py index 3560542a0bc..77793e4589d 100644 --- a/backends/samsung/builders/op_sqrt.py +++ b/backends/samsung/builders/op_sqrt.py @@ -26,10 +26,12 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "SQRT", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_squeeze.py b/backends/samsung/builders/op_squeeze.py index 82fa17fbc95..ff5286fee28 100644 --- a/backends/samsung/builders/op_squeeze.py +++ b/backends/samsung/builders/op_squeeze.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -35,3 +35,5 @@ def define_node( params = {"new_shape": [*node.meta["val"].shape]} enn_graph.define_op(node.name, "RESHAPE", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_sub.py b/backends/samsung/builders/op_sub.py index 7dc97bfa7ca..feb4173aca9 100644 --- a/backends/samsung/builders/op_sub.py +++ b/backends/samsung/builders/op_sub.py @@ -26,7 +26,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: # inputs input1 = node.args[0] input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) @@ -41,3 +41,5 @@ def define_node( enn_graph.define_op( node.name, "SUB", [input_id_1, input_id_2], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_sum_int_list.py b/backends/samsung/builders/op_sum_int_list.py index 7743e6632dd..a8c5367371c 100644 --- a/backends/samsung/builders/op_sum_int_list.py +++ b/backends/samsung/builders/op_sum_int_list.py @@ -24,7 +24,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -37,3 +37,5 @@ def define_node( output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "REDUCESUM", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_tanh.py b/backends/samsung/builders/op_tanh.py index 5b002890075..106256c791b 100644 --- a/backends/samsung/builders/op_tanh.py +++ b/backends/samsung/builders/op_tanh.py @@ -23,10 +23,12 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) output_id = self.define_tensor(node, enn_graph, vals_to_ids) enn_graph.define_op(node.name, "TANH", [input_id], [output_id]) + + return True diff --git a/backends/samsung/builders/op_to_copy.py b/backends/samsung/builders/op_to_copy.py index c770602bb5f..143ab007cba 100644 --- a/backends/samsung/builders/op_to_copy.py +++ b/backends/samsung/builders/op_to_copy.py @@ -28,7 +28,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: memory_format_target = node.kwargs.get("memory_format", torch.contiguous_format) to_contiguous = bool(memory_format_target == torch.contiguous_format) assert to_contiguous, "Don't support other param in _to_copy" @@ -42,3 +42,5 @@ def define_node( params["out_dtype"] = get_map_dtype(out_tensor.dtype) enn_graph.define_op(node.name, "CAST", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_topk.py b/backends/samsung/builders/op_topk.py index e4cda0ef148..6a4de9ccc91 100644 --- a/backends/samsung/builders/op_topk.py +++ b/backends/samsung/builders/op_topk.py @@ -24,7 +24,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -72,3 +72,5 @@ def define_node( raise AssertionError("Not supported sorted = False.") enn_graph.define_op(node.name, "TopK", [input_id], all_output_tensors, params) + + return True diff --git a/backends/samsung/builders/op_unsqueeze.py b/backends/samsung/builders/op_unsqueeze.py index 61fa06e6310..18f7c2d33b2 100644 --- a/backends/samsung/builders/op_unsqueeze.py +++ b/backends/samsung/builders/op_unsqueeze.py @@ -25,7 +25,7 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) @@ -33,3 +33,5 @@ def define_node( params = {"new_shape": [*node.meta["val"].shape]} enn_graph.define_op(node.name, "RESHAPE", [input_id], [output_id], params) + + return True diff --git a/backends/samsung/builders/op_upsample_bilinear2d.py b/backends/samsung/builders/op_upsample_bilinear2d.py index d4b040460e3..7e24122c0e6 100644 --- a/backends/samsung/builders/op_upsample_bilinear2d.py +++ b/backends/samsung/builders/op_upsample_bilinear2d.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import cast, Dict, List import torch @@ -27,11 +28,14 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) in_shape = get_shape(input) output_size = cast(List[int], node.args[1]) + if output_size is None: + logging.warning("output is None for this case.") + return False scale_factor = [ output_size[0] * 1.0 / in_shape[-2], output_size[1] * 1.0 / in_shape[-1], @@ -51,3 +55,5 @@ def define_node( enn_graph.define_op( node.name, "RESIZE_BILINEAR", [input_id], [output_id], params ) + + return True diff --git a/backends/samsung/builders/op_upsample_nearest2d.py b/backends/samsung/builders/op_upsample_nearest2d.py index 9859cd8f07e..6af5402d56c 100644 --- a/backends/samsung/builders/op_upsample_nearest2d.py +++ b/backends/samsung/builders/op_upsample_nearest2d.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import cast, Dict, List import torch @@ -27,11 +28,14 @@ def define_node( node: torch.fx.Node, enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], - ) -> None: + ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) in_shape = get_shape(input) output_size = cast(List[int], node.args[1]) + if output_size is None: + logging.warning("output is None for this case.") + return False scale_factor = [ output_size[0] * 1.0 / in_shape[-2], output_size[1] * 1.0 / in_shape[-1], @@ -50,3 +54,5 @@ def define_node( enn_graph.define_op( node.name, "RESIZE_NEAREST_NEIGHBOR", [input_id], [output_id], params ) + + return True diff --git a/backends/samsung/partition/enn_partitioner.py b/backends/samsung/partition/enn_partitioner.py index 91f496e7a5c..35f99f420d0 100644 --- a/backends/samsung/partition/enn_partitioner.py +++ b/backends/samsung/partition/enn_partitioner.py @@ -15,6 +15,7 @@ from executorch.backends.samsung.serialization.compile_options import ( ENN_COMPILE_OPTION_TITLE, ) +from executorch.backends.samsung.serialization.enn_graph_schema import EnnGraph from executorch.backends.samsung.utils.utils import get_compile_spec from executorch.exir.backend.backend_details import CompileSpec from executorch.exir.backend.canonical_partitioners.pattern_op_partitioner import ( @@ -70,9 +71,16 @@ def is_node_supported(self, _, node: torch.fx.Node) -> bool: ]: return False - if node.target in SUPPORTED_OPS or node.target.__name__ in self.node_visitors: + if node.target in SUPPORTED_OPS: return True + if node.target.__name__ in self.node_visitors: + enn_graph = EnnGraph() + vals_to_ids: Dict[torch.fx.Node, int] = {} + return self.node_visitors[node.target.__name__].define_node( + node, enn_graph, vals_to_ids + ) + supported = self.enn_wrapper.IsNodeSupportedByBackend() return supported From c1fb30a6240e247c287e6a319e33d86de024e1d2 Mon Sep 17 00:00:00 2001 From: Jiseong Oh Date: Tue, 14 Apr 2026 19:10:00 +0800 Subject: [PATCH 4/5] Fix issues for ops in test suite Fix issues for some ops for testSuite Signed-off-by: Jiseong Oh Co-authored-by: Guochao Yang --- backends/samsung/builders/op_add.py | 5 +++++ backends/samsung/builders/op_clamp.py | 6 ++++++ backends/samsung/builders/op_conv2d.py | 10 ++++++++++ backends/samsung/builders/op_mean_dim.py | 5 +++++ backends/samsung/builders/op_sub.py | 5 +++++ backends/samsung/builders/op_upsample_bilinear2d.py | 2 +- backends/samsung/partition/enn_partitioner.py | 2 -- backends/samsung/test/utils/runtime_executor.py | 2 +- backends/samsung/utils/export_utils.py | 5 +++++ 9 files changed, 38 insertions(+), 4 deletions(-) diff --git a/backends/samsung/builders/op_add.py b/backends/samsung/builders/op_add.py index acfa3070698..177f700f7e1 100644 --- a/backends/samsung/builders/op_add.py +++ b/backends/samsung/builders/op_add.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import Dict import torch @@ -33,6 +34,10 @@ def define_node( self._update_params_qdtype(node, params) input2 = node.args[1] input_id_2 = self.define_tensor(input2, enn_graph, vals_to_ids) + alpha = node.kwargs.get("alpha", 1.0) + if alpha != 1.0: + logging.warning("Currently, only alpha 1 for add is supported.") + return False output_id = self.define_tensor(node, enn_graph, vals_to_ids) diff --git a/backends/samsung/builders/op_clamp.py b/backends/samsung/builders/op_clamp.py index 78ec1a08a47..b69066c3337 100644 --- a/backends/samsung/builders/op_clamp.py +++ b/backends/samsung/builders/op_clamp.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import cast, Dict import torch @@ -11,6 +12,7 @@ NodeVisitor, register_node_visitor, ) +from executorch.backends.samsung.builders.utils import get_tensor from executorch.backends.samsung.serialization.enn_graph_schema import EnnGraph @@ -29,6 +31,10 @@ def define_node( ) -> bool: input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) + input_tensor = get_tensor(self.exported_program, input) + if input_tensor.dtype == torch.int64: + logging.warning("Currently, int64 clip is unsupported!") + return False # The default value of lower bound and upper bound output_min = torch.finfo(torch.float32).min diff --git a/backends/samsung/builders/op_conv2d.py b/backends/samsung/builders/op_conv2d.py index 557e6c36427..87f76f610bf 100644 --- a/backends/samsung/builders/op_conv2d.py +++ b/backends/samsung/builders/op_conv2d.py @@ -53,6 +53,13 @@ def define_node( padding = cast(List[int], node.args[4]) dilation = cast(List[int], node.args[5]) groups = cast(int, node.args[8]) + if is_transpose_conv and groups != 1: + logging.warning("Don't support groups for transpose conv.") + return False + output_padding = cast(List[int], node.args[7]) + if is_transpose_conv and output_padding != [0, 0]: + logging.warning("Don't support output padding for transpose conv.") + return False if len(padding) < 2: logging.warning( "For conv1d decomposed to conv2d(with conv1d params), Conv1dToConv2d pass will update the params." @@ -61,6 +68,9 @@ def define_node( explicit_padding = [padding[0], padding[1], padding[0], padding[1]] input_shape = get_shape(input) + if len(input_shape) > 4: + logging.warning("Currently, only conv2d is supported.") + return False kernel_shape = get_shape(weight_node) params = {} self._update_params_qdtype(node, params) diff --git a/backends/samsung/builders/op_mean_dim.py b/backends/samsung/builders/op_mean_dim.py index 46d56058ceb..3396102c045 100644 --- a/backends/samsung/builders/op_mean_dim.py +++ b/backends/samsung/builders/op_mean_dim.py @@ -12,6 +12,7 @@ NodeVisitor, register_node_visitor, ) +from executorch.backends.samsung.builders.utils import get_tensor from executorch.backends.samsung.serialization.enn_graph_schema import EnnGraph from executorch.backends.transforms import get_shape @@ -29,6 +30,10 @@ def define_node( enn_graph: EnnGraph, vals_to_ids: Dict[torch.Tensor, int], ) -> bool: + output_tensor = get_tensor(self.exported_program, node) + if output_tensor.dtype == torch.float64: + logging.warning("float64 for mean has not supported yet.") + return False # input input = node.args[0] input_id = self.define_tensor(input, enn_graph, vals_to_ids) diff --git a/backends/samsung/builders/op_sub.py b/backends/samsung/builders/op_sub.py index feb4173aca9..c12f4c85f4d 100644 --- a/backends/samsung/builders/op_sub.py +++ b/backends/samsung/builders/op_sub.py @@ -4,6 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. +import logging from typing import Dict import torch @@ -32,6 +33,10 @@ def define_node( input_id_1 = self.define_tensor(input1, enn_graph, vals_to_ids) input2 = node.args[1] input_id_2 = self.define_tensor(input2, enn_graph, vals_to_ids) + alpha = node.kwargs.get("alpha", 1.0) + if alpha != 1.0: + logging.warning("Currently, only alpha 1 for sub is supported.") + return False # output output_id = self.define_tensor(node, enn_graph, vals_to_ids) diff --git a/backends/samsung/builders/op_upsample_bilinear2d.py b/backends/samsung/builders/op_upsample_bilinear2d.py index 7e24122c0e6..7374e687101 100644 --- a/backends/samsung/builders/op_upsample_bilinear2d.py +++ b/backends/samsung/builders/op_upsample_bilinear2d.py @@ -48,7 +48,7 @@ def define_node( params = { "align_corners": align_corners, "upsampling_factor": scale_factor, - "half_pixel_centers": True, + "half_pixel_centers": not align_corners, } self._update_params_qdtype(node, params) output_id = self.define_tensor(node, enn_graph, vals_to_ids) diff --git a/backends/samsung/partition/enn_partitioner.py b/backends/samsung/partition/enn_partitioner.py index 35f99f420d0..7eb5c44b2a5 100644 --- a/backends/samsung/partition/enn_partitioner.py +++ b/backends/samsung/partition/enn_partitioner.py @@ -135,8 +135,6 @@ def ops_to_not_decompose( torch.ops.aten.max_pool2d.default, torch.ops.aten.linear.default, torch.ops.aten._safe_softmax.default, - torch.ops.aten.upsample_bilinear2d.vec, - torch.ops.aten.upsample_nearest2d.vec, torch.ops.aten.prelu.default, torch.ops.aten.layer_norm.default, torch.ops.aten.pixel_shuffle.default, diff --git a/backends/samsung/test/utils/runtime_executor.py b/backends/samsung/test/utils/runtime_executor.py index 9bc274799d7..2d58444ad99 100644 --- a/backends/samsung/test/utils/runtime_executor.py +++ b/backends/samsung/test/utils/runtime_executor.py @@ -157,7 +157,7 @@ def run_on_device(self) -> Tuple[torch.Tensor]: output_tensor = ( torch.from_numpy(output_array) .view(dtype=model_outputs[idx].dtype) - .view(*model_outputs[idx].shape) + .reshape(model_outputs[idx].shape) ) result.append(output_tensor) diff --git a/backends/samsung/utils/export_utils.py b/backends/samsung/utils/export_utils.py index 22f1833bd18..86512b75dec 100644 --- a/backends/samsung/utils/export_utils.py +++ b/backends/samsung/utils/export_utils.py @@ -37,6 +37,11 @@ def get_edge_compile_config(): exir_ops.edge.aten.layer_norm.default, exir_ops.edge.aten.matmul.default, exir_ops.edge.aten.hardsigmoid.default, + exir_ops.edge.aten.round.decimals, + exir_ops.edge.aten.median.dim, + exir_ops.edge.aten.median.default, + exir_ops.edge.aten.adaptive_max_pool2d.default, + exir_ops.edge.aten.adaptive_max_pool3d.default, ], ) From 9af67b2981d29d08c097e0fe66fe4cb6f394ee19 Mon Sep 17 00:00:00 2001 From: Jiseong Oh Date: Wed, 15 Apr 2026 15:44:34 +0800 Subject: [PATCH 5/5] Fix graph connection issue Signed-off-by: Jiseong Oh Co-authored-by: Guochao Yang --- backends/samsung/_passes/replace_scalar_ops.py | 9 ++++++++- backends/samsung/partition/enn_partitioner.py | 11 ++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/backends/samsung/_passes/replace_scalar_ops.py b/backends/samsung/_passes/replace_scalar_ops.py index 8ae54b0dc98..22a74c15f61 100644 --- a/backends/samsung/_passes/replace_scalar_ops.py +++ b/backends/samsung/_passes/replace_scalar_ops.py @@ -38,9 +38,16 @@ def call_operator( if op not in self._ops_with_scalar: return super().call_operator(op, args, kwargs, meta) + # For pow operation, convert int scalar to float32 tensor + # because the PowVisitor requires both inputs to be float32 + if op == exir_ops.edge.aten.pow.Tensor_Scalar and isinstance(args[1], int): + args1 = torch.tensor(float(args[1]), dtype=torch.float32) + else: + args1 = torch.tensor(args[1]) + return super().call_operator( op=self._ops_with_scalar.get(op, op), - args=(args[0], torch.tensor(args[1])), + args=(args[0], args1), kwargs=kwargs, meta=meta, ) diff --git a/backends/samsung/partition/enn_partitioner.py b/backends/samsung/partition/enn_partitioner.py index 7eb5c44b2a5..3e450cdf1bd 100644 --- a/backends/samsung/partition/enn_partitioner.py +++ b/backends/samsung/partition/enn_partitioner.py @@ -99,10 +99,19 @@ def generate_partitions( self, edge_program: torch.export.ExportedProgram ) -> List[Any]: self.op_support_checker = EnnOperatorSupport(edge_program, self.compile_specs) - return generate_partitions_from_list_of_nodes( + partition_list = generate_partitions_from_list_of_nodes( edge_program.graph_module, op_support=self.op_support_checker, ) + if len(partition_list) == 1 and partition_list[0].size() == 1: + first_node = list(partition_list[0].nodes.keys())[0] + # If there is only one partition graph containing a single "aten.clone.default" that is a useless operation, + # the RemoveUselessOpPass will remove this operation and cause a graph error. + # Therefore, we delete this node to prevent this graph error. + # For example, in the test_index_put_in_place_dtype case partition_list is [{aten_clone_default: 2}] + if first_node.target == exir_ops.edge.aten.clone.default: + del partition_list[0] + return partition_list def tag_nodes(self, partitions: List[Partition]) -> None: partition_tags: Dict[str, DelegationSpec] = {}