tico 0.1.0.dev250411__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 (196) hide show
  1. tico/__init__.py +31 -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 +97 -0
  51. tico/experimental/quantization/passes/insert_quantize_on_dtype_mismatch.py +289 -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/remove_weight_dequant_op.py +168 -0
  55. tico/experimental/quantization/public_interface.py +108 -0
  56. tico/experimental/quantization/quantizer.py +71 -0
  57. tico/interpreter/__init__.py +1 -0
  58. tico/interpreter/infer.py +116 -0
  59. tico/interpreter/interpreter.py +93 -0
  60. tico/passes/__init__.py +1 -0
  61. tico/passes/cast_aten_where_arg_type.py +185 -0
  62. tico/passes/cast_mixed_type_args.py +186 -0
  63. tico/passes/const_prop_pass.py +307 -0
  64. tico/passes/convert_conv1d_to_conv2d.py +151 -0
  65. tico/passes/convert_layout_op_to_reshape.py +84 -0
  66. tico/passes/convert_repeat_to_expand_copy.py +90 -0
  67. tico/passes/convert_to_relu6.py +180 -0
  68. tico/passes/decompose_addmm.py +127 -0
  69. tico/passes/decompose_batch_norm.py +198 -0
  70. tico/passes/decompose_fake_quantize.py +126 -0
  71. tico/passes/decompose_fake_quantize_tensor_qparams.py +270 -0
  72. tico/passes/decompose_group_norm.py +258 -0
  73. tico/passes/decompose_grouped_conv2d.py +202 -0
  74. tico/passes/decompose_slice_scatter.py +167 -0
  75. tico/passes/extract_dtype_kwargs.py +121 -0
  76. tico/passes/fill_meta_val.py +57 -0
  77. tico/passes/fuse_redundant_reshape_to_mean.py +102 -0
  78. tico/passes/legalize_causal_mask_value.py +113 -0
  79. tico/passes/legalize_predefined_layout_operators.py +383 -0
  80. tico/passes/lower_pow2_to_mul.py +75 -0
  81. tico/passes/lower_to_resize_nearest_neighbor.py +249 -0
  82. tico/passes/lower_to_slice.py +112 -0
  83. tico/passes/merge_consecutive_cat.py +82 -0
  84. tico/passes/ops.py +75 -0
  85. tico/passes/remove_nop.py +85 -0
  86. tico/passes/remove_redundant_assert_nodes.py +50 -0
  87. tico/passes/remove_redundant_expand.py +70 -0
  88. tico/passes/remove_redundant_permute.py +102 -0
  89. tico/passes/remove_redundant_reshape.py +431 -0
  90. tico/passes/remove_redundant_slice.py +64 -0
  91. tico/passes/remove_redundant_to_copy.py +84 -0
  92. tico/passes/restore_linear.py +113 -0
  93. tico/passes/segment_index_select.py +143 -0
  94. tico/pt2_to_circle.py +101 -0
  95. tico/serialize/__init__.py +1 -0
  96. tico/serialize/circle_graph.py +264 -0
  97. tico/serialize/circle_mapping.py +177 -0
  98. tico/serialize/circle_serializer.py +232 -0
  99. tico/serialize/operators/__init__.py +28 -0
  100. tico/serialize/operators/hashable_opcode.py +43 -0
  101. tico/serialize/operators/node_visitor.py +80 -0
  102. tico/serialize/operators/op_add.py +69 -0
  103. tico/serialize/operators/op_alias_copy.py +64 -0
  104. tico/serialize/operators/op_any.py +142 -0
  105. tico/serialize/operators/op_arange_start_step.py +61 -0
  106. tico/serialize/operators/op_argmax.py +62 -0
  107. tico/serialize/operators/op_avg_pool2d.py +112 -0
  108. tico/serialize/operators/op_bmm.py +62 -0
  109. tico/serialize/operators/op_cat.py +66 -0
  110. tico/serialize/operators/op_clamp.py +123 -0
  111. tico/serialize/operators/op_clone.py +71 -0
  112. tico/serialize/operators/op_constant_pad_nd.py +72 -0
  113. tico/serialize/operators/op_conv2d.py +181 -0
  114. tico/serialize/operators/op_copy.py +162 -0
  115. tico/serialize/operators/op_cos.py +59 -0
  116. tico/serialize/operators/op_cumsum.py +92 -0
  117. tico/serialize/operators/op_depthwise_conv2d.py +198 -0
  118. tico/serialize/operators/op_dequantize_per_channel.py +82 -0
  119. tico/serialize/operators/op_dequantize_per_tensor.py +64 -0
  120. tico/serialize/operators/op_div.py +62 -0
  121. tico/serialize/operators/op_embedding.py +60 -0
  122. tico/serialize/operators/op_eq.py +64 -0
  123. tico/serialize/operators/op_exp.py +60 -0
  124. tico/serialize/operators/op_expand.py +91 -0
  125. tico/serialize/operators/op_full.py +48 -0
  126. tico/serialize/operators/op_full_like.py +55 -0
  127. tico/serialize/operators/op_ge.py +54 -0
  128. tico/serialize/operators/op_gelu.py +59 -0
  129. tico/serialize/operators/op_gt.py +54 -0
  130. tico/serialize/operators/op_index.py +82 -0
  131. tico/serialize/operators/op_index_select.py +64 -0
  132. tico/serialize/operators/op_instance_norm.py +91 -0
  133. tico/serialize/operators/op_linear.py +70 -0
  134. tico/serialize/operators/op_log.py +53 -0
  135. tico/serialize/operators/op_log1p.py +83 -0
  136. tico/serialize/operators/op_logical_and.py +63 -0
  137. tico/serialize/operators/op_logical_not.py +62 -0
  138. tico/serialize/operators/op_lt.py +61 -0
  139. tico/serialize/operators/op_max_pool2d_with_indices.py +140 -0
  140. tico/serialize/operators/op_maximum.py +53 -0
  141. tico/serialize/operators/op_mean.py +66 -0
  142. tico/serialize/operators/op_minimum.py +53 -0
  143. tico/serialize/operators/op_mm.py +174 -0
  144. tico/serialize/operators/op_mul.py +99 -0
  145. tico/serialize/operators/op_ne.py +54 -0
  146. tico/serialize/operators/op_neg.py +59 -0
  147. tico/serialize/operators/op_permute.py +65 -0
  148. tico/serialize/operators/op_pow.py +138 -0
  149. tico/serialize/operators/op_prelu.py +54 -0
  150. tico/serialize/operators/op_quantize_per_tensor.py +79 -0
  151. tico/serialize/operators/op_reciprocal.py +64 -0
  152. tico/serialize/operators/op_relu.py +53 -0
  153. tico/serialize/operators/op_relu6.py +52 -0
  154. tico/serialize/operators/op_repeat.py +99 -0
  155. tico/serialize/operators/op_reshape.py +73 -0
  156. tico/serialize/operators/op_resize_nearest_neighbor.py +70 -0
  157. tico/serialize/operators/op_rsqrt.py +53 -0
  158. tico/serialize/operators/op_scalar_tensor.py +51 -0
  159. tico/serialize/operators/op_select_copy.py +65 -0
  160. tico/serialize/operators/op_sigmoid.py +56 -0
  161. tico/serialize/operators/op_sin.py +53 -0
  162. tico/serialize/operators/op_slice.py +155 -0
  163. tico/serialize/operators/op_softmax.py +100 -0
  164. tico/serialize/operators/op_split_with_sizes.py +96 -0
  165. tico/serialize/operators/op_sqrt.py +55 -0
  166. tico/serialize/operators/op_squeeze.py +73 -0
  167. tico/serialize/operators/op_sub.py +71 -0
  168. tico/serialize/operators/op_sum.py +63 -0
  169. tico/serialize/operators/op_tanh.py +54 -0
  170. tico/serialize/operators/op_to_copy.py +105 -0
  171. tico/serialize/operators/op_unsqueeze.py +66 -0
  172. tico/serialize/operators/op_view.py +74 -0
  173. tico/serialize/operators/op_where.py +82 -0
  174. tico/serialize/operators/utils.py +51 -0
  175. tico/serialize/pack.py +35 -0
  176. tico/serialize/quant_param.py +42 -0
  177. tico/utils/__init__.py +1 -0
  178. tico/utils/convert.py +292 -0
  179. tico/utils/define.py +35 -0
  180. tico/utils/diff_graph.py +181 -0
  181. tico/utils/errors.py +35 -0
  182. tico/utils/graph.py +200 -0
  183. tico/utils/logging.py +45 -0
  184. tico/utils/model.py +37 -0
  185. tico/utils/padding.py +47 -0
  186. tico/utils/passes.py +76 -0
  187. tico/utils/register_custom_op.py +562 -0
  188. tico/utils/trace_decorators.py +101 -0
  189. tico/utils/utils.py +314 -0
  190. tico/utils/validate_args_kwargs.py +1114 -0
  191. tico-0.1.0.dev250411.dist-info/LICENSE +241 -0
  192. tico-0.1.0.dev250411.dist-info/METADATA +17 -0
  193. tico-0.1.0.dev250411.dist-info/RECORD +196 -0
  194. tico-0.1.0.dev250411.dist-info/WHEEL +5 -0
  195. tico-0.1.0.dev250411.dist-info/entry_points.txt +3 -0
  196. tico-0.1.0.dev250411.dist-info/top_level.txt +1 -0
tico/utils/utils.py ADDED
@@ -0,0 +1,314 @@
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 inspect
16
+ import subprocess
17
+ import typing
18
+ import warnings
19
+ from functools import wraps
20
+
21
+ import torch
22
+ from circle_schema import circle
23
+ from packaging.version import Version
24
+ from torch._guards import detect_fake_mode
25
+ from torch.export import ExportedProgram
26
+ from torch.utils import _pytree as pytree
27
+
28
+ from tico.serialize.quant_param import QuantParam
29
+
30
+
31
+ HAS_TORCH_OVER_25 = Version(torch.__version__) >= Version("2.5.0")
32
+ HAS_TORCH_OVER_28_DEV = Version(torch.__version__) >= Version("2.8.0.dev")
33
+
34
+
35
+ def get_fake_mode(exported_program: ExportedProgram):
36
+ fake_mode = detect_fake_mode(
37
+ tuple(
38
+ node.meta["val"]
39
+ for node in exported_program.graph.nodes
40
+ if node.op == "placeholder"
41
+ )
42
+ )
43
+ assert fake_mode is not None
44
+ return fake_mode
45
+
46
+
47
+ class SuppressWarning:
48
+ def __init__(self, warning_category: type[Warning], regex):
49
+ self.warning_category = warning_category
50
+ self.regex = regex
51
+
52
+ def __enter__(self):
53
+ warnings.filterwarnings(
54
+ "ignore", category=self.warning_category, message=self.regex
55
+ )
56
+
57
+ def __exit__(self, exc_type, exc_val, exc_tb):
58
+ warnings.filterwarnings(
59
+ "default", category=self.warning_category, message=self.regex
60
+ )
61
+
62
+
63
+ class ArgTypeError(Exception):
64
+ """
65
+ Invalid argument type
66
+ """
67
+
68
+ pass
69
+
70
+
71
+ def enforce_type(callable):
72
+ """Check types for your callable's signature
73
+
74
+ NOTE Place this one above @dataclass decorator if you want to use it with dataclass initializer.
75
+ Ex.
76
+ @enforce_type
77
+ @dataclass
78
+ class Args:
79
+ ...
80
+ """
81
+ spec = inspect.getfullargspec(callable)
82
+
83
+ def check_types(*args, **kwargs):
84
+ parameters = dict(zip(spec.args, args))
85
+ parameters.update(kwargs)
86
+ for name, value in parameters.items():
87
+ if name == "self":
88
+ # skip 'self' in spec.args
89
+ continue
90
+
91
+ assert (
92
+ name in spec.annotations
93
+ ), f"All parameter require type hints. {name} needs a type hint"
94
+
95
+ type_hint = spec.annotations[name]
96
+
97
+ # Return tuple of flattened types.
98
+ # Q) What is flatten?
99
+ # A) Optional/Union is not included. Below are included.
100
+ # collections: List, Set, ...
101
+ # primitive types: int, str, ...
102
+ def _flatten_type(type_hint) -> tuple:
103
+ # `get_origin` maps Union[...] and Optional[...] varieties to Union
104
+ if typing.get_origin(type_hint) == typing.Union:
105
+ # ex. typing.Union[list, int] -> (list, int)
106
+ # ex. typing.Optional[torch.fx.Node] -> (torch.fx.Node, NoneType)
107
+ actual_type = tuple(
108
+ [_flatten_type(t) for t in typing.get_args(type_hint)]
109
+ )
110
+ else:
111
+ actual_type = (type_hint,)
112
+ return actual_type
113
+
114
+ type_hint = _flatten_type(type_hint)
115
+
116
+ # Return true if value matches with type_hint
117
+ # Return false otherwise
118
+ def _check_type(value, type_hint):
119
+ if type_hint == typing.Any:
120
+ return True
121
+
122
+ if isinstance(type_hint, tuple):
123
+ return any([_check_type(value, t) for t in type_hint])
124
+
125
+ if typing.get_origin(type_hint) in (list, set):
126
+ if not isinstance(value, typing.get_origin(type_hint)):
127
+ return False
128
+
129
+ for v in value:
130
+ if not any(
131
+ [_check_type(v, t) for t in typing.get_args(type_hint)]
132
+ ):
133
+ return False
134
+
135
+ return True
136
+
137
+ if typing.get_origin(type_hint) == dict:
138
+ if not isinstance(value, typing.get_origin(type_hint)):
139
+ return False
140
+
141
+ for k, v in value.items():
142
+ k_type, v_type = typing.get_args(type_hint)
143
+ if not _check_type(k, k_type):
144
+ return False
145
+ if not _check_type(v, v_type):
146
+ return False
147
+
148
+ return True
149
+
150
+ # TODO: Support more type hints
151
+ return isinstance(value, type_hint)
152
+
153
+ type_check_result = _check_type(value, type_hint)
154
+ if not type_check_result:
155
+ raise ArgTypeError(
156
+ "Unexpected type for '{}' (expected {} but found {})".format(
157
+ name, type_hint, type(value)
158
+ )
159
+ )
160
+
161
+ def decorate(func):
162
+ @wraps(func)
163
+ def wrapper(*args, **kwargs):
164
+ check_types(*args, **kwargs)
165
+ return func(*args, **kwargs)
166
+
167
+ return wrapper
168
+
169
+ if inspect.isclass(callable):
170
+ callable.__init__ = decorate(callable.__init__)
171
+ return callable
172
+
173
+ return decorate(callable)
174
+
175
+
176
+ def fill_meta_val(exported_program: ExportedProgram):
177
+ for node in exported_program.graph.nodes:
178
+ assert hasattr(node, "meta"), f"{node.name} does not have meta attribute"
179
+
180
+ if node.meta.get("val", None) is None:
181
+ if node.op == "call_function":
182
+ set_new_meta_val(node)
183
+
184
+
185
+ def set_new_meta_val(node: torch.fx.node.Node):
186
+ """
187
+ Set node.meta["val"].
188
+
189
+ There are some cases when node.meta["val"] should be updated.
190
+ - After creating new node
191
+ - After updating node's args or kwargs
192
+ """
193
+ assert isinstance(node, torch.fx.node.Node)
194
+
195
+ # `node.target()` needs only `Tensor` for its arguments.
196
+ # Therefore, let's retrieve `FakeTensor` if it is `torch.fx.Node`.
197
+ args, kwargs = pytree.tree_map_only(
198
+ torch.fx.Node,
199
+ lambda n: n.meta["val"],
200
+ (node.args, node.kwargs),
201
+ )
202
+ new_val = node.target(*args, **kwargs) # type: ignore[operator]
203
+ node.meta["val"] = new_val
204
+
205
+
206
+ def unset_meta_val(node: torch.fx.node.Node):
207
+ """
208
+ Unset node.meta["val"].
209
+
210
+ - When to use it?
211
+ When we need to update a node's meta val
212
+ but some precedent's meta value are not decided yet, (eg. newly created args)
213
+ let's simply unset meta val and expect `FillMetaVal` do it.
214
+ """
215
+ assert isinstance(node, torch.fx.node.Node)
216
+
217
+ if "val" in node.meta:
218
+ del node.meta["val"]
219
+
220
+
221
+ def run_bash_cmd(command: typing.List[str]) -> subprocess.CompletedProcess[str]:
222
+ """
223
+ Executes a given bash command represented as a sequence of program arguments
224
+ using subprocess and returns output.
225
+
226
+ Args:
227
+ command (List[str]): A sequence of program arguments.
228
+
229
+ Returns:
230
+ str: The standard output of the executed command.
231
+
232
+ Example:
233
+ >>> completed_process = run_bash_cmd(["echo", "Hello, World!"])
234
+ print (completed_process.stdout)
235
+ 'Hello, World!\\n'
236
+
237
+ >>> cp = run_bash_cmd(["ls", "-l"])
238
+ print (cp.stdout)
239
+ 'drwxrwxr-x 8 user group 4096 12월 3 17:16 tico\\n'
240
+ """
241
+ if not isinstance(command, list) or not all(isinstance(c, str) for c in command):
242
+ raise ValueError("Command must be a list of strings.")
243
+ try:
244
+ return subprocess.run(command, check=True, text=True, capture_output=True)
245
+ except subprocess.CalledProcessError as err:
246
+ cmd_str = " ".join(err.cmd)
247
+ msg = f"Error while running command:\n\n $ {cmd_str}"
248
+ msg += "\n"
249
+ msg += "[EXIT CODE]\n"
250
+ msg += f"{err.returncode}\n"
251
+ msg += "[STDOUT]\n"
252
+ msg += err.stdout
253
+ msg += "[STDERR]\n"
254
+ msg += err.stderr
255
+ raise RuntimeError(f"Failed.\n\n {msg}")
256
+
257
+
258
+ def has_quantization_ops(graph: torch.fx.Graph):
259
+ """
260
+ Checks whether the given fx graph contains any quantization-related operations.
261
+
262
+ This function inspects the provided graph to determine if it includes operations associated
263
+ with quantization (e.g., quantize, dequantize, fake quantize, etc.). The presence of such operations
264
+ can be used to decide whether to run subsequent quantization-specific passes on the graph.
265
+
266
+ Parameters:
267
+ graph: The fx graph to be examined. It is expected that the graph supports
268
+ iteration or traversal over its constituent operations.
269
+
270
+ Returns:
271
+ bool: True if the graph contains one or more quantization-related operations, False otherwise.
272
+ """
273
+ quantized_ops = [
274
+ torch.ops.quantized_decomposed.quantize_per_tensor.default,
275
+ torch.ops.quantized_decomposed.quantize_per_channel.default,
276
+ torch.ops.quantized_decomposed.dequantize_per_tensor.default,
277
+ torch.ops.quantized_decomposed.dequantize_per_channel.default,
278
+ ]
279
+ for node in graph.nodes:
280
+ if node.op != "call_function":
281
+ continue
282
+ if node.target in quantized_ops:
283
+ return True
284
+
285
+ return False
286
+
287
+
288
+ def to_circle_qparam(qparam: QuantParam):
289
+ circle_qparam = circle.QuantizationParameters.QuantizationParametersT()
290
+ if qparam.scale is not None:
291
+ circle_qparam.scale = qparam.scale
292
+
293
+ if qparam.zero_point is not None:
294
+ circle_qparam.zeroPoint = qparam.zero_point
295
+
296
+ if qparam.quantized_dimension is not None:
297
+ circle_qparam.quantizedDimension = qparam.quantized_dimension
298
+
299
+ if qparam.min is not None:
300
+ circle_qparam.min = qparam.min
301
+
302
+ if qparam.max is not None:
303
+ circle_qparam.max = qparam.max
304
+
305
+ return circle_qparam
306
+
307
+
308
+ def quant_min_max(dtype: str):
309
+ if dtype == "uint8":
310
+ return (0, 255)
311
+ elif dtype == "int16":
312
+ return (-32768, 32767)
313
+ else:
314
+ raise NotImplementedError(f"NYI dtype: {dtype}")