@@ -561,6 +561,10 @@ def validate_quantizer_cfg_entry(cls, values):
561561 "Each quant_cfg entry must specify 'cfg', 'enable', or both. "
562562 "An entry with only 'quantizer_name' has no effect."
563563 )
564+ if "cfg" in values and values ["cfg" ] is None :
565+ raise ValueError ("cfg must be omitted or a valid mapping/list, not null." )
566+ if "enable" in values and values ["enable" ] is None :
567+ raise ValueError ("enable must be a boolean when provided, not null." )
564568
565569 cfg = values .get ("cfg" )
566570 enable = values .get ("enable" , True )
@@ -1008,15 +1012,15 @@ class GPTQCalibConfig(QuantizeAlgorithmConfig):
10081012
10091013
10101014QuantizerCfgListConfig = list [QuantizerCfgEntry ]
1011- QuantizeQuantCfgInputType = Sequence [QuantizerCfgEntry | Mapping [str , Any ]]
1015+ QuantizeQuantCfgInputType = Mapping [ str , Any ] | Sequence [QuantizerCfgEntry | Mapping [str , Any ]]
10121016
10131017_QuantizeAlgoCfgType = str | dict | QuantizeAlgorithmConfig | None
10141018
10151019QuantizeAlgoCfgType = _QuantizeAlgoCfgType | list [_QuantizeAlgoCfgType ] | None
10161020
10171021
10181022def normalize_quant_cfg_list (
1019- v : Mapping [str , Any ] | list [QuantizerCfgEntry | Mapping [str , Any ]],
1023+ v : Mapping [str , Any ] | Sequence [QuantizerCfgEntry | Mapping [str , Any ]],
10201024) -> list [QuantizerCfgEntry ]:
10211025 """Normalize a raw quant_cfg into a list of :class:`QuantizerCfgEntry` objects.
10221026
@@ -1099,15 +1103,19 @@ def _dict_to_entry(key: str, value: Any) -> list[dict[str, Any]]:
10991103 if isinstance (sub_cfg , QuantizerAttributeConfig ):
11001104 enable = None
11011105 cfg = sub_cfg
1102- else :
1106+ elif isinstance ( sub_cfg , Mapping ) :
11031107 sub_cfg = dict (sub_cfg )
11041108 enable = sub_cfg .pop ("enable" , None )
11051109 cfg = sub_cfg or None
1110+ else :
1111+ enable = None
1112+ cfg = sub_cfg
11061113 entry : dict [str , Any ] = {
11071114 "parent_class" : key ,
11081115 "quantizer_name" : q_path ,
1109- "cfg" : cfg ,
11101116 }
1117+ if cfg is not None :
1118+ entry ["cfg" ] = cfg
11111119 if enable is not None :
11121120 entry ["enable" ] = enable
11131121 entries .append (entry )
@@ -1119,7 +1127,9 @@ def _dict_to_entry(key: str, value: Any) -> list[dict[str, Any]]:
11191127 else :
11201128 cfg = value
11211129 enable = None
1122- entry = {"quantizer_name" : key , "cfg" : cfg }
1130+ entry = {"quantizer_name" : key }
1131+ if cfg is not None :
1132+ entry ["cfg" ] = cfg
11231133 if enable is not None :
11241134 entry ["enable" ] = enable
11251135 return [entry ]
@@ -1165,6 +1175,17 @@ def _dict_to_entry(key: str, value: Any) -> list[dict[str, Any]]:
11651175 # Validate: when cfg is present and enable=True, cfg must be a non-empty
11661176 # dict or list. An empty cfg would attempt to create a
11671177 # QuantizerAttributeConfig with no actual configuration.
1178+ if "cfg" in entry and entry ["cfg" ] is None :
1179+ raise ValueError (
1180+ f"Invalid quant_cfg entry: { raw !r} - 'cfg' must be omitted or a "
1181+ "valid mapping/list, not null."
1182+ )
1183+ if "enable" in entry and entry ["enable" ] is None :
1184+ raise ValueError (
1185+ f"Invalid quant_cfg entry: { raw !r} - 'enable' must be a boolean "
1186+ "when provided, not null."
1187+ )
1188+
11681189 cfg = entry .get ("cfg" )
11691190 enable = entry .get ("enable" , True )
11701191 if enable and cfg is not None :
@@ -1190,9 +1211,8 @@ def _dict_to_entry(key: str, value: Any) -> list[dict[str, Any]]:
11901211 "explicitly."
11911212 )
11921213
1193- # Normalize: make enable and cfg always explicit .
1214+ # Normalize: make enable explicit. cfg remains omitted when it is intentionally unset .
11941215 entry .setdefault ("enable" , True )
1195- entry .setdefault ("cfg" , None )
11961216
11971217 result .append (QuantizerCfgEntry .model_validate (entry ))
11981218 return result
@@ -1201,6 +1221,18 @@ def _dict_to_entry(key: str, value: Any) -> list[dict[str, Any]]:
12011221class QuantizeConfig (ModeloptBaseConfig ):
12021222 """Default configuration for ``quantize`` mode."""
12031223
1224+ def model_dump (self , ** kwargs ):
1225+ """Dump quant_cfg entries without unset optional fields."""
1226+ data = super ().model_dump (** kwargs )
1227+ if "quant_cfg" in data :
1228+ data ["quant_cfg" ] = [
1229+ entry .model_dump (exclude_unset = True )
1230+ if isinstance (entry , QuantizerCfgEntry )
1231+ else {k : v for k , v in entry .items () if v is not None }
1232+ for entry in self .quant_cfg
1233+ ]
1234+ return data
1235+
12041236 quant_cfg : QuantizerCfgListConfig = ModeloptField (
12051237 default = [{"quantizer_name" : "*" , "cfg" : {"num_bits" : 8 , "axis" : None }}],
12061238 title = "Quantization configuration" ,
0 commit comments