compile_config.py Source File

compile_config.py Source File#

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