compile_config.py Source File

compile_config.py Source File#

Mobilint SDK qb Compiler: compile_config.py Source File
Mobilint SDK qb Compiler v1.0
MCS002-KR
compile_config.py
1from typeguard import typechecked
2from . import ConfigABC, is_valid_dir_path, check_save_path
3from .resource_management_config import ResourceManagementConfig
4from .quantization_config import QuantizationConfig
5from .advanced_quantization_config import AdvancedQuantizationConfig
6from .llm_config import LlmConfig
7from .input_process_config import (
8 InputProcessConfig,
9 get_input_process_config,
10 Uint8InputConfig,
11 PreprocessingConfig,
12)
13from typing import List, Optional
14
15import tempfile
16import json
17from qbcompiler.calibration.utils_calib import (
18 list_calib_files_in_json,
19 list_calib_files_in_txt,
20 CalibType,
21 check_calib_data,
22 get_calib_paths_for_multi_shape,
23)
24from qbcompiler.version import __version__
25from qbcompiler.logging import get_logger
26
27logger = get_logger(__name__)
28
29_OUTDATED_KWARG_CONFIG_WARNING = ["is_quant_ch"]
30
31_OUTDATED_KWARG_CONFIG_ERRORS = {
32 "quant_output": "The 'quant_output' argument has been removed. Use just 'quantization_output' instead \n"
33 "output (int): Output quantization type index\n"
34 "0: Layer - Per-layer quantization\n"
35 "1: Ch - Per-channel quantization\n"
36 "2: Sigmoid - Sigmoid-based quantization\n By default, this option is set to 0 (Layer).",
37 "quantize_percentile": "The 'quantize_percentile' argument has been removed. Use just 'percentile' instead.",
38 "is_asym_quant": "'is_asym_quant' is deprecated_option, use 'quantization_method' instead, The quantization_method option only takes integers.\n"
39 "quantization_method (int): Calibration method index\n"
40 "0: Symmetric per tensor quantization\n"
41 "1: Symmetric per channel quantization\n"
42 "2: Asymmetric per tensor quantization \n"
43 "3: Asymmetric per channel quantization \n By default, this option is set to 1.",
44 "is_quant_ch": "'is_quant_ch' is deprecated_option, use 'quantization_method' instead, The quantization_method option only takes integers. \n"
45 "quantization_method (int): Calibration method index\n"
46 "0: Symmetric per tensor quantization\n"
47 "1: Symmetric per channel quantization\n"
48 "2: Asymmetric per tensor quantization \n"
49 "3: Asymmetric per channel quantization \nIf is_quant_ch is provided, quantization_method is set to 1 when True and 0 when False automatically.",
50 "smooth_factor": "'smooth_factor' is deprecated and cannot be used anymore.",
51 "quantize_method": "'quantize_method' is deprecated_option, use 'quantization_mode' instead. The quantization_mode option only takes integers.\n"
52 "quantization_mode (int): Quantization mode index\n"
53 "0: max\n"
54 "1: maxPercentile\n"
55 "2: histogram\n By default, this option is set to 1 (maxPercentile).",
56}
57
58
63
64
65class CompileConfig(ConfigABC):
66 optional = False
67 py_to_cpp_name = {
68 "calib_data_path": "calibData",
69 "save_path": "savePath",
70 "model_nickname": "modelNickname",
71 "save_msgpack_name": "saveMsgpackName",
72 "model_path": "modelPath",
73 "inference_scheme": "inferenceScheme",
74 "save_sample": "saveSample",
75 "cpu_offload": "cpuOffload",
76 "optimize_option": "optimizeOption",
77 "sample_dtype": "sampleDtype",
78 "version": "version",
79 }
80 min_max_check = {"optimize_option": [0, None]}
81 inference_scheme_types = ["single", "multi", "global", "global4", "global8", "all"]
82 sample_dtypes = ["float", "int8"]
83 """
84 @brief Unified compilation configuration object for Mobilint MXQ compilation.
85
86 @details This config consolidates compilation-related parameters and sub-config class into a single structure.
87 """
88
89 @typechecked
91 self,
92 calib_data_path: str | None,
93 use_random_calib: bool,
94 save_path: str,
95 model_nickname: str,
96 save_msgpack_name: str | None,
97 model_path: str | None,
98 inference_scheme: str,
99 save_sample: bool,
100 cpu_offload: bool,
101 optimize_option: int,
102 sample_dtype: str,
103 buffer_mode: int,
104 version: str,
105 input_shape_dict: dict,
106 resource_management: ResourceManagementConfig,
107 quantization: QuantizationConfig,
108 advanced_quantization: AdvancedQuantizationConfig,
109 llm_config: LlmConfig,
110 input_process: InputProcessConfig,
111 optional: bool = optional,
112 ):
113 """
114 @brief Unified compilation configuration object for Mobilint MXQ compilation.
115 @param calib_data_path str | None.
116 Path to calibration dataset. Accepts either:<br>
117 - a directory containing pre-processed NumPy samples, or<br>
118 - a .txt/.json meta file listing NumPy sample file paths.<br>
119 If @p use_random_calib is True, this may be None. Otherwise, a valid path is expected for
120 quantized compilation workflows.
121 @param use_random_calib bool.
122 When True, uses randomly generated calibration samples (typically for smoke testing and
123 compilability validation). When False, @p calib_data_path is used as the calibration source.
124 @param save_path str.
125 Output MXQ filename/path to generate.
126 @param model_nickname str.
127 Model nickname used as a fallback identifier when intermediate results need to be saved.
128 It is recommended to set this to the filename component of @p save_path.
129 @param save_msgpack_name str | None.
130 filename/path to save an intermediate serialized representation (msgpack) of the
131 high-level compiled model/graph. Primarily intended for debugging and is now rarely used.
132 @param model_path str | None. (deprecated) Outdated argument. Please refer to the model usage in the @p mxq_compile function.
133 @param inference_scheme str.
134 NPU inference scheme string. Must be one of:<br>
135 @c "single", @c "multi", @c "global", @c "global4", @c "global8" (@c "global" and @c "global8" behave identically).
136 @param save_sample bool.
137 When True, saves representative input/output tensors for debugging.
138 @param cpu_offload bool.
139 Enables CPU offload for unsupported operator groups/segments during NPU inference.
140 This is a beta feature and is recommended only for special cases.
141 @param optimize_option int. Compiler optimization selector.
142 @param sample_dtype string. Data type for saved sample inference outputs: "float" or "int8".
143 Primarily intended for debugging and is now rarely used.
144 @param buffer_mode int.
145 Buffer serialization mode for saving .mblt file. Common conventions:<br>
146 - 0: naïve buffer serialization<br>
147 - 1: mmap-backed buffer serialization<br>
148 @param version str. qbcompiler version.
149 @param input_shape_dict dict. Optional HWC input shape dictionary used for multi-shape compilation (for example {"input0": [[224, 224, 3], [256, 256, 3]]}).
150 @param resource_management ResourceManagementConfig.
151 Resource management configuration class.
152 @param quantization QuantizationConfig.
153 Quantization configuration class (e.g., calibration strategy, bit-widths, per-tensor/per-channel
154 settings, quantization scheme/policies).
155 @param advanced_quantization AdvancedQuantizationConfig.
156 Advanced quantization configuration block for fine-grained or experimental controls beyond the basic quantization settings.
157 @param llm_config LlmConfig. LLM-specific configuration class.
158 @param input_process InputProcessConfig. Unified input processing configuration containing
159 uint8 input handling, image channels, and preprocessing pipeline settings.
160 optional bool. Indicates whether this config is optional. Use the default value defined as a class variable.
161
162 """
163 super().__init__(optional)
165 calib_data_path, use_random_calib, input_shape_dict
166 )
167 self.save_path = save_path
168 self.model_nickname = model_nickname
169 self.save_msgpack_name = save_msgpack_name
170 self.model_path = model_path
171 self.inference_scheme = inference_scheme
172 self.save_sample = save_sample
173 self.cpu_offload = cpu_offload
174 self.optimize_option = optimize_option
175 self.sample_dtype = sample_dtype
176 self.buffer_mode = buffer_mode
177 self.version = version
178 self.input_shape_dict = input_shape_dict
179
180 # New unified config structure
181 self.resource_management = resource_management
182 self.quantization = quantization
183 self.advanced_quantization = advanced_quantization
184 self.llm_config = llm_config
185 self.input_process = input_process
186
187 self.check_valid(
188 except_list=[
189 "optional",
190 "resource_management",
191 "quantization",
192 "advanced_quantization",
193 "llm_config",
194 "input_process",
195 "calib_file",
196 "buffer_mode",
197 "input_shape_dict",
198 ]
199 )
200
201 @classmethod
202 def default_config(cls, **kwargs):
203 """
204 Create default config with optional parameter overrides.
205
206 Args:
207 **kwargs: Parameters to override defaults
208 """
209 # Default values
210 defaults = {
211 "calib_data_path": None,
212 "use_random_calib": False,
213 "save_path": "./tmp.mxq",
214 "save_msgpack_name": None,
215 "model_nickname": "temporary",
216 "model_path": None,
217 "inference_scheme": "single",
218 "save_sample": False,
219 "cpu_offload": False,
220 "optimize_option": 1,
221 "sample_dtype": "float",
222 "buffer_mode": 1,
223 "input_shape_dict": dict(),
224 "version": __version__,
225 "resource_management": ResourceManagementConfig.default_config(),
226 "quantization": QuantizationConfig.default_config(),
227 "advanced_quantization": AdvancedQuantizationConfig.default_config(),
228 "llm_config": LlmConfig.default_config(),
229 "input_process": InputProcessConfig.default_config(),
230 }
231
232 # Override with provided kwargs
233 defaults.update({k: v for k, v in kwargs.items() if v is not None})
234
235 return CompileConfig(optional=cls.optional, **defaults)
236
237 @classmethod
238 def from_json(cls, json_path: str, **kwargs):
239 """
240 Load config from JSON file and merge with additional kwargs.
241
242 Args:
243 json_path: Path to JSON configuration file
244 **kwargs: Additional compile-time parameters (calib_data_path, save_path, etc.)
245 """
246 with open(json_path, "r") as f:
247 config_dict = json.load(f)
248
249 # Load sub-configs from JSON
250 resource_management = ResourceManagementConfig.from_dict(
251 config_dict.get("resourceManagement", {})
252 )
253 quantization = QuantizationConfig.from_dict(config_dict.get("quantization", {}))
254 advanced_quantization = AdvancedQuantizationConfig.from_dict(
255 config_dict.get("advancedQuantization", {})
256 )
257 llm_config = LlmConfig.from_dict(config_dict.get("llmConfig", {}))
258 input_process = InputProcessConfig.from_dict(
259 config_dict.get("inputProcess", {})
260 )
261 input_shape_dict = config_dict.get("inputShapeDict", {})
262
263 # Merge with kwargs (compile-time parameters take precedence)
264 return cls(
265 resource_management=resource_management,
266 quantization=quantization,
267 advanced_quantization=advanced_quantization,
268 llm_config=llm_config,
269 input_process=kwargs.get("input_process", input_process),
270 input_shape_dict=kwargs.get("input_shape_dict", input_shape_dict),
271 **{
272 k: v
273 for k, v in kwargs.items()
274 if k not in ["input_shape_dict", "input_process"]
275 },
276 )
277
278 def check_valid_str_configs(self):
279 if self.save_path:
280 check_save_path(self.save_path, "mxq")
281 if self.save_msgpack_name:
282 is_valid_dir_path(self.save_msgpack_name)
283 if self.inference_scheme.lower() not in CompileConfig.inference_scheme_types:
284 raise ValueError(
285 f"Inference_scheme should be one of the {CompileConfig.inference_scheme_types}"
286 )
287 if self.sample_dtype.lower() not in CompileConfig.sample_dtypes:
288 raise ValueError(
289 f"Sample data type should be one of the {CompileConfig.sample_dtypes}"
290 )
291 if self.buffer_mode not in (0, 1):
292 raise ValueError(f"buffer mode must be either 0 or 1")
293
294 def to_dict(self):
295 compile_config_dict = dict()
296 for py_name, cpp_name in CompileConfig.py_to_cpp_name.items():
297 value = getattr(self, py_name)
298 if isinstance(value, str) and py_name in [
299 "inference_scheme",
300 "sample_dtype",
301 ]:
302 value = value.lower()
303 compile_config_dict[cpp_name] = value
304
305 # Add new unified config structure
306 compile_config_dict["quant"] = dict()
307 compile_config_dict["quant"].update(self.resource_management.to_dict())
308 compile_config_dict["quant"].update(self.quantization.to_dict())
309 compile_config_dict["quant"].update(self.advanced_quantization.to_dict())
310 compile_config_dict["quant"].update(self.llm_config.to_dict())
311 compile_config_dict["quant"].update(self.input_process.to_dict())
312 compile_config_dict["quant"]["inputShapeDict"] = self.input_shape_dict
313
314 return compile_config_dict
315
316 def _get_calibration_path(
317 self,
318 calib_data_path: str,
319 use_random_calib: bool,
320 input_shape_dict: dict = None,
321 ):
322 if not calib_data_path and not use_random_calib:
323 raise ValueError(
324 "Please use calib_data_path or enable use_random_calib. Do not leave calib_data_path empty while setting use_random_calib to false."
325 )
326 if (
327 not calib_data_path or use_random_calib
328 ): # we don't have to check the validity of calib_data_path
329 return None
330 calib_data_case = check_calib_data(calib_data_path, input_shape_dict)
331 if calib_data_case == CalibType.SINGLE_DIR:
332 self.calib_file = tempfile.NamedTemporaryFile(suffix=".txt")
333 list_calib_files_in_txt(calib_data_path, self.calib_file.name)
334 calib_data_path = self.calib_file.name
335 elif calib_data_case == CalibType.MULTI_DIR:
336 self.calib_file = tempfile.NamedTemporaryFile(suffix=".json")
337 list_calib_files_in_json(calib_data_path, self.calib_file.name)
338 calib_data_path = self.calib_file.name
339 elif calib_data_case == CalibType.MULTI_SHAPE:
340 calib_data_path = get_calib_paths_for_multi_shape(
341 calib_data_path, input_shape_dict
342 )
343 elif calib_data_case in (CalibType.SINGLE_TXT, CalibType.MULTI_JSON):
344 pass
345 else:
346 raise ValueError(f"Got unexpected calib_data_path={calib_data_path}.")
347
348 return calib_data_path
349
350
352 calib_data_path=None,
353 use_random_calib=False,
354 save_path="./tmp.mxq",
355 save_msgpack_name=None,
356 model_nickname="temporary",
357 model_path=None,
358 inference_scheme="single",
359 save_sample=False,
360 cpu_offload=False,
361 optimize_option=1,
362 sample_dtype="float",
363 buffer_mode=1,
364 input_shape_dict=dict(),
365 resource_management_config: Optional[ResourceManagementConfig] = None,
366 quantization_config: Optional[QuantizationConfig] = None,
367 llm_config: Optional[LlmConfig] = None,
368 advanced_quantization_config: Optional[AdvancedQuantizationConfig] = None,
369 input_process_config: Optional[InputProcessConfig] = None,
370 version=__version__,
371 **kwargs,
372):
373 """
374 @brief Create Compilation Config with partial parameters merged with defaults.
375 """
376 outdated_keys = _OUTDATED_KWARG_CONFIG_ERRORS.keys() & kwargs.keys()
377 if outdated_keys:
378 messages = [_OUTDATED_KWARG_CONFIG_ERRORS[k] for k in sorted(outdated_keys)]
379 full_message = "\n".join(messages)
380 warning_keys = set(_OUTDATED_KWARG_CONFIG_WARNING)
381
382 if set(outdated_keys) == warning_keys:
383 for old_argument in outdated_keys:
384 if old_argument == "is_quant_ch":
385 is_quant = bool(kwargs.get("is_quant_ch", False))
386 kwargs["quantization_method"] = 1 if is_quant else 0
387 else:
388 raise NotImplementedError(
389 f"{old_argument} should be properly mapped"
390 )
391 logger.warning(full_message)
392 else:
393 error_keys = set(outdated_keys) - warning_keys
394 if not error_keys:
395 return
396
397 error_messages = [
398 _OUTDATED_KWARG_CONFIG_ERRORS[k] for k in sorted(error_keys)
399 ]
400 error_message = "\n".join(error_messages)
401 raise ValueError(error_message)
402
403 if resource_management_config is None:
404 resource_management_config = ResourceManagementConfig.from_kwargs(**kwargs)
405 if quantization_config is None:
406 quantization_config = QuantizationConfig.from_kwargs(**kwargs)
407 if llm_config is None:
408 llm_config = LlmConfig.from_kwargs(**kwargs)
409 if advanced_quantization_config is None:
410 # AdvancedQuantizationConfig config don't use "from_kwargs" because of shared key names, such as "apply".
411 advanced_quantization_config = AdvancedQuantizationConfig.default_config()
412 if input_process_config is None:
413 input_process_config = InputProcessConfig.default_config()
414
415 return CompileConfig(
416 optional=CompileConfig.optional,
417 calib_data_path=calib_data_path,
418 use_random_calib=use_random_calib,
419 save_path=save_path,
420 save_msgpack_name=save_msgpack_name,
421 model_nickname=model_nickname,
422 model_path=model_path,
423 inference_scheme=inference_scheme,
424 save_sample=save_sample,
425 cpu_offload=cpu_offload,
426 optimize_option=optimize_option,
427 sample_dtype=sample_dtype,
428 buffer_mode=buffer_mode,
429 version=version,
430 input_shape_dict=input_shape_dict,
431 resource_management=resource_management_config,
432 quantization=quantization_config,
433 advanced_quantization=advanced_quantization_config,
434 llm_config=llm_config,
435 input_process=input_process_config,
436 )
437
438
439
from_json(cls, str json_path, **kwargs)
Load config from JSON file and merge with additional kwargs.
default_config(cls, **kwargs)
Create default config with optional parameter overrides.
__init__(self, str|None calib_data_path, bool use_random_calib, str save_path, str model_nickname, str|None save_msgpack_name, str|None model_path, str inference_scheme, bool save_sample, bool cpu_offload, int optimize_option, str sample_dtype, int buffer_mode, str version, dict input_shape_dict, ResourceManagementConfig resource_management, QuantizationConfig quantization, AdvancedQuantizationConfig advanced_quantization, LlmConfig llm_config, InputProcessConfig input_process, bool optional=optional)
Unified compilation configuration object for Mobilint MXQ compilation.
_get_calibration_path(self, str calib_data_path, bool use_random_calib, dict input_shape_dict=None)
get_compile_config(calib_data_path=None, use_random_calib=False, save_path="./tmp.mxq", save_msgpack_name=None, model_nickname="temporary", model_path=None, inference_scheme="single", save_sample=False, cpu_offload=False, optimize_option=1, sample_dtype="float", buffer_mode=1, input_shape_dict=dict(), Optional[ResourceManagementConfig] resource_management_config=None, Optional[QuantizationConfig] quantization_config=None, Optional[LlmConfig] llm_config=None, Optional[AdvancedQuantizationConfig] advanced_quantization_config=None, Optional[InputProcessConfig] input_process_config=None, version=__version__, **kwargs)
Create Compilation Config with partial parameters merged with defaults.