tico 0.1.0.dev250813__py3-none-any.whl → 0.1.0.dev250814__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 +1 -1
- tico/experimental/quantization/ptq/observers/__init__.py +4 -0
- tico/experimental/quantization/ptq/observers/ema.py +62 -0
- tico/experimental/quantization/ptq/observers/identity.py +74 -0
- tico/utils/utils.py +50 -53
- {tico-0.1.0.dev250813.dist-info → tico-0.1.0.dev250814.dist-info}/METADATA +1 -1
- {tico-0.1.0.dev250813.dist-info → tico-0.1.0.dev250814.dist-info}/RECORD +11 -9
- {tico-0.1.0.dev250813.dist-info → tico-0.1.0.dev250814.dist-info}/LICENSE +0 -0
- {tico-0.1.0.dev250813.dist-info → tico-0.1.0.dev250814.dist-info}/WHEEL +0 -0
- {tico-0.1.0.dev250813.dist-info → tico-0.1.0.dev250814.dist-info}/entry_points.txt +0 -0
- {tico-0.1.0.dev250813.dist-info → tico-0.1.0.dev250814.dist-info}/top_level.txt +0 -0
tico/__init__.py
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
from tico.experimental.quantization.ptq.observers.affine_base import AffineObserverBase
|
2
2
|
from tico.experimental.quantization.ptq.observers.base import ObserverBase
|
3
|
+
from tico.experimental.quantization.ptq.observers.ema import EMAObserver
|
4
|
+
from tico.experimental.quantization.ptq.observers.identity import IdentityObserver
|
3
5
|
from tico.experimental.quantization.ptq.observers.minmax import MinMaxObserver
|
4
6
|
|
5
7
|
__all__ = [
|
6
8
|
"AffineObserverBase",
|
7
9
|
"ObserverBase",
|
10
|
+
"EMAObserver",
|
11
|
+
"IdentityObserver",
|
8
12
|
"MinMaxObserver",
|
9
13
|
]
|
@@ -0,0 +1,62 @@
|
|
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 torch
|
16
|
+
|
17
|
+
from tico.experimental.quantization.ptq.observers.affine_base import AffineObserverBase
|
18
|
+
from tico.experimental.quantization.ptq.utils import channelwise_minmax
|
19
|
+
|
20
|
+
|
21
|
+
class EMAObserver(AffineObserverBase):
|
22
|
+
"""
|
23
|
+
Exponential-Moving-Average min/max tracker.
|
24
|
+
|
25
|
+
Why?
|
26
|
+
-----
|
27
|
+
• Smoother than raw MinMax (reduces outlier shock).
|
28
|
+
• Much cheaper than histogram/MSE observers.
|
29
|
+
|
30
|
+
The update rule follows the common "momentum" form:
|
31
|
+
|
32
|
+
ema = momentum * ema + (1 - momentum) * new_value
|
33
|
+
|
34
|
+
With momentum → 0: *fast* adaptation, momentum → 1: *slow* adaptation.
|
35
|
+
"""
|
36
|
+
|
37
|
+
def __init__(
|
38
|
+
self,
|
39
|
+
*,
|
40
|
+
momentum: float = 0.9,
|
41
|
+
**kwargs,
|
42
|
+
):
|
43
|
+
super().__init__(**kwargs)
|
44
|
+
assert 0.0 < momentum < 1.0, "momentum must be in (0, 1)"
|
45
|
+
self.momentum = momentum
|
46
|
+
|
47
|
+
@torch.no_grad()
|
48
|
+
def _update_stats(self, x: torch.Tensor):
|
49
|
+
if self.channel_axis is None:
|
50
|
+
curr_min, curr_max = x.min(), x.max()
|
51
|
+
else:
|
52
|
+
curr_min, curr_max = channelwise_minmax(x, self.channel_axis)
|
53
|
+
|
54
|
+
if (
|
55
|
+
torch.isinf(self.min_val).any() and torch.isinf(self.max_val).any()
|
56
|
+
): # first batch → hard init
|
57
|
+
self.min_val, self.max_val = curr_min, curr_max
|
58
|
+
return
|
59
|
+
|
60
|
+
m = self.momentum
|
61
|
+
self.min_val = m * self.min_val + (1 - m) * curr_min
|
62
|
+
self.max_val = m * self.max_val + (1 - m) * curr_max
|
@@ -0,0 +1,74 @@
|
|
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
|
+
"""
|
16
|
+
IdentityObserver: a *no-op* observer for FP-only modules.
|
17
|
+
|
18
|
+
Motivation
|
19
|
+
----------
|
20
|
+
Some layers should stay in full precision even when the rest of the model
|
21
|
+
is quantized. Attaching an `IdentityObserver` satisfies the wrapper API
|
22
|
+
(`_update_stats()`, `compute_qparams()`, `fake_quant()`) without actually
|
23
|
+
performing any statistics gathering or fake-quantization.
|
24
|
+
"""
|
25
|
+
import torch
|
26
|
+
|
27
|
+
from tico.experimental.quantization.ptq.observers.affine_base import AffineObserverBase
|
28
|
+
|
29
|
+
|
30
|
+
class IdentityObserver(AffineObserverBase):
|
31
|
+
"""
|
32
|
+
Passthrough observer that **never** alters the tensor.
|
33
|
+
|
34
|
+
• `_update_stats()` → does nothing
|
35
|
+
• `compute_qparams()` → returns (1.0, 0) *dummy* q-params
|
36
|
+
• `fake_quant()` → returns *x* unchanged
|
37
|
+
"""
|
38
|
+
|
39
|
+
def __init__(self, **kwargs):
|
40
|
+
# Call parent so the usual fields (`dtype`, `qscheme`, …) exist,
|
41
|
+
# but immediately disable any stateful behaviour.
|
42
|
+
super().__init__(**kwargs)
|
43
|
+
|
44
|
+
# Deactivate statistics collection permanently.
|
45
|
+
self.enabled = False
|
46
|
+
|
47
|
+
# Pre-cache sentinel q-params so wrapper code that blindly
|
48
|
+
# accesses them won't crash.
|
49
|
+
self._cached_scale = torch.tensor(1.0)
|
50
|
+
self._cached_zp = torch.tensor(0, dtype=torch.int)
|
51
|
+
|
52
|
+
def reset(self) -> None: # (simple override – nothing to do)
|
53
|
+
"""No internal state to reset."""
|
54
|
+
pass
|
55
|
+
|
56
|
+
def _update_stats(self, x: torch.Tensor) -> None:
|
57
|
+
"""Skip statistic collection entirely."""
|
58
|
+
return
|
59
|
+
|
60
|
+
def compute_qparams(self):
|
61
|
+
"""
|
62
|
+
Return the pre-cached (scale, zero_point) tuple.
|
63
|
+
|
64
|
+
Keeping the signature identical to other observers allows uniform
|
65
|
+
lifecycle management in wrapper code.
|
66
|
+
"""
|
67
|
+
return self._cached_scale, self._cached_zp
|
68
|
+
|
69
|
+
def fake_quant(self, x: torch.Tensor):
|
70
|
+
"""Identity mapping — leaves *x* in FP."""
|
71
|
+
return x
|
72
|
+
|
73
|
+
def __repr__(self) -> str:
|
74
|
+
return f"{self.__class__.__name__}()"
|
tico/utils/utils.py
CHANGED
@@ -79,73 +79,70 @@ def enforce_type(callable):
|
|
79
79
|
def check_types(*args, **kwargs):
|
80
80
|
parameters = dict(zip(spec.args, args))
|
81
81
|
parameters.update(kwargs)
|
82
|
-
for name, value in parameters.items():
|
83
|
-
if name == "self":
|
84
|
-
# skip 'self' in spec.args
|
85
|
-
continue
|
86
|
-
|
87
|
-
assert (
|
88
|
-
name in spec.annotations
|
89
|
-
), f"All parameter require type hints. {name} needs a type hint"
|
90
|
-
|
91
|
-
type_hint = spec.annotations[name]
|
92
82
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
83
|
+
# Return tuple of flattened types.
|
84
|
+
# Q) What is flatten?
|
85
|
+
# A) Optional/Union is not included. Below are included.
|
86
|
+
# collections: List, Set, ...
|
87
|
+
# primitive types: int, str, ...
|
88
|
+
def _flatten_type(type_hint) -> tuple:
|
89
|
+
# `get_origin` maps Union[...] and Optional[...] varieties to Union
|
90
|
+
if typing.get_origin(type_hint) == typing.Union:
|
91
|
+
# ex. typing.Union[list, int] -> (list, int)
|
92
|
+
# ex. typing.Optional[torch.fx.Node] -> (torch.fx.Node, NoneType)
|
93
|
+
actual_type = tuple(
|
94
|
+
_flatten_type(t) for t in typing.get_args(type_hint)
|
95
|
+
)
|
96
|
+
else:
|
97
|
+
actual_type = (type_hint,)
|
98
|
+
return actual_type
|
109
99
|
|
110
|
-
|
100
|
+
# Return true if value matches with type_hint
|
101
|
+
# Return false otherwise
|
102
|
+
def _check_type(value, type_hint):
|
103
|
+
if type_hint == typing.Any:
|
104
|
+
return True
|
111
105
|
|
112
|
-
|
113
|
-
|
114
|
-
def _check_type(value, type_hint):
|
115
|
-
if type_hint == typing.Any:
|
116
|
-
return True
|
106
|
+
if isinstance(type_hint, tuple):
|
107
|
+
return any(_check_type(value, t) for t in type_hint)
|
117
108
|
|
118
|
-
|
119
|
-
|
109
|
+
if typing.get_origin(type_hint) in (list, set):
|
110
|
+
if not isinstance(value, typing.get_origin(type_hint)):
|
111
|
+
return False
|
120
112
|
|
121
|
-
|
122
|
-
if not
|
113
|
+
for v in value:
|
114
|
+
if not any(_check_type(v, t) for t in typing.get_args(type_hint)):
|
123
115
|
return False
|
124
116
|
|
125
|
-
|
126
|
-
if not any(
|
127
|
-
[_check_type(v, t) for t in typing.get_args(type_hint)]
|
128
|
-
):
|
129
|
-
return False
|
117
|
+
return True
|
130
118
|
|
131
|
-
|
119
|
+
if typing.get_origin(type_hint) is dict:
|
120
|
+
if not isinstance(value, typing.get_origin(type_hint)):
|
121
|
+
return False
|
132
122
|
|
133
|
-
|
134
|
-
|
123
|
+
for k, v in value.items():
|
124
|
+
k_type, v_type = typing.get_args(type_hint)
|
125
|
+
if not _check_type(k, k_type):
|
126
|
+
return False
|
127
|
+
if not _check_type(v, v_type):
|
135
128
|
return False
|
136
129
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
if not _check_type(v, v_type):
|
142
|
-
return False
|
130
|
+
return True
|
131
|
+
|
132
|
+
# TODO: Support more type hints
|
133
|
+
return isinstance(value, type_hint)
|
143
134
|
|
144
|
-
|
135
|
+
for name, value in parameters.items():
|
136
|
+
if name == "self":
|
137
|
+
# skip 'self' in spec.args
|
138
|
+
continue
|
145
139
|
|
146
|
-
|
147
|
-
|
140
|
+
assert (
|
141
|
+
name in spec.annotations
|
142
|
+
), f"All parameter require type hints. {name} needs a type hint"
|
148
143
|
|
144
|
+
type_hint = spec.annotations[name]
|
145
|
+
type_hint = _flatten_type(type_hint)
|
149
146
|
type_check_result = _check_type(value, type_hint)
|
150
147
|
if not type_check_result:
|
151
148
|
raise ArgTypeError(
|
@@ -1,4 +1,4 @@
|
|
1
|
-
tico/__init__.py,sha256=
|
1
|
+
tico/__init__.py,sha256=Y5AdGv7QfIPC6o_P2M2S16JtXG5LLmtIfUU7gq6scYQ,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
|
@@ -60,9 +60,11 @@ tico/experimental/quantization/ptq/__init__.py,sha256=ZoPdEwZ1i1n5pBFChx8GuUrkfR
|
|
60
60
|
tico/experimental/quantization/ptq/dtypes.py,sha256=xfCBtq6mQmUYRwsoFgII6gvRl1raQi0Inj9pznDuKwQ,2236
|
61
61
|
tico/experimental/quantization/ptq/mode.py,sha256=lT-T8vIv8YWcwrjT7xXVhOw1g7aoAdh_3PWB-ptPKaI,1052
|
62
62
|
tico/experimental/quantization/ptq/qscheme.py,sha256=uwhv7bCxOOXB3I-IKlRyr_u4eXOq48uIqGy4TLDqGxY,1301
|
63
|
-
tico/experimental/quantization/ptq/observers/__init__.py,sha256=
|
63
|
+
tico/experimental/quantization/ptq/observers/__init__.py,sha256=wyrO0KTZve78aFWTwvsOE82Vu2kbCxJv8aqjiO1QL2s,524
|
64
64
|
tico/experimental/quantization/ptq/observers/affine_base.py,sha256=e2Eba64nrxKQyE4F_WJ7WTSsk3xe6bkdGUKaoLFWGFw,4638
|
65
65
|
tico/experimental/quantization/ptq/observers/base.py,sha256=Wons1MzpqK1mfcy-ppl-B2Dum0edXg2dWW2Lw3V18tw,3280
|
66
|
+
tico/experimental/quantization/ptq/observers/ema.py,sha256=WZiYWEHrkgizAwnRCtfOm9JPHfZrjZTxMr6X9Wuovmo,2061
|
67
|
+
tico/experimental/quantization/ptq/observers/identity.py,sha256=jdlNH52z8ANOZbs_0KFZ4iEstVfNC1OUzQsm1a9FFpM,2595
|
66
68
|
tico/experimental/quantization/ptq/observers/minmax.py,sha256=mLHkwIzWFzQXev7EU7w1333KckwRjukc3_cUPJOnUfs,1486
|
67
69
|
tico/experimental/quantization/ptq/utils/__init__.py,sha256=PL9IZgiWoMtsXVljeOy7KymmLVP238SXEFRLXYK72WQ,126
|
68
70
|
tico/experimental/quantization/ptq/utils/reduce_utils.py,sha256=3kWawLB91EcvvHlCrNqqfZF7tpgr22htBSA049mKw_4,973
|
@@ -214,15 +216,15 @@ tico/utils/serialize.py,sha256=mEuusEzi82WFsz3AkowgWwxSLeo50JDxyOj6yYDQhEI,1914
|
|
214
216
|
tico/utils/signature.py,sha256=R2GV0alRpXEbZISqPKyxCUWbgDcsrQ2ovbVG3737IzA,9595
|
215
217
|
tico/utils/torch_compat.py,sha256=oc6PztVsXdHcQ3iaVR90wLLxrGaj6zFHWZ8K9rRS6q8,1795
|
216
218
|
tico/utils/trace_decorators.py,sha256=ddLIiKQfSaQrxgF1kNpwjFTQnXENzeSfcr1kuAW4jGI,3221
|
217
|
-
tico/utils/utils.py,sha256=
|
219
|
+
tico/utils/utils.py,sha256=aySftYnNTsqVAMcGs_3uX3-hz577a2cj4p1aVV-1XeQ,12747
|
218
220
|
tico/utils/validate_args_kwargs.py,sha256=aY7hyDaZKrZn0ev0liUFZdHS8__0Vpp5QyqDEobZ_zM,27163
|
219
221
|
tico/utils/mx/__init__.py,sha256=IO6FP_xYbGy0dW0HL26GXD3ouxARaxCK7bz9dn4blPQ,26
|
220
222
|
tico/utils/mx/elemwise_ops.py,sha256=V6glyAHsVR1joqpsgnNytatCD_ew92xNWZ19UFDoMTA,10281
|
221
223
|
tico/utils/mx/formats.py,sha256=uzNWyu-1onUlwQfX5cZ6fZSUfHMRqorper7_T1k3jfk,3404
|
222
224
|
tico/utils/mx/mx_ops.py,sha256=RcfUTYVi-wilGB2sC35OeARdwDqnixv7dG5iyZ-fQT8,8555
|
223
|
-
tico-0.1.0.
|
224
|
-
tico-0.1.0.
|
225
|
-
tico-0.1.0.
|
226
|
-
tico-0.1.0.
|
227
|
-
tico-0.1.0.
|
228
|
-
tico-0.1.0.
|
225
|
+
tico-0.1.0.dev250814.dist-info/LICENSE,sha256=kp4JLII7bzRhPb0CPD5XTDZMh22BQ7h3k3B7t8TiSbw,12644
|
226
|
+
tico-0.1.0.dev250814.dist-info/METADATA,sha256=CWbuRvOwPOiqf8FwnG5H8tij1fQqH3k_JpO8zhtXQfg,8450
|
227
|
+
tico-0.1.0.dev250814.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
228
|
+
tico-0.1.0.dev250814.dist-info/entry_points.txt,sha256=kBKYSS_IYrSXmUYevmmepqIVPScq5vF8ulQRu3I_Zf0,59
|
229
|
+
tico-0.1.0.dev250814.dist-info/top_level.txt,sha256=oqs7UPoNSKZEwqsX8B-KAWdQwfAa7i60pbxW_Jk7P3w,5
|
230
|
+
tico-0.1.0.dev250814.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|