tico 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. tico/__init__.py +42 -0
  2. tico/config/__init__.py +4 -0
  3. tico/config/base.py +37 -0
  4. tico/config/factory.py +41 -0
  5. tico/config/v1.py +35 -0
  6. tico/experimental/__init__.py +1 -0
  7. tico/experimental/quantization/__init__.py +1 -0
  8. tico/experimental/quantization/algorithm/__init__.py +1 -0
  9. tico/experimental/quantization/algorithm/gptq/__init__.py +1 -0
  10. tico/experimental/quantization/algorithm/gptq/gptq.py +172 -0
  11. tico/experimental/quantization/algorithm/gptq/quant.py +153 -0
  12. tico/experimental/quantization/algorithm/gptq/quantizer.py +225 -0
  13. tico/experimental/quantization/algorithm/gptq/utils.py +65 -0
  14. tico/experimental/quantization/algorithm/pt2e/__init__.py +1 -0
  15. tico/experimental/quantization/algorithm/pt2e/annotation/__init__.py +1 -0
  16. tico/experimental/quantization/algorithm/pt2e/annotation/annotator.py +215 -0
  17. tico/experimental/quantization/algorithm/pt2e/annotation/config.py +26 -0
  18. tico/experimental/quantization/algorithm/pt2e/annotation/op/__init__.py +21 -0
  19. tico/experimental/quantization/algorithm/pt2e/annotation/op/adaptive_avg_pool2d.py +65 -0
  20. tico/experimental/quantization/algorithm/pt2e/annotation/op/add.py +57 -0
  21. tico/experimental/quantization/algorithm/pt2e/annotation/op/conv2d.py +92 -0
  22. tico/experimental/quantization/algorithm/pt2e/annotation/op/div.py +57 -0
  23. tico/experimental/quantization/algorithm/pt2e/annotation/op/linear.py +94 -0
  24. tico/experimental/quantization/algorithm/pt2e/annotation/op/mean.py +53 -0
  25. tico/experimental/quantization/algorithm/pt2e/annotation/op/mul.py +57 -0
  26. tico/experimental/quantization/algorithm/pt2e/annotation/op/relu6.py +53 -0
  27. tico/experimental/quantization/algorithm/pt2e/annotation/op/rsqrt.py +53 -0
  28. tico/experimental/quantization/algorithm/pt2e/annotation/op/sub.py +57 -0
  29. tico/experimental/quantization/algorithm/pt2e/annotation/spec.py +47 -0
  30. tico/experimental/quantization/algorithm/pt2e/annotation/utils.py +88 -0
  31. tico/experimental/quantization/algorithm/pt2e/quantizer.py +78 -0
  32. tico/experimental/quantization/algorithm/pt2e/transformation/__init__.py +1 -0
  33. tico/experimental/quantization/algorithm/pt2e/transformation/convert_scalars_to_attrs.py +58 -0
  34. tico/experimental/quantization/algorithm/pt2e/utils.py +138 -0
  35. tico/experimental/quantization/algorithm/smoothquant/__init__.py +1 -0
  36. tico/experimental/quantization/algorithm/smoothquant/observer.py +78 -0
  37. tico/experimental/quantization/algorithm/smoothquant/quantizer.py +81 -0
  38. tico/experimental/quantization/algorithm/smoothquant/smooth_quant.py +164 -0
  39. tico/experimental/quantization/config.py +68 -0
  40. tico/experimental/quantization/evaluation/__init__.py +1 -0
  41. tico/experimental/quantization/evaluation/backend.py +20 -0
  42. tico/experimental/quantization/evaluation/evaluate.py +223 -0
  43. tico/experimental/quantization/evaluation/executor/__init__.py +1 -0
  44. tico/experimental/quantization/evaluation/executor/backend_executor.py +54 -0
  45. tico/experimental/quantization/evaluation/executor/circle_executor.py +75 -0
  46. tico/experimental/quantization/evaluation/executor/triv24_executor.py +128 -0
  47. tico/experimental/quantization/evaluation/metric.py +109 -0
  48. tico/experimental/quantization/evaluation/utils.py +185 -0
  49. tico/experimental/quantization/passes/__init__.py +1 -0
  50. tico/experimental/quantization/passes/fold_quant_ops.py +154 -0
  51. tico/experimental/quantization/passes/insert_quantize_on_dtype_mismatch.py +345 -0
  52. tico/experimental/quantization/passes/propagate_qparam_backward.py +91 -0
  53. tico/experimental/quantization/passes/propagate_qparam_forward.py +141 -0
  54. tico/experimental/quantization/passes/quantize_bias.py +123 -0
  55. tico/experimental/quantization/passes/remove_weight_dequant_op.py +177 -0
  56. tico/experimental/quantization/public_interface.py +108 -0
  57. tico/experimental/quantization/quantizer.py +71 -0
  58. tico/interpreter/__init__.py +1 -0
  59. tico/interpreter/infer.py +116 -0
  60. tico/interpreter/interpreter.py +93 -0
  61. tico/passes/__init__.py +1 -0
  62. tico/passes/cast_aten_where_arg_type.py +191 -0
  63. tico/passes/cast_mixed_type_args.py +187 -0
  64. tico/passes/const_prop_pass.py +307 -0
  65. tico/passes/convert_conv1d_to_conv2d.py +160 -0
  66. tico/passes/convert_layout_op_to_reshape.py +85 -0
  67. tico/passes/convert_repeat_to_expand_copy.py +89 -0
  68. tico/passes/convert_to_relu6.py +181 -0
  69. tico/passes/decompose_addmm.py +124 -0
  70. tico/passes/decompose_batch_norm.py +192 -0
  71. tico/passes/decompose_fake_quantize.py +134 -0
  72. tico/passes/decompose_fake_quantize_tensor_qparams.py +294 -0
  73. tico/passes/decompose_group_norm.py +275 -0
  74. tico/passes/decompose_grouped_conv2d.py +209 -0
  75. tico/passes/decompose_slice_scatter.py +169 -0
  76. tico/passes/extract_dtype_kwargs.py +122 -0
  77. tico/passes/fill_meta_val.py +57 -0
  78. tico/passes/fuse_leading_unsqueeze_reshape.py +112 -0
  79. tico/passes/fuse_redundant_reshape_to_mean.py +102 -0
  80. tico/passes/legalize_causal_mask_value.py +108 -0
  81. tico/passes/legalize_predefined_layout_operators.py +386 -0
  82. tico/passes/lower_pow2_to_mul.py +75 -0
  83. tico/passes/lower_to_resize_nearest_neighbor.py +235 -0
  84. tico/passes/lower_to_slice.py +230 -0
  85. tico/passes/merge_consecutive_cat.py +80 -0
  86. tico/passes/ops.py +78 -0
  87. tico/passes/remove_nop.py +84 -0
  88. tico/passes/remove_redundant_assert_nodes.py +51 -0
  89. tico/passes/remove_redundant_expand.py +66 -0
  90. tico/passes/remove_redundant_permute.py +122 -0
  91. tico/passes/remove_redundant_reshape.py +436 -0
  92. tico/passes/remove_redundant_slice.py +62 -0
  93. tico/passes/remove_redundant_to_copy.py +86 -0
  94. tico/passes/restore_linear.py +115 -0
  95. tico/passes/segment_index_select.py +145 -0
  96. tico/pt2_to_circle.py +105 -0
  97. tico/serialize/__init__.py +1 -0
  98. tico/serialize/circle_graph.py +319 -0
  99. tico/serialize/circle_mapping.py +177 -0
  100. tico/serialize/circle_serializer.py +240 -0
  101. tico/serialize/operators/__init__.py +28 -0
  102. tico/serialize/operators/hashable_opcode.py +43 -0
  103. tico/serialize/operators/node_visitor.py +80 -0
  104. tico/serialize/operators/op_abs.py +53 -0
  105. tico/serialize/operators/op_add.py +69 -0
  106. tico/serialize/operators/op_alias_copy.py +64 -0
  107. tico/serialize/operators/op_any.py +150 -0
  108. tico/serialize/operators/op_arange_start_step.py +61 -0
  109. tico/serialize/operators/op_argmax.py +62 -0
  110. tico/serialize/operators/op_avg_pool2d.py +192 -0
  111. tico/serialize/operators/op_bmm.py +62 -0
  112. tico/serialize/operators/op_cat.py +66 -0
  113. tico/serialize/operators/op_clamp.py +126 -0
  114. tico/serialize/operators/op_clone.py +71 -0
  115. tico/serialize/operators/op_constant_pad_nd.py +72 -0
  116. tico/serialize/operators/op_conv2d.py +186 -0
  117. tico/serialize/operators/op_copy.py +164 -0
  118. tico/serialize/operators/op_cos.py +59 -0
  119. tico/serialize/operators/op_cumsum.py +95 -0
  120. tico/serialize/operators/op_depthwise_conv2d.py +199 -0
  121. tico/serialize/operators/op_dequantize_per_channel.py +82 -0
  122. tico/serialize/operators/op_dequantize_per_tensor.py +64 -0
  123. tico/serialize/operators/op_div.py +62 -0
  124. tico/serialize/operators/op_embedding.py +60 -0
  125. tico/serialize/operators/op_eq.py +64 -0
  126. tico/serialize/operators/op_exp.py +60 -0
  127. tico/serialize/operators/op_expand.py +91 -0
  128. tico/serialize/operators/op_full.py +48 -0
  129. tico/serialize/operators/op_full_like.py +55 -0
  130. tico/serialize/operators/op_ge.py +54 -0
  131. tico/serialize/operators/op_gelu.py +59 -0
  132. tico/serialize/operators/op_gt.py +54 -0
  133. tico/serialize/operators/op_index.py +82 -0
  134. tico/serialize/operators/op_index_select.py +64 -0
  135. tico/serialize/operators/op_instance_norm.py +91 -0
  136. tico/serialize/operators/op_leaky_relu.py +60 -0
  137. tico/serialize/operators/op_linear.py +70 -0
  138. tico/serialize/operators/op_log.py +53 -0
  139. tico/serialize/operators/op_log1p.py +86 -0
  140. tico/serialize/operators/op_logical_and.py +63 -0
  141. tico/serialize/operators/op_logical_not.py +62 -0
  142. tico/serialize/operators/op_lt.py +61 -0
  143. tico/serialize/operators/op_max_dim.py +70 -0
  144. tico/serialize/operators/op_max_pool2d_with_indices.py +155 -0
  145. tico/serialize/operators/op_maximum.py +53 -0
  146. tico/serialize/operators/op_mean.py +66 -0
  147. tico/serialize/operators/op_minimum.py +53 -0
  148. tico/serialize/operators/op_mm.py +177 -0
  149. tico/serialize/operators/op_mul.py +99 -0
  150. tico/serialize/operators/op_ne.py +54 -0
  151. tico/serialize/operators/op_neg.py +59 -0
  152. tico/serialize/operators/op_permute.py +65 -0
  153. tico/serialize/operators/op_pow.py +141 -0
  154. tico/serialize/operators/op_prelu.py +54 -0
  155. tico/serialize/operators/op_quantize_per_tensor.py +79 -0
  156. tico/serialize/operators/op_reciprocal.py +64 -0
  157. tico/serialize/operators/op_relu.py +53 -0
  158. tico/serialize/operators/op_relu6.py +52 -0
  159. tico/serialize/operators/op_repeat.py +100 -0
  160. tico/serialize/operators/op_reshape.py +73 -0
  161. tico/serialize/operators/op_resize_nearest_neighbor.py +70 -0
  162. tico/serialize/operators/op_rsqrt.py +53 -0
  163. tico/serialize/operators/op_scalar_tensor.py +51 -0
  164. tico/serialize/operators/op_select_copy.py +65 -0
  165. tico/serialize/operators/op_sigmoid.py +56 -0
  166. tico/serialize/operators/op_sin.py +53 -0
  167. tico/serialize/operators/op_slice.py +155 -0
  168. tico/serialize/operators/op_softmax.py +100 -0
  169. tico/serialize/operators/op_split_with_sizes.py +99 -0
  170. tico/serialize/operators/op_sqrt.py +55 -0
  171. tico/serialize/operators/op_squeeze.py +73 -0
  172. tico/serialize/operators/op_sub.py +71 -0
  173. tico/serialize/operators/op_sum.py +63 -0
  174. tico/serialize/operators/op_tanh.py +54 -0
  175. tico/serialize/operators/op_to_copy.py +105 -0
  176. tico/serialize/operators/op_unsqueeze.py +66 -0
  177. tico/serialize/operators/op_view.py +74 -0
  178. tico/serialize/operators/op_where.py +82 -0
  179. tico/serialize/operators/utils.py +94 -0
  180. tico/serialize/pack.py +35 -0
  181. tico/serialize/quant_param.py +42 -0
  182. tico/utils/__init__.py +1 -0
  183. tico/utils/convert.py +296 -0
  184. tico/utils/define.py +35 -0
  185. tico/utils/diff_graph.py +181 -0
  186. tico/utils/errors.py +35 -0
  187. tico/utils/graph.py +282 -0
  188. tico/utils/logging.py +45 -0
  189. tico/utils/model.py +37 -0
  190. tico/utils/mx/__init__.py +1 -0
  191. tico/utils/mx/elemwise_ops.py +267 -0
  192. tico/utils/mx/formats.py +125 -0
  193. tico/utils/mx/mx_ops.py +270 -0
  194. tico/utils/padding.py +47 -0
  195. tico/utils/passes.py +76 -0
  196. tico/utils/register_custom_op.py +609 -0
  197. tico/utils/serialize.py +42 -0
  198. tico/utils/trace_decorators.py +101 -0
  199. tico/utils/utils.py +406 -0
  200. tico/utils/validate_args_kwargs.py +1149 -0
  201. tico-0.1.0.dist-info/LICENSE +241 -0
  202. tico-0.1.0.dist-info/METADATA +354 -0
  203. tico-0.1.0.dist-info/RECORD +206 -0
  204. tico-0.1.0.dist-info/WHEEL +5 -0
  205. tico-0.1.0.dist-info/entry_points.txt +3 -0
  206. tico-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+ from torch.ao.quantization.quantizer import DerivedQuantizationSpec
21
+
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
23
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
24
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
25
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
26
+ QuantizationConfig,
27
+ )
28
+ from tico.utils.validate_args_kwargs import Conv2DArgs
29
+
30
+
31
+ @annot_spec.register_annotator(
32
+ [torch.ops.aten.conv2d.default, torch.ops.aten.conv2d.padding]
33
+ )
34
+ def _annotate_conv2d(
35
+ gm: torch.fx.GraphModule,
36
+ node: torch.fx.Node,
37
+ quantization_config: Optional[QuantizationConfig],
38
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
39
+ ):
40
+ for node in gm.graph.nodes:
41
+ if node.op != "call_function" or node.target not in [
42
+ torch.ops.aten.conv2d.default,
43
+ torch.ops.aten.conv2d.padding,
44
+ ]:
45
+ continue
46
+ if filter_fn and not filter_fn(node):
47
+ continue
48
+ if quant_utils.is_annotated(node):
49
+ continue
50
+
51
+ args = Conv2DArgs(*node.args, **node.kwargs) # type: ignore[arg-type]
52
+ input_ = args.input
53
+ weight = args.weight
54
+ bias = args.bias
55
+
56
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
57
+ weight_qspec = quant_utils.get_weight_qspec(quantization_config)
58
+ annot_utils.annotate_input_qspec_map(node, input_, input_act_qspec)
59
+ annot_utils.annotate_input_qspec_map(node, weight, weight_qspec)
60
+ nodes_to_mark_annotated = [input_, weight, node]
61
+ if bias:
62
+
63
+ def _derive_bias_qparams_from_act_and_weight_qparams(obs_or_fqs):
64
+ act_scale, _ = obs_or_fqs[0].calculate_qparams()
65
+ weight_scale, _ = obs_or_fqs[1].calculate_qparams()
66
+ bias_scale = act_scale * weight_scale
67
+ bias_zero_point = torch.zeros_like(bias_scale, dtype=torch.int32)
68
+ return bias_scale, bias_zero_point
69
+
70
+ bias_qspec = DerivedQuantizationSpec(
71
+ derived_from=[
72
+ (input_, node),
73
+ (weight, node),
74
+ ],
75
+ derive_qparams_fn=_derive_bias_qparams_from_act_and_weight_qparams,
76
+ dtype=torch.int32,
77
+ quant_min=-(2**31),
78
+ quant_max=2**31 - 1,
79
+ qscheme=weight_qspec.qscheme,
80
+ ch_axis=0 if weight_qspec.qscheme == torch.per_channel_affine else None,
81
+ )
82
+ annot_utils.annotate_input_qspec_map(
83
+ node,
84
+ bias,
85
+ bias_qspec,
86
+ )
87
+ nodes_to_mark_annotated.append(bias)
88
+
89
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
90
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
91
+
92
+ annot_utils.mark_nodes_as_annotated(nodes_to_mark_annotated)
@@ -0,0 +1,57 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+
21
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
23
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
24
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
25
+ QuantizationConfig,
26
+ )
27
+ from tico.utils.validate_args_kwargs import DivTensorArgs
28
+
29
+
30
+ @annot_spec.register_annotator([torch.ops.aten.div.Tensor])
31
+ def _annotate_div(
32
+ gm: torch.fx.GraphModule,
33
+ node: torch.fx.Node,
34
+ quantization_config: Optional[QuantizationConfig],
35
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
36
+ ):
37
+ if node.op != "call_function" or node.target != torch.ops.aten.div.Tensor:
38
+ return
39
+ if filter_fn and not filter_fn(node):
40
+ return
41
+ if quant_utils.is_annotated(node):
42
+ return
43
+
44
+ args = DivTensorArgs(*node.args) # type: ignore[arg-type]
45
+ input = args.input
46
+ other = args.other
47
+
48
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
49
+ if isinstance(input, torch.fx.Node):
50
+ annot_utils.annotate_input_qspec_map(node, input, input_act_qspec)
51
+ if isinstance(other, torch.fx.Node):
52
+ annot_utils.annotate_input_qspec_map(node, other, input_act_qspec)
53
+
54
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
55
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
56
+
57
+ annot_utils.mark_nodes_as_annotated(node)
@@ -0,0 +1,94 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, List, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+ from torch.ao.quantization.quantizer import DerivedQuantizationSpec
21
+
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
23
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
24
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
25
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
26
+ QuantizationConfig,
27
+ )
28
+ from tico.utils.validate_args_kwargs import LinearArgs
29
+
30
+
31
+ @annot_spec.register_annotator([torch.ops.aten.linear.default])
32
+ def _annotate_linear(
33
+ gm: torch.fx.GraphModule,
34
+ node: torch.fx.Node,
35
+ quantization_config: Optional[QuantizationConfig],
36
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
37
+ ):
38
+ if node.op != "call_function" or node.target != torch.ops.aten.linear.default:
39
+ return
40
+ if filter_fn and not filter_fn(node):
41
+ return
42
+ if quant_utils.is_annotated(node):
43
+ return
44
+
45
+ args = LinearArgs(*node.args, **node.kwargs) # type: ignore[arg-type]
46
+ input_ = args.input
47
+ weight = args.weight
48
+ bias = args.bias
49
+
50
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
51
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
52
+ weight_qspec = quant_utils.get_weight_qspec(quantization_config)
53
+ bias_qspec = quant_utils.get_bias_qspec(quantization_config)
54
+
55
+ annot_utils.annotate_input_qspec_map(
56
+ node,
57
+ input_,
58
+ input_act_qspec,
59
+ )
60
+ annot_utils.annotate_input_qspec_map(
61
+ node,
62
+ weight,
63
+ weight_qspec,
64
+ )
65
+ nodes_to_mark_annotated = [node, weight]
66
+ if bias:
67
+
68
+ def _derive_bias_qparams_from_act_and_weight_qparams(obs_or_fqs):
69
+ act_scale, _ = obs_or_fqs[0].calculate_qparams()
70
+ weight_scale, _ = obs_or_fqs[1].calculate_qparams()
71
+ bias_scale = act_scale * weight_scale
72
+ bias_zero_point = torch.zeros_like(bias_scale, dtype=torch.int32)
73
+ return bias_scale, bias_zero_point
74
+
75
+ bias_qspec = DerivedQuantizationSpec(
76
+ derived_from=[
77
+ (input_, node),
78
+ (weight, node),
79
+ ],
80
+ derive_qparams_fn=_derive_bias_qparams_from_act_and_weight_qparams,
81
+ dtype=torch.int32,
82
+ quant_min=-(2**31),
83
+ quant_max=2**31 - 1,
84
+ qscheme=weight_qspec.qscheme,
85
+ ch_axis=0 if weight_qspec.qscheme == torch.per_channel_affine else None,
86
+ )
87
+ annot_utils.annotate_input_qspec_map(
88
+ node,
89
+ bias,
90
+ bias_qspec,
91
+ )
92
+ nodes_to_mark_annotated.append(bias)
93
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
94
+ annot_utils.mark_nodes_as_annotated(nodes_to_mark_annotated)
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+
21
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
23
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
24
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
25
+ QuantizationConfig,
26
+ )
27
+ from tico.utils.validate_args_kwargs import MeanDimArgs
28
+
29
+
30
+ @annot_spec.register_annotator([torch.ops.aten.mean.dim])
31
+ def _annotate_mean(
32
+ gm: torch.fx.GraphModule,
33
+ node: torch.fx.Node,
34
+ quantization_config: Optional[QuantizationConfig],
35
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
36
+ ):
37
+ if node.op != "call_function" or node.target != torch.ops.aten.mean.dim:
38
+ return
39
+ if filter_fn and not filter_fn(node):
40
+ return
41
+ if quant_utils.is_annotated(node):
42
+ return
43
+
44
+ args = MeanDimArgs(*node.args, **node.kwargs) # type: ignore[arg-type]
45
+ input = args.input
46
+
47
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
48
+ annot_utils.annotate_input_qspec_map(node, input, input_act_qspec)
49
+
50
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
51
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
52
+
53
+ annot_utils.mark_nodes_as_annotated(node)
@@ -0,0 +1,57 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+
21
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
23
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
24
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
25
+ QuantizationConfig,
26
+ )
27
+ from tico.utils.validate_args_kwargs import MulTensorArgs
28
+
29
+
30
+ @annot_spec.register_annotator([torch.ops.aten.mul.Tensor])
31
+ def _annotate_mul(
32
+ gm: torch.fx.GraphModule,
33
+ node: torch.fx.Node,
34
+ quantization_config: Optional[QuantizationConfig],
35
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
36
+ ):
37
+ if node.op != "call_function" or node.target != torch.ops.aten.mul.Tensor:
38
+ return
39
+ if filter_fn and not filter_fn(node):
40
+ return
41
+ if quant_utils.is_annotated(node):
42
+ return
43
+
44
+ args = MulTensorArgs(*node.args, **node.kwargs) # type: ignore[arg-type]
45
+ input = args.input
46
+ other = args.other
47
+
48
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
49
+ if isinstance(input, torch.fx.Node):
50
+ annot_utils.annotate_input_qspec_map(node, input, input_act_qspec)
51
+ if isinstance(other, torch.fx.Node):
52
+ annot_utils.annotate_input_qspec_map(node, other, input_act_qspec)
53
+
54
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
55
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
56
+
57
+ annot_utils.mark_nodes_as_annotated(node)
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+
21
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
23
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
24
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
25
+ QuantizationConfig,
26
+ )
27
+ from tico.utils.validate_args_kwargs import Relu6Args
28
+
29
+
30
+ @annot_spec.register_annotator([torch.ops.aten.relu6.default])
31
+ def _annotate_relu6(
32
+ gm: torch.fx.GraphModule,
33
+ node: torch.fx.Node,
34
+ quantization_config: Optional[QuantizationConfig],
35
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
36
+ ):
37
+ if node.op != "call_function" or node.target != torch.ops.aten.relu6.default:
38
+ return
39
+ if filter_fn and not filter_fn(node):
40
+ return
41
+ if quant_utils.is_annotated(node):
42
+ return
43
+
44
+ args = Relu6Args(*node.args, **node.kwargs) # type: ignore
45
+ input = args.input
46
+
47
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
48
+ annot_utils.annotate_input_qspec_map(node, input, input_act_qspec)
49
+
50
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
51
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
52
+
53
+ annot_utils.mark_nodes_as_annotated(node)
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+
21
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
23
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
24
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
25
+ QuantizationConfig,
26
+ )
27
+ from tico.utils.validate_args_kwargs import RsqrtArgs
28
+
29
+
30
+ @annot_spec.register_annotator([torch.ops.aten.rsqrt.default])
31
+ def _annotate_rsqrt(
32
+ gm: torch.fx.GraphModule,
33
+ node: torch.fx.Node,
34
+ quantization_config: Optional[QuantizationConfig],
35
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
36
+ ):
37
+ if node.op != "call_function" or node.target != torch.ops.aten.rsqrt.default:
38
+ return
39
+ if filter_fn and not filter_fn(node):
40
+ return
41
+ if quant_utils.is_annotated(node):
42
+ return
43
+
44
+ args = RsqrtArgs(*node.args, **node.kwargs) # type: ignore[arg-type]
45
+ input = args.input
46
+
47
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
48
+ annot_utils.annotate_input_qspec_map(node, input, input_act_qspec)
49
+
50
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
51
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
52
+
53
+ annot_utils.mark_nodes_as_annotated(node)
@@ -0,0 +1,57 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+
21
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
22
+ import tico.experimental.quantization.algorithm.pt2e.annotation.utils as annot_utils
23
+ import tico.experimental.quantization.algorithm.pt2e.utils as quant_utils
24
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
25
+ QuantizationConfig,
26
+ )
27
+ from tico.utils.validate_args_kwargs import SubTensorArgs
28
+
29
+
30
+ @annot_spec.register_annotator([torch.ops.aten.sub.Tensor])
31
+ def _annotate_sub(
32
+ gm: torch.fx.GraphModule,
33
+ node: torch.fx.Node,
34
+ quantization_config: Optional[QuantizationConfig],
35
+ filter_fn: Optional[Callable[[torch.fx.Node], bool]] = None,
36
+ ):
37
+ if node.op != "call_function" or node.target != torch.ops.aten.sub.Tensor:
38
+ return
39
+ if filter_fn and not filter_fn(node):
40
+ return
41
+ if quant_utils.is_annotated(node):
42
+ return
43
+
44
+ args = SubTensorArgs(*node.args) # type: ignore[arg-type]
45
+ input = args.input
46
+ other = args.other
47
+
48
+ input_act_qspec = quant_utils.get_input_act_qspec(quantization_config)
49
+ if isinstance(input, torch.fx.Node):
50
+ annot_utils.annotate_input_qspec_map(node, input, input_act_qspec)
51
+ if isinstance(other, torch.fx.Node):
52
+ annot_utils.annotate_input_qspec_map(node, other, input_act_qspec)
53
+
54
+ output_act_qspec = quant_utils.get_output_act_qspec(quantization_config)
55
+ annot_utils.annotate_output_qspec(node, output_act_qspec)
56
+
57
+ annot_utils.mark_nodes_as_annotated(node)
@@ -0,0 +1,47 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Callable, Dict, List, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+
21
+ from tico.experimental.quantization.algorithm.pt2e.annotation.config import (
22
+ QuantizationConfig,
23
+ )
24
+
25
+ AnnotatorType = Callable[
26
+ [
27
+ torch.fx.GraphModule,
28
+ torch.fx.Node,
29
+ Optional[QuantizationConfig],
30
+ Optional[Callable[[torch.fx.Node], bool]],
31
+ ],
32
+ None,
33
+ ]
34
+ OP_TO_ANNOTATOR: Dict[torch._ops.OpOverload, AnnotatorType] = {}
35
+ OP_TO_SHARE_QUANT_SPEC: List[Callable] = [
36
+ torch.ops.aten.view_copy.default,
37
+ torch.ops.aten.view.default,
38
+ ]
39
+
40
+
41
+ def register_annotator(target: List[torch._ops.OpOverload]):
42
+ def decorator(annotator: AnnotatorType):
43
+ for t in target:
44
+ OP_TO_ANNOTATOR[t] = annotator
45
+ return annotator
46
+
47
+ return decorator
@@ -0,0 +1,88 @@
1
+ # Copyright (c) 2025 Samsung Electronics Co., Ltd. All Rights Reserved
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import List, Optional, TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import torch.fx
19
+ import torch
20
+ from torch.ao.quantization.quantizer import (
21
+ QuantizationAnnotation,
22
+ SharedQuantizationSpec,
23
+ )
24
+
25
+ import tico.experimental.quantization.algorithm.pt2e.annotation.spec as annot_spec
26
+
27
+
28
+ def annotate_input_qspec_map(node: torch.fx.Node, input_node: torch.fx.Node, qspec):
29
+ quantization_annotation: QuantizationAnnotation = node.meta.get(
30
+ "quantization_annotation", QuantizationAnnotation()
31
+ )
32
+ quantization_annotation.input_qspec_map[input_node] = qspec
33
+ node.meta["quantization_annotation"] = quantization_annotation
34
+
35
+
36
+ def annotate_output_qspec(node: torch.fx.Node, qspec):
37
+ quantization_annotation: QuantizationAnnotation = node.meta.get(
38
+ "quantization_annotation", QuantizationAnnotation()
39
+ )
40
+ quantization_annotation.output_qspec = qspec
41
+ node.meta["quantization_annotation"] = quantization_annotation
42
+
43
+
44
+ def mark_nodes_as_annotated(nodes: List[torch.fx.Node] | torch.fx.Node):
45
+ if isinstance(nodes, torch.fx.Node):
46
+ nodes = [nodes]
47
+ for node in nodes:
48
+ if node is not None:
49
+ if "quantization_annotation" not in node.meta:
50
+ node.meta["quantization_annotation"] = QuantizationAnnotation()
51
+ node.meta["quantization_annotation"]._annotated = True
52
+
53
+
54
+ def propagate_annotation_forward(model: torch.fx.GraphModule) -> None:
55
+ for n in model.graph.nodes:
56
+ if n.op != "call_function" or n.target not in annot_spec.OP_TO_SHARE_QUANT_SPEC:
57
+ continue
58
+
59
+ prev_node = n.args[0]
60
+ if not isinstance(prev_node, torch.fx.Node):
61
+ continue
62
+
63
+ quantization_annotation: Optional[QuantizationAnnotation] = prev_node.meta.get(
64
+ "quantization_annotation", None
65
+ )
66
+ if not quantization_annotation:
67
+ continue
68
+
69
+ output_qspec = quantization_annotation.output_qspec
70
+ if not output_qspec:
71
+ continue
72
+
73
+ # Make sure current node is not annotated
74
+ if (
75
+ "quantization_annotation" in n.meta
76
+ and n.meta["quantization_annotation"]._annotated
77
+ ):
78
+ continue
79
+
80
+ shared_qspec = SharedQuantizationSpec(prev_node)
81
+ # Propagate the previous output_qspec to the current node
82
+ n.meta["quantization_annotation"] = QuantizationAnnotation(
83
+ input_qspec_map={
84
+ prev_node: shared_qspec,
85
+ },
86
+ output_qspec=shared_qspec,
87
+ _annotated=True,
88
+ )