Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion backends/samsung/_passes/remove_useless_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion backends/samsung/_passes/replace_scalar_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
4 changes: 4 additions & 0 deletions backends/samsung/builders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
op_dequantize,
op_div,
op_embedding,
op_exp,
op_expand_copy,
op_gelu,
op_getitem,
Expand Down Expand Up @@ -48,6 +49,7 @@
op_select,
op_sigmoid,
op_sin,
op_skip,
op_slice_copy,
op_softmax,
op_split_with_sizes_copy,
Expand Down Expand Up @@ -77,6 +79,7 @@
op_dequantize,
op_div,
op_embedding,
op_exp,
op_expand_copy,
op_gelu,
op_getitem,
Expand Down Expand Up @@ -107,6 +110,7 @@
op_select,
op_sigmoid,
op_sin,
op_skip,
op_slice_copy,
op_softmax,
op_split_with_sizes_copy,
Expand Down
6 changes: 4 additions & 2 deletions backends/samsung/builders/node_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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())

Expand Down
9 changes: 8 additions & 1 deletion backends/samsung/builders/op_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,16 +27,22 @@ 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 = {}
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)

enn_graph.define_op(
node.name, "ELTSUM", [input_id_1, input_id_2], [output_id], params
)

return True
8 changes: 3 additions & 5 deletions backends/samsung/builders/op_avg_pool2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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:
Expand All @@ -68,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
8 changes: 7 additions & 1 deletion backends/samsung/builders/op_batch_norm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -51,6 +51,12 @@ 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
)

return True
4 changes: 3 additions & 1 deletion backends/samsung/builders/op_bmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
4 changes: 3 additions & 1 deletion backends/samsung/builders/op_cat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
10 changes: 9 additions & 1 deletion backends/samsung/builders/op_clamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
# 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
from executorch.backends.samsung.builders.node_visitor import (
NodeVisitor,
register_node_visitor,
)
from executorch.backends.samsung.builders.utils import get_tensor
from executorch.backends.samsung.serialization.enn_graph_schema import EnnGraph


Expand All @@ -26,9 +28,13 @@ 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)
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
Expand All @@ -45,3 +51,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
4 changes: 3 additions & 1 deletion backends/samsung/builders/op_constant_pad_nd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
22 changes: 20 additions & 2 deletions backends/samsung/builders/op_conv2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -52,9 +53,24 @@ 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."
)
return True
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)
Expand All @@ -72,7 +88,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)

Expand All @@ -87,3 +103,5 @@ def define_node(
enn_graph.define_op(
node.name, conv_type, all_input_tensors, [output_id], params
)

return True
4 changes: 3 additions & 1 deletion backends/samsung/builders/op_cos.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 3 additions & 1 deletion backends/samsung/builders/op_div.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
4 changes: 3 additions & 1 deletion backends/samsung/builders/op_embedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -40,3 +40,5 @@ def define_node(
enn_graph.define_op(
node.name, "GATHER", [weight_id, input_id], [output_id], params
)

return True
33 changes: 33 additions & 0 deletions backends/samsung/builders/op_exp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 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],
) -> 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
Loading
Loading