tico 0.1.0.dev250819__py3-none-any.whl → 0.1.0.dev250821__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.
tico/__init__.py CHANGED
@@ -29,7 +29,7 @@ __all__ = [
29
29
  ]
30
30
 
31
31
  # THIS LINE IS AUTOMATICALLY GENERATED BY setup.py
32
- __version__ = "0.1.0.dev250819"
32
+ __version__ = "0.1.0.dev250821"
33
33
 
34
34
  MINIMUM_SUPPORTED_VERSION = "2.5.0"
35
35
  SECURE_TORCH_VERSION = "2.6.0"
@@ -0,0 +1,5 @@
1
+ from tico.experimental.quantization.ptq.wrappers.nn.quant_linear import QuantLinear
2
+
3
+ __all__ = [
4
+ "QuantLinear",
5
+ ]
@@ -0,0 +1,66 @@
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 Optional
16
+
17
+ import torch.nn as nn
18
+ import torch.nn.functional as F
19
+
20
+ from tico.experimental.quantization.ptq.mode import Mode
21
+ from tico.experimental.quantization.ptq.qscheme import QScheme
22
+ from tico.experimental.quantization.ptq.quant_config import QuantConfig
23
+ from tico.experimental.quantization.ptq.wrappers.quant_module_base import (
24
+ QuantModuleBase,
25
+ )
26
+ from tico.experimental.quantization.ptq.wrappers.registry import register
27
+
28
+
29
+ @register(nn.Linear)
30
+ class QuantLinear(QuantModuleBase):
31
+ """Per-channel weight fake-quant, eager-output activation fake-quant."""
32
+
33
+ def __init__(
34
+ self,
35
+ fp: nn.Linear,
36
+ *,
37
+ qcfg: Optional[QuantConfig] = None,
38
+ fp_name: Optional[str] = None
39
+ ):
40
+ super().__init__(qcfg, fp_name=fp_name)
41
+ self.weight_obs = self._make_obs(
42
+ "weight", qscheme=QScheme.PER_CHANNEL_ASYMM, channel_axis=0
43
+ )
44
+ self.act_in_obs = self._make_obs("act_in")
45
+ self.act_out_obs = self._make_obs("act_out")
46
+ self.module = fp
47
+
48
+ def enable_calibration(self) -> None:
49
+ super().enable_calibration()
50
+ # immediately capture the fixed weight range
51
+ self.weight_obs.collect(self.module.weight)
52
+
53
+ def forward(self, x):
54
+ x_q = self._fq(x, self.act_in_obs)
55
+
56
+ w = self.module.weight
57
+ if self._mode is Mode.QUANT:
58
+ w = self.weight_obs.fake_quant(w)
59
+ b = self.module.bias
60
+
61
+ out = F.linear(x_q, w, b)
62
+
63
+ return self._fq(out, self.act_out_obs)
64
+
65
+ def _all_observers(self):
66
+ return (self.weight_obs, self.act_in_obs, self.act_out_obs)
@@ -0,0 +1,54 @@
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 Optional
16
+
17
+ import torch
18
+
19
+ from tico.experimental.quantization.ptq.quant_config import QuantConfig
20
+ from tico.experimental.quantization.ptq.wrappers.quant_module_base import (
21
+ QuantModuleBase,
22
+ )
23
+ from tico.experimental.quantization.ptq.wrappers.registry import lookup
24
+
25
+
26
+ class PTQWrapper(QuantModuleBase):
27
+ """
28
+ Adapter that turns a fp module into its quantized counterpart.
29
+
30
+ It is itself a QuantModuleBase so composite wrappers can treat
31
+ it exactly like any other quant module.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ module: torch.nn.Module,
37
+ qcfg: Optional[QuantConfig] = None,
38
+ *,
39
+ fp_name: Optional[str] = None,
40
+ ):
41
+ super().__init__(qcfg)
42
+ wrapped_cls = lookup(type(module))
43
+ if wrapped_cls is None:
44
+ raise NotImplementedError(f"No quant wrapper for {type(module).__name__}")
45
+ self.wrapped: QuantModuleBase = wrapped_cls(module, qcfg=qcfg, fp_name=fp_name) # type: ignore[arg-type, misc]
46
+
47
+ def forward(self, *args, **kwargs):
48
+ return self.wrapped(*args, **kwargs)
49
+
50
+ def _all_observers(self):
51
+ yield from self.wrapped._all_observers()
52
+
53
+ def extra_repr(self) -> str:
54
+ return self.wrapped.extra_repr()
@@ -0,0 +1,113 @@
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
16
+
17
+ import torch
18
+ import torch.nn as nn
19
+
20
+ from tico.experimental.quantization.ptq.quant_config import QuantConfig
21
+ from tico.experimental.quantization.ptq.wrappers.quant_module_base import (
22
+ QuantModuleBase,
23
+ )
24
+ from tico.experimental.quantization.ptq.wrappers.registry import register
25
+
26
+
27
+ class QuantElementwise(QuantModuleBase):
28
+ """
29
+ Generic wrapper for any 1-to-1 element-wise op `y = f(x)`.
30
+
31
+ Sub-classes only need to implement:
32
+ • `FUNC`: a Callable that maps tensor→tensor
33
+ """
34
+
35
+ # subclass must set this
36
+ FUNC: Callable[[torch.Tensor], torch.Tensor] | None = None
37
+
38
+ def __init_subclass__(cls, **kwargs):
39
+ super().__init_subclass__(**kwargs)
40
+ if cls is QuantElementwise:
41
+ return
42
+ if cls.FUNC is None:
43
+ raise NotImplementedError(
44
+ f"{cls.__name__} must define a staticmethod `FUNC(tensor) -> tensor`"
45
+ )
46
+
47
+ def __init__(
48
+ self,
49
+ fp_module: nn.Module,
50
+ *,
51
+ qcfg: Optional[QuantConfig] = None,
52
+ fp_name: Optional[str] = None,
53
+ ):
54
+ super().__init__(qcfg, fp_name=fp_name)
55
+ self.module = fp_module
56
+ self.act_in_obs = self._make_obs("act_in")
57
+ self.act_out_obs = self._make_obs("act_out")
58
+
59
+ # ------------------------------------------------------------
60
+ def forward(self, x):
61
+ x_q = self._fq(x, self.act_in_obs)
62
+ assert self.FUNC is not None
63
+ y = self.FUNC(x_q) # element-wise op
64
+ y_q = self._fq(y, self.act_out_obs)
65
+ return y_q
66
+
67
+ # ------------------------------------------------------------
68
+ def _all_observers(self):
69
+ return (self.act_in_obs, self.act_out_obs)
70
+
71
+
72
+ """
73
+ Why `FUNC` is a `staticmethod`
74
+
75
+ - Prevents automatic binding: calling `self.FUNC(x)` will not inject `self`,
76
+ so the callable keeps the expected signature `Tensor -> Tensor`
77
+ (e.g., `torch.sigmoid(x)`), avoiding TypeErrors.
78
+
79
+ - Expresses purity and statelessness: `FUNC` is a pure, element-wise transform
80
+ that must not read or mutate module state (params, buffers, config).
81
+
82
+ - Tracing/export friendly (FX / TorchScript): the call is captured as
83
+ `call_function(torch.*)` instead of a bound `call_method`, which makes graph
84
+ rewrites/pattern-matching and backends' substitutions more reliable.
85
+
86
+ - Avoids submodule pollution: we keep a functional op (`torch.relu`) rather
87
+ than an `nn.Module` instance that would appear in the module tree.
88
+
89
+ - Small perf/alloc win: no bound-method objects are created on each call.
90
+ """
91
+
92
+ # Sigmoid
93
+ @register(nn.Sigmoid)
94
+ class QuantSigmoid(QuantElementwise):
95
+ FUNC = staticmethod(torch.sigmoid)
96
+
97
+
98
+ # Tanh
99
+ @register(nn.Tanh)
100
+ class QuantTanh(QuantElementwise):
101
+ FUNC = staticmethod(torch.tanh)
102
+
103
+
104
+ # ReLU
105
+ @register(nn.ReLU)
106
+ class QuantReLU(QuantElementwise):
107
+ FUNC = staticmethod(torch.relu)
108
+
109
+
110
+ # GELU (approximate)
111
+ @register(nn.GELU)
112
+ class QuantGELU(QuantElementwise):
113
+ FUNC = staticmethod(torch.nn.functional.gelu)
@@ -0,0 +1,112 @@
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
+ import importlib
16
+ from typing import Callable, Dict, Type
17
+
18
+ import torch.nn as nn
19
+
20
+ from tico.experimental.quantization.ptq.wrappers.quant_module_base import (
21
+ QuantModuleBase,
22
+ )
23
+
24
+ _WRAPPERS: Dict[Type[nn.Module], Type[QuantModuleBase]] = {}
25
+ _IMPORT_ONCE = False
26
+ _CORE_MODULES = (
27
+ "tico.experimental.quantization.ptq.wrappers.nn.quant_linear",
28
+ # add future core wrappers here
29
+ )
30
+
31
+
32
+ def _lazy_init():
33
+ """
34
+ Deferred one-shot import of "core wrapper modules".
35
+
36
+ Why not import everything when the program first starts?
37
+ --------------------------------------------------
38
+ * **Avoid circular-import hell**
39
+ Core wrappers often import `PTQWrapper`, which in turn calls
40
+ `registry.lookup()`. Importing those files eagerly here would create a
41
+ cycle (`registry → wrapper → registry`). Delaying the import until the
42
+ *first* `lookup()` call lets Python finish constructing the registry
43
+ module before any wrapper files are touched.
44
+
45
+ * **Cold-start speed**
46
+ Most user code never wraps layers explicitly; they only hit
47
+ `PTQWrapper` if they are doing quantization. Deferring half-a-dozen
48
+ heavyweight `import torch …` files until they are really needed
49
+ reduces library start-up latency in the common path.
50
+
51
+ * **Optional dependencies**
52
+ Core wrappers listed in `_CORE_MODULES` are chosen to be dependency-free
53
+ (pure PyTorch). Anything that needs `transformers`, `torchvision`,
54
+ etc. uses the `@try_register()` decorator inside its own module. Those
55
+ optional modules are *not* imported here, so users without the extra
56
+ packages still get a clean import.
57
+
58
+ Implementation notes
59
+ --------------------
60
+ * `_IMPORT_ONCE` guard ensures we execute the import loop only once,
61
+ even if `lookup()` is called from multiple threads.
62
+ * Each path in `_CORE_MODULES` is a "fully-qualified module string"
63
+ (e.g. "ptq.wrappers.linear_quant"). Importing the module runs all
64
+ its `@register(nn.Layer)` decorators, populating `_WRAPPERS`.
65
+ * After the first call the function becomes a cheap constant-time no-op.
66
+ """
67
+ global _IMPORT_ONCE
68
+ if _IMPORT_ONCE:
69
+ return
70
+ for mod in _CORE_MODULES:
71
+ __import__(mod) # triggers decorators
72
+ _IMPORT_ONCE = True
73
+
74
+
75
+ # ───────────────────────────── decorator for always-present classes
76
+ def register(
77
+ fp_cls: Type[nn.Module],
78
+ ) -> Callable[[Type[QuantModuleBase]], Type[QuantModuleBase]]:
79
+ def _decorator(quant_cls: Type[QuantModuleBase]):
80
+ _WRAPPERS[fp_cls] = quant_cls
81
+ return quant_cls
82
+
83
+ return _decorator
84
+
85
+
86
+ # ───────────────────────────── conditional decorator
87
+ def try_register(path: str) -> Callable[[Type[QuantModuleBase]], Type[QuantModuleBase]]:
88
+ """
89
+ @try_register("transformers.models.llama.modeling_llama.LlamaMLP")
90
+
91
+ • If import succeeds → behave like `@register`
92
+ • If module/class not found → become a NO-OP
93
+ """
94
+
95
+ def _decorator(quant_cls: Type[QuantModuleBase]):
96
+ module_name, _, cls_name = path.rpartition(".")
97
+ try:
98
+ mod = importlib.import_module(module_name)
99
+ fp_cls = getattr(mod, cls_name)
100
+ _WRAPPERS[fp_cls] = quant_cls
101
+ except (ModuleNotFoundError, AttributeError):
102
+ # transformers not installed or class renamed – silently skip
103
+ pass
104
+ return quant_cls
105
+
106
+ return _decorator
107
+
108
+
109
+ # ───────────────────────────── lookup
110
+ def lookup(fp_cls: Type[nn.Module]) -> Type[QuantModuleBase] | None:
111
+ _lazy_init()
112
+ return _WRAPPERS.get(fp_cls)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tico
3
- Version: 0.1.0.dev250819
3
+ Version: 0.1.0.dev250821
4
4
  Summary: Convert exported Torch module to circle
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -1,4 +1,4 @@
1
- tico/__init__.py,sha256=lsEhU5spgB7ZLxS5ZhEhaDXDrDhT-14eoev-lcvlIx0,1883
1
+ tico/__init__.py,sha256=yEGf_7r1bSZi_LwntDyrVf0WUNvouR4X_fcua51LRUI,1883
2
2
  tico/pt2_to_circle.py,sha256=gu3MD4Iqc0zMZcCZ2IT8oGbyj21CTSbT3Rgd9s2B_9A,2767
3
3
  tico/config/__init__.py,sha256=xZzCXjZ84qE-CsBi-dfaL05bqpQ3stKKfTXhnrJRyVs,142
4
4
  tico/config/base.py,sha256=q5xMqGxTUZs4mFqt5c7i_y9U00fYgdMGl9nUqIVMlCo,1248
@@ -71,7 +71,12 @@ tico/experimental/quantization/ptq/observers/mx.py,sha256=aP4qmBgeiRIYZJksShN5gs
71
71
  tico/experimental/quantization/ptq/utils/__init__.py,sha256=PL9IZgiWoMtsXVljeOy7KymmLVP238SXEFRLXYK72WQ,126
72
72
  tico/experimental/quantization/ptq/utils/reduce_utils.py,sha256=3kWawLB91EcvvHlCrNqqfZF7tpgr22htBSA049mKw_4,973
73
73
  tico/experimental/quantization/ptq/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
+ tico/experimental/quantization/ptq/wrappers/ptq_wrapper.py,sha256=KRw_VvFJYvd2OBj4K1sYEXxUwZk9QghMw3NsgjKIAGk,1857
75
+ tico/experimental/quantization/ptq/wrappers/quant_elementwise.py,sha256=LhEoobfvto6zKrBOKL4gmxfFFc31jHzyQV_zfps-iQM,3604
74
76
  tico/experimental/quantization/ptq/wrappers/quant_module_base.py,sha256=6RK4bn9G1pzFmkIdBdFf7liBOpb-b7rpthgD83AgkbQ,5256
77
+ tico/experimental/quantization/ptq/wrappers/registry.py,sha256=exXl2wNNzVgC2P9gMjpF_-PqIBgYERGruzh0u1Pril0,4367
78
+ tico/experimental/quantization/ptq/wrappers/nn/__init__.py,sha256=q4A9BiGlsa8ZdGV3y0SDiSkzkdVugsK2iz2daiJqBCY,118
79
+ tico/experimental/quantization/ptq/wrappers/nn/quant_linear.py,sha256=xW-VEPB7RJoslS3xLVCdhIuMjppknvpkZleRGK4JFVQ,2240
75
80
  tico/interpreter/__init__.py,sha256=IO6FP_xYbGy0dW0HL26GXD3ouxARaxCK7bz9dn4blPQ,26
76
81
  tico/interpreter/infer.py,sha256=1ZFe3DVMR2mlwBosoedqoL0-CGN_01CKLgMgxuw62KA,4861
77
82
  tico/interpreter/interpreter.py,sha256=tGbluCbrehTCqBu8mtGDNzby_ieJ2ry8_RH_eC0CQxk,3828
@@ -226,9 +231,9 @@ tico/utils/mx/__init__.py,sha256=IO6FP_xYbGy0dW0HL26GXD3ouxARaxCK7bz9dn4blPQ,26
226
231
  tico/utils/mx/elemwise_ops.py,sha256=V6glyAHsVR1joqpsgnNytatCD_ew92xNWZ19UFDoMTA,10281
227
232
  tico/utils/mx/formats.py,sha256=uzNWyu-1onUlwQfX5cZ6fZSUfHMRqorper7_T1k3jfk,3404
228
233
  tico/utils/mx/mx_ops.py,sha256=RcfUTYVi-wilGB2sC35OeARdwDqnixv7dG5iyZ-fQT8,8555
229
- tico-0.1.0.dev250819.dist-info/LICENSE,sha256=kp4JLII7bzRhPb0CPD5XTDZMh22BQ7h3k3B7t8TiSbw,12644
230
- tico-0.1.0.dev250819.dist-info/METADATA,sha256=x4HeKSdCqixV9Xx-eGLbYMAWPvTAGhr0HrMtq0V5lWA,8450
231
- tico-0.1.0.dev250819.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
232
- tico-0.1.0.dev250819.dist-info/entry_points.txt,sha256=kBKYSS_IYrSXmUYevmmepqIVPScq5vF8ulQRu3I_Zf0,59
233
- tico-0.1.0.dev250819.dist-info/top_level.txt,sha256=oqs7UPoNSKZEwqsX8B-KAWdQwfAa7i60pbxW_Jk7P3w,5
234
- tico-0.1.0.dev250819.dist-info/RECORD,,
234
+ tico-0.1.0.dev250821.dist-info/LICENSE,sha256=kp4JLII7bzRhPb0CPD5XTDZMh22BQ7h3k3B7t8TiSbw,12644
235
+ tico-0.1.0.dev250821.dist-info/METADATA,sha256=h3a04PlCzUhqD8MvbgSQHopBPU9IcpNEFx7GthfXVM0,8450
236
+ tico-0.1.0.dev250821.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
237
+ tico-0.1.0.dev250821.dist-info/entry_points.txt,sha256=kBKYSS_IYrSXmUYevmmepqIVPScq5vF8ulQRu3I_Zf0,59
238
+ tico-0.1.0.dev250821.dist-info/top_level.txt,sha256=oqs7UPoNSKZEwqsX8B-KAWdQwfAa7i60pbxW_Jk7P3w,5
239
+ tico-0.1.0.dev250821.dist-info/RECORD,,