quantization_config.py Source File

quantization_config.py Source File#

Mobilint SDK qb Compiler: quantization_config.py Source File
Mobilint SDK qb Compiler v0.12.0.0
MCS002-KR
quantization_config.py
1import numbers
2from typing import Dict, List, Optional
3from typeguard import typechecked
4from . import ConfigABC
5
6
12
13
14class CalibrationConfig(ConfigABC):
15 """
16 @brief Configuration for calibration during quantization.
17
18 @details Defines calibration and quantization parameterization used to derive activation/weight scales and related
19 statistics during quantized compilation.
20 """
21
22 optional = False
23 method_list = ["WChALayer", "WChAMulti", "WChALayerZeropoint", "WChAMultiZeropoint"]
24 output_list = ["Layer", "Ch", "Sigmoid"]
25 mode_list = [
26 "percentile",
27 "max",
28 "maxPercentile",
29 "fastPercentile",
30 "histogramKL",
31 "histogramMSE",
32 ]
33
34 DEFAULTS = {
35 "quantization_method": 1,
36 "quantization_output": 0,
37 "quantization_mode": 2,
38 "percentile": 0.9999,
39 "topk_ratio": 0.01,
40 "max_each": 128,
41 "max_total": 65536,
42 "kernel_size": 9,
43 "stack_size": 32768,
44 "hist_num_cluster": 4,
45 "hist_search_percentile_min": 0.9999,
46 "hist_epsilon": 0.01,
47 "hist_adjust_coeff": 0.5,
48 "act_scale_min": 0.0005,
49 "weight_scale_min": 1e-6,
50 "min_clip_ratio": -1,
51 "layer_overrides": {"actScaleMin": {"0.0005": []}},
52 }
53
54 py_to_cpp_name = {
55 "quantization_method": "method",
56 "quantization_output": "output",
57 "quantization_mode": "mode",
58 "percentile": "percentile",
59 "topk_ratio": "topKRatio",
60 "max_each": "maxEach",
61 "max_total": "maxTotal",
62 "kernel_size": "kernelSize",
63 "stack_size": "stackSize",
64 "hist_num_cluster": "numCluster",
65 "hist_search_percentile_min": "searchPercentileMin",
66 "hist_epsilon": "epsilon",
67 "hist_adjust_coeff": "adjustCoeff",
68 "act_scale_min": "actScaleMin",
69 "weight_scale_min": "weightScaleMin",
70 "min_clip_ratio": "minClipRatio",
71 }
72
73 min_max_check = {
74 "quantization_method": [0, 3],
75 "quantization_output": [0, 2],
76 "quantization_mode": [0, 5],
77 "percentile": [0, 1],
78 "topk_ratio": [0, 1],
79 "max_each": [0, None],
80 "max_total": [0, None],
81 "kernel_size": [0, None],
82 "stack_size": [0, None],
83 "hist_num_cluster": [0, None],
84 "hist_search_percentile_min": [0, 1],
85 "hist_epsilon": [0, 1],
86 "hist_adjust_coeff": [0, None],
87 "act_scale_min": [0, 1],
88 "weight_scale_min": [0, 1],
89 "min_clip_ratio": [-1, 1],
90 }
91
93 self,
94 quantization_method: int,
95 quantization_output: int,
96 quantization_mode: int,
97 percentile: numbers.Number,
98 topk_ratio: numbers.Number,
99 max_each: int,
100 max_total: int,
101 kernel_size: int,
102 stack_size: int,
103 hist_num_cluster: int,
104 hist_search_percentile_min: numbers.Number,
105 hist_epsilon: numbers.Number,
106 hist_adjust_coeff: numbers.Number,
107 act_scale_min: numbers.Number,
108 weight_scale_min: numbers.Number,
109 min_clip_ratio: numbers.Number,
110 layer_overrides: Dict,
111 optional: bool = optional,
112 ):
113 """
114 @brief Initialize the CalibrationConfig.
115
116 @param quantization_method int. Calibration method index:<br>
117 0: WChALayer - Weight per-channel, Activation per-layer.<br>
118 1: WChAMulti - Weight per-channel, Activation multi-layer.<br>
119 2: WChALayerZeropoint - Weight per-channel, Activation per-layer with zeropoint.<br>
120 3: WChAMultiZeropoint - Weight per-channel, Activation multi-layer with zeropoint.<br>
121 @param quantization_output int. Output quantization type index:<br>
122 0: Layer - Per-layer quantization.<br>
123 1: Ch - Per-channel quantization.<br>
124 2: Sigmoid - Sigmoid-based quantization.<br>
125 @param quantization_mode int. Quantization mode index:<br>
126 0: percentile.<br>
127 1: max.<br>
128 2: maxPercentile.<br>
129 3: fastPercentile.<br>
130 4: histogramKL.<br>
131 5: histogramMSE.<br>
132 @param percentile float. Percentile value used when @p quantization_mode is 0 (percentile).
133 @param topk_ratio float. Top-k ratio used when @p quantization_mode is 2 (maxPercentile).
134 @param max_each int. Maximum number of samples processed per iteration.
135 @param max_total int. Total maximum number of samples processed across all iterations.
136 @param kernel_size int. Kernel size used for fast distribution estimation (typically for @p quantization_mode 3).
137 @param stack_size int. Stack size used for fast distribution estimation (typically for @p quantization_mode 3).
138 @param hist_num_cluster int. Number of clusters/bins used in histogram-based calibration modes.
139 @param hist_search_percentile_min float. Minimum search percentile for histogram-based calibration.
140 @param hist_epsilon float. Numerical epsilon used in histogram-based calibration to avoid instability.
141 @param hist_adjust_coeff float. Adjustment coefficient applied in histogram-based calibration.
142 @param act_scale_min float. Minimum allowed activation scale (lower bound clamp).
143 @param weight_scale_min float. Minimum allowed weight scale (lower bound clamp).
144 @param min_clip_ratio float. Minimum clip ratio constraint applied during calibration.
145 @param layer_overrides Dict. Layer-specific override settings. Keys are layer identifiers; values override one or more
146 calibration parameters for the specified layer.
147 @param optional bool. Indicates whether this config is optional. Use the default value defined as a class variable.
148 """
149 super().__init__(optional)
150 self.quantization_method = quantization_method
151 self.quantization_output = quantization_output
152 self.quantization_mode = quantization_mode
153 self.percentile = percentile
154 self.topk_ratio = topk_ratio
155 self.max_each = max_each
156 self.max_total = max_total
157 self.kernel_size = kernel_size
158 self.stack_size = stack_size
159 self.hist_num_cluster = hist_num_cluster
160 self.hist_search_percentile_min = hist_search_percentile_min
161 self.hist_epsilon = hist_epsilon
162 self.hist_adjust_coeff = hist_adjust_coeff
163 self.act_scale_min = act_scale_min
164 self.weight_scale_min = weight_scale_min
165 self.min_clip_ratio = min_clip_ratio
166 self.layer_overrides = layer_overrides
167 self.check_valid(except_list=["optional", "layer_overrides"])
168
169 @classmethod
170 def default_config(cls):
171 return cls(**cls.DEFAULTS, optional=cls.optional)
172
173 @classmethod
174 def from_kwargs(cls, **kwargs):
175 params = cls.DEFAULTS.copy()
176 updated_kwargs = dict()
177 for key in cls.DEFAULTS.keys():
178 if key in kwargs:
179 updated_kwargs[key] = kwargs[key]
180 params[key] = kwargs[key]
181
182 try:
183 return cls(**params, optional=cls.optional)
184 except:
185 raise ValueError(
186 f"Please review the configuration kwargs passed to {cls.__name__}. These kwargs were updated and will be used: {updated_kwargs}"
187 )
188
189 @classmethod
190 def from_dict(cls, config_dict: dict):
191 """Create CalibrationConfig from dictionary (JSON structure)"""
192 params = cls.DEFAULTS.copy()
193
194 # Top-level parameters
195 if "method" in config_dict:
196 params["quantization_method"] = config_dict["method"]
197 if "output" in config_dict:
198 params["quantization_output"] = config_dict["output"]
199 if "mode" in config_dict:
200 params["quantization_mode"] = config_dict["mode"]
201
202 # Percentile config
203 if "percentile" in config_dict:
204 percentile_config = config_dict["percentile"]
205 if "percentile" in percentile_config:
206 params["percentile"] = percentile_config["percentile"]
207 if "max" in percentile_config:
208 max_config = percentile_config["max"]
209 if "topKRatio" in max_config:
210 params["topk_ratio"] = max_config["topKRatio"]
211 if "maxEach" in max_config:
212 params["max_each"] = max_config["maxEach"]
213 if "maxTotal" in max_config:
214 params["max_total"] = max_config["maxTotal"]
215
216 # Fast distribution config
217 if "fastDist" in config_dict:
218 fast_dist = config_dict["fastDist"]
219 if "kernelSize" in fast_dist:
220 params["kernel_size"] = fast_dist["kernelSize"]
221 if "stackSize" in fast_dist:
222 params["stack_size"] = fast_dist["stackSize"]
223
224 # Histogram config
225 if "histogram" in config_dict:
226 histogram = config_dict["histogram"]
227 if "numCluster" in histogram:
228 params["hist_num_cluster"] = histogram["numCluster"]
229 if "searchPercentileMin" in histogram:
230 params["hist_search_percentile_min"] = histogram["searchPercentileMin"]
231 if "epsilon" in histogram:
232 params["hist_epsilon"] = histogram["epsilon"]
233 if "adjustCoeff" in histogram:
234 params["hist_adjust_coeff"] = histogram["adjustCoeff"]
235
236 # Scale and clip parameters
237 if "actScaleMin" in config_dict:
238 params["act_scale_min"] = config_dict["actScaleMin"]
239 if "weightScaleMin" in config_dict:
240 params["weight_scale_min"] = config_dict["weightScaleMin"]
241 if "minclipRatio" in config_dict:
242 params["min_clip_ratio"] = config_dict["minclipRatio"]
243 if "layerOverrides" in config_dict:
244 params["layer_overrides"] = config_dict["layerOverrides"]
245
246 return cls(**params)
247
248 def to_dict(self):
249 return {
250 "minclipRatio": self.min_clip_ratio,
251 "methodList": self.method_list,
252 "method": self.quantization_method,
253 "outputList": self.output_list,
254 "output": self.quantization_output,
255 "modeList": self.mode_list,
256 "mode": self.quantization_mode,
257 "percentile": {
258 "percentile": self.percentile,
259 "max": {
260 "topKRatio": self.topk_ratio,
261 "maxEach": self.max_each,
262 "maxTotal": self.max_total,
263 },
264 },
265 "max": {},
266 "fastDist": {
267 "sizeCali": 100,
268 "kernelSize": self.kernel_size,
269 "stackSize": self.stack_size,
270 },
271 "histogram": {
272 "numCluster": self.hist_num_cluster,
273 "searchPercentileMin": self.hist_search_percentile_min,
274 "epsilon": self.hist_epsilon,
275 "adjustCoeff": self.hist_adjust_coeff,
276 },
277 "kurtosis": {
278 "percentileMin": 0.9999,
279 "percentileMax": 0.999999,
280 "kurtosisMin": 3.0,
281 "kurtosisMax": 1000.0,
282 "convexity": 1.0,
283 },
284 "actScaleMin": self.act_scale_min,
285 "weightScaleMin": self.weight_scale_min,
286 "layerOverrides": self.layer_overrides,
287 }
288
289
290class BitConfig(ConfigABC):
291 """
292 @brief Configuration for bit precision.
293 @details Defines bit-width parameterization for activations and weights used in mixed-precision quantization (e.g., attention and FFN components).
294 """
295
296 optional = False
297
298 DEFAULTS = {
299 "query_act_bits": 8,
300 "key_act_bits": 8,
301 "value_act_bits": 8,
302 "output_act_bits": 16,
303 "ffn_act_bits": 16,
304 "head_act_bits": 8,
305 "query_weight_bits": 8,
306 "key_weight_bits": 8,
307 "value_weight_bits": 8,
308 "output_weight_bits": 8,
309 "ffn_weight_bits": 8,
310 "head_weight_bits": 8,
311 "mixed_precision_apply": False,
312 "save_path": "",
313 "load_path": "",
314 "activation_16bits": [],
315 "weight_16bits": [],
316 }
317
318 py_to_cpp_name = {
319 "query_act_bits": "queryActBits",
320 "key_act_bits": "keyActBits",
321 "value_act_bits": "valueActBits",
322 "output_act_bits": "outputActBits",
323 "ffn_act_bits": "ffnActBits",
324 "head_act_bits": "headActBits",
325 "query_weight_bits": "queryWeightBits",
326 "key_weight_bits": "keyWeightBits",
327 "value_weight_bits": "valueWeightBits",
328 "output_weight_bits": "outputWeightBits",
329 "ffn_weight_bits": "ffnWeightBits",
330 "head_weight_bits": "headWeightBits",
331 "mixed_precision_apply": "mixedPrecisionApply",
332 "save_path": "savePath",
333 "load_path": "loadPath",
334 }
335
336 # Check that all bits values are positive
337 min_max_check = {
338 "query_act_bits": [1, None],
339 "key_act_bits": [1, None],
340 "value_act_bits": [1, None],
341 "output_act_bits": [1, None],
342 "ffn_act_bits": [1, None],
343 "head_act_bits": [1, None],
344 "query_weight_bits": [1, None],
345 "key_weight_bits": [1, None],
346 "value_weight_bits": [1, None],
347 "output_weight_bits": [1, None],
348 "ffn_weight_bits": [1, None],
349 "head_weight_bits": [1, None],
350 }
351
353 self,
354 query_act_bits: int,
355 key_act_bits: int,
356 value_act_bits: int,
357 output_act_bits: int,
358 ffn_act_bits: int,
359 head_act_bits: int,
360 query_weight_bits: int,
361 key_weight_bits: int,
362 value_weight_bits: int,
363 output_weight_bits: int,
364 ffn_weight_bits: int,
365 head_weight_bits: int,
366 mixed_precision_apply: bool,
367 save_path: str,
368 load_path: str,
369 activation_16bits: List[str],
370 weight_16bits: List[str],
371 optional: bool = optional,
372 ):
373 """
374 @brief Initialize the BitConfig.
375
376 @param query_act_bits int. Query activation bit-width.
377 @param key_act_bits int. Key activation bit-width.
378 @param value_act_bits int. Value activation bit-width.
379 @param output_act_bits int. Output activation bit-width.
380 @param ffn_act_bits int. FFN activation bit-width.
381 @param head_act_bits int. Head activation bit-width.
382 @param query_weight_bits int. Query weight bit-width.
383 @param key_weight_bits int. Key weight bit-width.
384 @param value_weight_bits int. Value weight bit-width.
385 @param output_weight_bits int. Output weight bit-width.
386 @param ffn_weight_bits int. FFN weight bit-width.
387 @param head_weight_bits int. Head weight bit-width.
388 @param mixed_precision_apply bool. If true, apply mixed-precision according to the specified bit-widths.
389 @param save_path str. (optional) Path to save the bit allocation. If empty, the allocation is not saved.
390 @param load_path str. (optional) Path to load the bit allocation. If empty, allocation is not loaded.
391 @param activation_16bits List[str]. (optional) Layer names to force 16-bit activations.
392 @param weight_16bits List[str]. (optional) Layer names to force 16-bit weights.
393 """
394 super().__init__(optional)
395 self.query_act_bits = query_act_bits
396 self.key_act_bits = key_act_bits
397 self.value_act_bits = value_act_bits
398 self.output_act_bits = output_act_bits
399 self.ffn_act_bits = ffn_act_bits
400 self.head_act_bits = head_act_bits
401 self.query_weight_bits = query_weight_bits
402 self.key_weight_bits = key_weight_bits
403 self.value_weight_bits = value_weight_bits
404 self.output_weight_bits = output_weight_bits
405 self.ffn_weight_bits = ffn_weight_bits
406 self.head_weight_bits = head_weight_bits
407 self.mixed_precision_apply = mixed_precision_apply
408 self.save_path = save_path
409 self.load_path = load_path
410 self.activation_16bits = activation_16bits
411 self.weight_16bits = weight_16bits
412 self.check_valid(except_list=["optional", "activation_16bits", "weight_16bits"])
413
414 @classmethod
415 def default_config(cls):
416 return cls(**cls.DEFAULTS, optional=cls.optional)
417
418 @classmethod
419 def from_kwargs(cls, **kwargs):
420 params = cls.DEFAULTS.copy()
421 updated_kwargs = dict()
422 for key in cls.DEFAULTS.keys():
423 if key in kwargs:
424 updated_kwargs[key] = kwargs[key]
425 params[key] = kwargs[key]
426
427 try:
428 return cls(**params, optional=cls.optional)
429 except:
430 raise ValueError(
431 f"Please review the configuration kwargs passed to {cls.__name__}. These kwargs were updated and will be used: {updated_kwargs}"
432 )
433
434 @classmethod
435 def from_dict(cls, config_dict: dict):
436 """Create BitConfig from dictionary (JSON structure)"""
437 params = cls.DEFAULTS.copy()
438
439 # Transformer config
440 if "transformer" in config_dict:
441 transformer = config_dict["transformer"]
442
443 # Activation bits
444 if "activation" in transformer:
445 activation = transformer["activation"]
446 if "query" in activation:
447 params["query_act_bits"] = activation["query"]
448 if "key" in activation:
449 params["key_act_bits"] = activation["key"]
450 if "value" in activation:
451 params["value_act_bits"] = activation["value"]
452 if "output" in activation:
453 params["output_act_bits"] = activation["output"]
454 if "ffn" in activation:
455 params["ffn_act_bits"] = activation["ffn"]
456 if "head" in activation:
457 params["head_act_bits"] = activation["head"]
458
459 # Weight bits
460 if "weight" in transformer:
461 weight = transformer["weight"]
462 if "query" in weight:
463 params["query_weight_bits"] = weight["query"]
464 if "key" in weight:
465 params["key_weight_bits"] = weight["key"]
466 if "value" in weight:
467 params["value_weight_bits"] = weight["value"]
468 if "output" in weight:
469 params["output_weight_bits"] = weight["output"]
470 if "ffn" in weight:
471 params["ffn_weight_bits"] = weight["ffn"]
472 if "head" in weight:
473 params["head_weight_bits"] = weight["head"]
474
475 # Mixed precision
476 if "mixedPrecision" in transformer:
477 mixed_precision = transformer["mixedPrecision"]
478 if "apply" in mixed_precision:
479 params["mixed_precision_apply"] = mixed_precision["apply"]
480
481 # Save info
482 if "saveInfo" in config_dict:
483 save_info = config_dict["saveInfo"]
484 if "savePath" in save_info:
485 params["save_path"] = save_info["savePath"]
486 if "loadPath" in save_info:
487 params["load_path"] = save_info["loadPath"]
488
489 # Layer overrides
490 if "layerOverrides" in config_dict:
491 layer_overrides = config_dict["layerOverrides"]
492 if "activation16Bits" in layer_overrides:
493 params["activation_16bits"] = layer_overrides["activation16Bits"]
494 if "weight16Bits" in layer_overrides:
495 params["weight_16bits"] = layer_overrides["weight16Bits"]
496
497 return cls(**params)
498
499 def to_dict(self):
500 return {
501 "transformer": {
502 "activation": {
503 "query": self.query_act_bits,
504 "key": self.key_act_bits,
505 "value": self.value_act_bits,
506 "output": self.output_act_bits,
507 "ffn": self.ffn_act_bits,
508 "head": self.head_act_bits,
509 },
510 "weight": {
511 "query": self.query_weight_bits,
512 "key": self.key_weight_bits,
513 "value": self.value_weight_bits,
514 "output": self.output_weight_bits,
515 "ffn": self.ffn_weight_bits,
516 "head": self.head_weight_bits,
517 },
518 "mixedPrecision": {
519 "apply": self.mixed_precision_apply,
520 "typeWise": True,
521 "prune": 0,
522 "bit_2": 0,
523 "bit_4": 0,
524 "bit_8": 1,
525 "importanceThreshold_low": -1,
526 "importanceThreshold_high": -1,
527 },
528 },
529 "saveInfo": {
530 "savePath": self.save_path,
531 "loadPath": self.load_path,
532 },
533 "layerOverrides": {
534 "activation16Bits": self.activation_16bits,
535 "weight16Bits": self.weight_16bits,
536 },
537 }
538
539
540class QuantizationConfig(ConfigABC):
541 """
542 @brief Unified quantization configuration.
543
544 @details Groups calibration and bit-precision configurations into a single configuration.
545 """
546
547 optional = False
548 py_to_cpp_name = {
549 "calibration": "calibration",
550 "bit": "bit",
551 }
552
553 min_max_check = {}
554
555 @typechecked
557 self,
558 optional: bool,
559 calibration: Optional[CalibrationConfig] = None,
560 bit: Optional[BitConfig] = None,
561 ):
562 """
563 @brief Initialize the QuantizationConfig.
564 @param calibration CalibrationConfig. Calibration configuration.
565 @param bit BitConfig. Bit precision configuration.
566 """
567 super().__init__(optional)
568 self.calibration = calibration or CalibrationConfig.default_config()
569 self.bit = bit or BitConfig.default_config()
570
571 @classmethod
572 def default_config(cls):
573 return QuantizationConfig(
574 calibration=CalibrationConfig.default_config(),
575 bit=BitConfig.default_config(),
576 optional=cls.optional,
577 )
578
579 @classmethod
580 def from_kwargs(cls, **kwargs):
581 return QuantizationConfig(
582 calibration=CalibrationConfig.from_kwargs(**kwargs),
583 bit=BitConfig.from_kwargs(**kwargs),
584 optional=cls.optional,
585 )
586
587 @classmethod
588 def from_dict(cls, config_dict: dict):
589 calibration_dict = config_dict.get("calibration", {})
590 bit_dict = config_dict.get("bit", {})
591
592 return cls(
593 calibration=CalibrationConfig.from_dict(calibration_dict),
594 bit=BitConfig.from_dict(bit_dict),
595 )
596
597 def to_dict(self):
598 return {
599 "quantization": {
600 "calibration": self.calibration.to_dict(),
601 "bit": self.bit.to_dict(),
602 }
603 }
604
605
606def get_calibration_config(**kwargs) -> CalibrationConfig:
607 """
608 @brief Create CalibrationConfig with partial parameters merged with defaults.
609 """
610 params = CalibrationConfig.DEFAULTS.copy()
611 params.update(kwargs)
612 return CalibrationConfig(**params, optional=CalibrationConfig.optional)
613
614
615def get_bit_config(**kwargs) -> BitConfig:
616 """
617 @brief Create BitConfig with partial parameters merged with defaults.
618 """
619 params = BitConfig.DEFAULTS.copy()
620 params.update(kwargs)
621 return BitConfig(**params, optional=BitConfig.optional)
622
623
625 calibration: Optional[CalibrationConfig] = None,
626 bit: Optional[BitConfig] = None,
627) -> QuantizationConfig:
628 """
629 @brief Create QuantizationConfig with partial parameters merged with defaults.
630 """
631 return QuantizationConfig(
632 calibration=calibration, bit=bit, optional=QuantizationConfig.optional
633 )
634
635
636# @}
Configuration for calibration during quantization.
from_dict(cls, dict config_dict)
Create BitConfig from dictionary (JSON structure)
__init__(self, int query_act_bits, int key_act_bits, int value_act_bits, int output_act_bits, int ffn_act_bits, int head_act_bits, int query_weight_bits, int key_weight_bits, int value_weight_bits, int output_weight_bits, int ffn_weight_bits, int head_weight_bits, bool mixed_precision_apply, str save_path, str load_path, List[str] activation_16bits, List[str] weight_16bits, bool optional=optional)
Initialize the BitConfig.
from_dict(cls, dict config_dict)
Create CalibrationConfig from dictionary (JSON structure)
BitConfig get_bit_config(**kwargs)
Create BitConfig with partial parameters merged with defaults.
CalibrationConfig get_calibration_config(**kwargs)
Create CalibrationConfig with partial parameters merged with defaults.
__init__(self, bool optional, Optional[CalibrationConfig] calibration=None, Optional[BitConfig] bit=None)
Initialize the QuantizationConfig.
QuantizationConfig get_quantization_config(Optional[CalibrationConfig] calibration=None, Optional[BitConfig] bit=None)
Create QuantizationConfig with partial parameters merged with defaults.
__init__(self, int quantization_method, int quantization_output, int quantization_mode, numbers.Number percentile, numbers.Number topk_ratio, int max_each, int max_total, int kernel_size, int stack_size, int hist_num_cluster, numbers.Number hist_search_percentile_min, numbers.Number hist_epsilon, numbers.Number hist_adjust_coeff, numbers.Number act_scale_min, numbers.Number weight_scale_min, numbers.Number min_clip_ratio, Dict layer_overrides, bool optional=optional)
Initialize the CalibrationConfig.