2222
2323import torch
2424import torch .nn as nn
25+ from safetensors import safe_open
2526from safetensors .torch import save_file
2627
28+ from modelopt .torch .quantization .nn import SequentialQuantizer , TensorQuantizer
29+ from modelopt .torch .quantization .utils .core_utils import (
30+ enable_weight_access_and_writeback ,
31+ requires_weight_materialization ,
32+ )
33+ from modelopt .torch .quantization .utils .layerwise_calib import LayerActivationCollector
34+ from modelopt .torch .utils import distributed as dist
35+
36+ from .layer_utils import is_moe , sync_moe_gate_up_amax
2737from .model_config import FUSION_FREE_FORMATS , QUANTIZATION_NVFP4
28- from .quant_utils import get_quant_config , get_quantization_format
38+ from .model_utils import TiedWeightMap
39+ from .quant_aware_conversion import build_reverse_name_mapper , revert_quant_config_names
40+ from .quant_utils import _postprocess_single_tensor , get_quant_config , get_quantization_format
41+ from .registry import ExportContext , PrepareMoEInputsRegistry
42+ from .unified_export_hf import (
43+ _add_mtp_exclusions ,
44+ _dispatch_export_handler ,
45+ _fuse_shared_input_modules ,
46+ _prepare_moe_inputs ,
47+ _resolve_export_dtype ,
48+ _write_hf_export_config ,
49+ collect_shared_input_modules ,
50+ save_non_weight_artifacts ,
51+ )
52+ from .unified_export_hf_streaming import _assert_no_split_rules
2953
3054# Fusable per layer because the groups (q/k/v, gate/up) never cross a decoder boundary.
3155# AWQ and SVDQuant also need pre-quant-scale steps, which are still whole-model.
@@ -44,8 +68,6 @@ def layer_shard_name(layer_idx: int) -> str:
4468
4569def _is_quantized_module (module : nn .Module ) -> bool :
4670 """By type, not name: fused experts name theirs ``gate_up_proj_weight_quantizer``."""
47- from modelopt .torch .quantization .nn import SequentialQuantizer , TensorQuantizer
48-
4971 return any (
5072 isinstance (child , (TensorQuantizer , SequentialQuantizer )) for child in module .children ()
5173 )
@@ -67,8 +89,6 @@ def _tied_quantized_modules(model: nn.Module) -> list[str]:
6789 weights are on meta and would pass vacuously. Falls back to ``data_ptr`` when the model
6890 publishes no map (transformers < 5).
6991 """
70- from .model_utils import TiedWeightMap
71-
7292 tied_map = TiedWeightMap (model )
7393 groups : dict [str , list [str ]] = {}
7494 by_ptr : dict [int , list [str ]] = {}
@@ -105,8 +125,6 @@ def assert_formats_supported(module: nn.Module, scope: str) -> None:
105125
106126def assert_layerwise_export_supported (model : nn .Module ) -> None :
107127 """Raise unless per-layer export is valid for this model."""
108- from modelopt .torch .utils import distributed as dist
109-
110128 assert_formats_supported (model , "before calibration" )
111129
112130 tied = _tied_quantized_modules (model )
@@ -145,14 +163,6 @@ def __init__(
145163
146164 Runs before calibration, so nothing amax-dependent exists yet.
147165 """
148- from modelopt .torch .quantization .utils .layerwise_calib import LayerActivationCollector
149-
150- from .layer_utils import is_moe
151- from .quant_aware_conversion import build_reverse_name_mapper
152- from .registry import ExportContext , PrepareMoEInputsRegistry
153- from .unified_export_hf import _resolve_export_dtype
154- from .unified_export_hf_streaming import _assert_no_split_rules
155-
156166 assert_layerwise_export_supported (model )
157167 # Splits regroup tensors across the whole state dict; no per-layer pass reverses that.
158168 _assert_no_split_rules (model )
@@ -214,10 +224,9 @@ def export_layer(
214224 a fusing format can rediscover which modules share an input; omit them only when
215225 nothing fuses.
216226 """
227+ # Local, as in every other export module: the plugin imports transformers.
217228 from modelopt .torch .quantization .plugins .huggingface import _reconstruct_fused_moe_linear
218229
219- from .unified_export_hf import _dispatch_export_handler , _prepare_moe_inputs
220-
221230 assert not self ._finalized , "export_layer() called after finalize()"
222231 if layer_module is not self ._layers [layer_idx ]:
223232 # Not an assert: -O would strip it, and the failure is silent -- layer N's
@@ -257,8 +266,6 @@ def _unify_shared_quantization_params(
257266 shared-input group, one weight_scale_2 per expert gate/up pair. Its pre-quant-scale
258267 steps are AWQ/SVDQuant-only and refused.
259268 """
260- from .layer_utils import sync_moe_gate_up_amax
261-
262269 # A set, not get_quantization_format: that stops at the first hit, so a mixed
263270 # FP8-attention/NVFP4-expert layer would report fp8 and skip fusing entirely.
264271 if _module_formats (layer_module ) - FUSION_FREE_FORMATS :
@@ -267,9 +274,6 @@ def _unify_shared_quantization_params(
267274
268275 def _fuse_shared_input_scales (self , layer_module : nn .Module , layer_inputs : list | None ) -> None :
269276 """Rediscover the groups that share an input, on real activations, and fuse them."""
270- from .quant_utils import get_quantization_format
271- from .unified_export_hf import _fuse_shared_input_modules , collect_shared_input_modules
272-
273277 layer_format = get_quantization_format (layer_module )
274278 if not layer_inputs :
275279 raise RuntimeError (
@@ -290,19 +294,6 @@ def finalize(self) -> dict:
290294
291295 Leaves ``export_dir`` a complete checkpoint; no ``export_hf_checkpoint()`` needed.
292296 """
293- from modelopt .torch .quantization .utils .core_utils import (
294- enable_weight_access_and_writeback ,
295- requires_weight_materialization ,
296- )
297-
298- from .quant_aware_conversion import revert_quant_config_names
299- from .unified_export_hf import (
300- _add_mtp_exclusions ,
301- _dispatch_export_handler ,
302- _write_hf_export_config ,
303- save_non_weight_artifacts ,
304- )
305-
306297 assert not self ._finalized , "finalize() called twice"
307298 self ._finalized = True
308299
@@ -407,8 +398,6 @@ def assert_shards_present(self, upto: int) -> None:
407398
408399 def _collect (self , out : dict [str , torch .Tensor ], full_key : str , tensor : torch .Tensor ) -> None :
409400 """Apply per-tensor export postprocessing and hub-name reversal, or drop the tensor."""
410- from .quant_utils import _postprocess_single_tensor
411-
412401 if tensor is None or tensor .is_meta :
413402 return
414403 new_key , new_value = _postprocess_single_tensor (
@@ -426,8 +415,6 @@ def _write_index(self) -> None:
426415 From disk because a resumed run never saw the earlier shards in memory; by layer
427416 count rather than a glob, so a longer previous run's leftovers cannot leak in.
428417 """
429- from safetensors import safe_open
430-
431418 # Out of the index already; delete them so the directory *is* the checkpoint.
432419 for stale in self ._export_dir .glob ("model-layer-*.safetensors" ):
433420 if int (stale .stem .rsplit ("-" , 1 )[1 ]) >= len (self ._layers ):
0 commit comments