nvidia-modelopt 0.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelopt/__init__.py +20 -0
- modelopt/deploy/__init__.py +16 -0
- modelopt/deploy/llm/__init__.py +30 -0
- modelopt/deploy/llm/generate.py +345 -0
- modelopt/onnx/__init__.py +34 -0
- modelopt/onnx/autocast/__init__.py +19 -0
- modelopt/onnx/autocast/__main__.py +187 -0
- modelopt/onnx/autocast/convert.py +202 -0
- modelopt/onnx/autocast/graphsanitizer.py +422 -0
- modelopt/onnx/autocast/logging_config.py +78 -0
- modelopt/onnx/autocast/nodeclassifier.py +416 -0
- modelopt/onnx/autocast/precisionconverter.py +1032 -0
- modelopt/onnx/autocast/referencerunner.py +159 -0
- modelopt/onnx/autocast/utils.py +117 -0
- modelopt/onnx/llm_export_utils/__init__.py +16 -0
- modelopt/onnx/llm_export_utils/export_utils.py +162 -0
- modelopt/onnx/llm_export_utils/quantization_utils.py +122 -0
- modelopt/onnx/llm_export_utils/surgeon_utils.py +120 -0
- modelopt/onnx/logging_config.py +77 -0
- modelopt/onnx/op_types.py +300 -0
- modelopt/onnx/quantization/__init__.py +20 -0
- modelopt/onnx/quantization/__main__.py +291 -0
- modelopt/onnx/quantization/calib_utils.py +178 -0
- modelopt/onnx/quantization/extensions.py +35 -0
- modelopt/onnx/quantization/fp8.py +375 -0
- modelopt/onnx/quantization/graph_utils.py +1479 -0
- modelopt/onnx/quantization/gs_patching.py +112 -0
- modelopt/onnx/quantization/int4.py +1347 -0
- modelopt/onnx/quantization/int8.py +283 -0
- modelopt/onnx/quantization/operators.py +121 -0
- modelopt/onnx/quantization/ort_patching.py +1766 -0
- modelopt/onnx/quantization/ort_utils.py +346 -0
- modelopt/onnx/quantization/partitioning.py +439 -0
- modelopt/onnx/quantization/qdq_utils.py +1349 -0
- modelopt/onnx/quantization/quant_utils.py +283 -0
- modelopt/onnx/quantization/quantize.py +528 -0
- modelopt/onnx/quantization/src/modelopt_round_and_pack_ext.cpp +127 -0
- modelopt/onnx/trt_utils.py +424 -0
- modelopt/onnx/utils.py +753 -0
- modelopt/torch/__init__.py +41 -0
- modelopt/torch/_deploy/__init__.py +23 -0
- modelopt/torch/_deploy/_runtime/__init__.py +29 -0
- modelopt/torch/_deploy/_runtime/common.py +72 -0
- modelopt/torch/_deploy/_runtime/ort_client.py +193 -0
- modelopt/torch/_deploy/_runtime/registry.py +83 -0
- modelopt/torch/_deploy/_runtime/runtime_client.py +154 -0
- modelopt/torch/_deploy/_runtime/tensorrt/constants.py +108 -0
- modelopt/torch/_deploy/_runtime/tensorrt/engine_builder.py +324 -0
- modelopt/torch/_deploy/_runtime/tensorrt/hw_param_config.py +51 -0
- modelopt/torch/_deploy/_runtime/tensorrt/layerwise_profiling.py +178 -0
- modelopt/torch/_deploy/_runtime/tensorrt/parse_trtexec_log.py +151 -0
- modelopt/torch/_deploy/_runtime/tensorrt/tensorrt_utils.py +200 -0
- modelopt/torch/_deploy/_runtime/trt_client.py +219 -0
- modelopt/torch/_deploy/compilation.py +142 -0
- modelopt/torch/_deploy/device_model.py +157 -0
- modelopt/torch/_deploy/profiling.py +193 -0
- modelopt/torch/_deploy/utils/__init__.py +18 -0
- modelopt/torch/_deploy/utils/onnx_optimizer.py +120 -0
- modelopt/torch/_deploy/utils/onnx_utils.py +58 -0
- modelopt/torch/_deploy/utils/torch_onnx.py +593 -0
- modelopt/torch/distill/__init__.py +28 -0
- modelopt/torch/distill/config.py +130 -0
- modelopt/torch/distill/distillation.py +84 -0
- modelopt/torch/distill/distillation_model.py +318 -0
- modelopt/torch/distill/loss_balancers.py +140 -0
- modelopt/torch/distill/losses.py +275 -0
- modelopt/torch/distill/mode.py +223 -0
- modelopt/torch/distill/plugins/__init__.py +24 -0
- modelopt/torch/distill/plugins/huggingface.py +110 -0
- modelopt/torch/distill/plugins/megatron.py +476 -0
- modelopt/torch/distill/registry.py +23 -0
- modelopt/torch/export/__init__.py +24 -0
- modelopt/torch/export/convert_hf_config.py +117 -0
- modelopt/torch/export/distribute.py +300 -0
- modelopt/torch/export/hf_config_map.py +84 -0
- modelopt/torch/export/layer_utils.py +1893 -0
- modelopt/torch/export/mcore_config_map.py +25 -0
- modelopt/torch/export/model_config.py +623 -0
- modelopt/torch/export/model_config_export.py +552 -0
- modelopt/torch/export/model_config_utils.py +392 -0
- modelopt/torch/export/model_utils.py +71 -0
- modelopt/torch/export/plugins/__init__.py +21 -0
- modelopt/torch/export/plugins/mcore_common.py +67 -0
- modelopt/torch/export/plugins/mcore_custom.py +530 -0
- modelopt/torch/export/plugins/mcore_deepseek.py +143 -0
- modelopt/torch/export/plugins/mcore_gptoss.py +71 -0
- modelopt/torch/export/plugins/mcore_llama.py +164 -0
- modelopt/torch/export/plugins/mcore_nemotron.py +90 -0
- modelopt/torch/export/plugins/mcore_qwen.py +99 -0
- modelopt/torch/export/plugins/megatron_importer.py +647 -0
- modelopt/torch/export/postprocess.py +847 -0
- modelopt/torch/export/quant_utils.py +1069 -0
- modelopt/torch/export/tensorrt_llm_type.py +42 -0
- modelopt/torch/export/tensorrt_llm_utils.py +405 -0
- modelopt/torch/export/transformer_engine.py +94 -0
- modelopt/torch/export/unified_export_hf.py +537 -0
- modelopt/torch/export/unified_export_megatron.py +1164 -0
- modelopt/torch/nas/__init__.py +27 -0
- modelopt/torch/nas/algorithms.py +856 -0
- modelopt/torch/nas/autonas.py +808 -0
- modelopt/torch/nas/conversion.py +119 -0
- modelopt/torch/nas/hparams/__init__.py +19 -0
- modelopt/torch/nas/hparams/concat.py +319 -0
- modelopt/torch/nas/hparams/container.py +48 -0
- modelopt/torch/nas/modules/__init__.py +21 -0
- modelopt/torch/nas/modules/container.py +99 -0
- modelopt/torch/nas/modules/conv.py +254 -0
- modelopt/torch/nas/modules/linear.py +76 -0
- modelopt/torch/nas/modules/norm.py +193 -0
- modelopt/torch/nas/modules/utils.py +61 -0
- modelopt/torch/nas/patch.py +261 -0
- modelopt/torch/nas/plugins/__init__.py +29 -0
- modelopt/torch/nas/plugins/megatron.py +1497 -0
- modelopt/torch/nas/plugins/torch.py +71 -0
- modelopt/torch/nas/plugins/transformer_engine.py +42 -0
- modelopt/torch/nas/plugins/transformers.py +210 -0
- modelopt/torch/nas/registry.py +23 -0
- modelopt/torch/nas/search_space.py +260 -0
- modelopt/torch/nas/traced_hp.py +149 -0
- modelopt/torch/nas/utils.py +408 -0
- modelopt/torch/opt/__init__.py +41 -0
- modelopt/torch/opt/_hooks.py +98 -0
- modelopt/torch/opt/config.py +383 -0
- modelopt/torch/opt/conversion.py +620 -0
- modelopt/torch/opt/dynamic.py +1367 -0
- modelopt/torch/opt/hparam.py +275 -0
- modelopt/torch/opt/mode.py +353 -0
- modelopt/torch/opt/plugins/__init__.py +38 -0
- modelopt/torch/opt/plugins/diffusers.py +40 -0
- modelopt/torch/opt/plugins/huggingface.py +162 -0
- modelopt/torch/opt/plugins/mcore_dist_checkpointing.py +211 -0
- modelopt/torch/opt/plugins/megatron.py +142 -0
- modelopt/torch/opt/plugins/peft.py +108 -0
- modelopt/torch/opt/plugins/transformers.py +160 -0
- modelopt/torch/opt/searcher.py +363 -0
- modelopt/torch/opt/utils.py +125 -0
- modelopt/torch/prune/__init__.py +26 -0
- modelopt/torch/prune/fastnas.py +376 -0
- modelopt/torch/prune/gradnas.py +349 -0
- modelopt/torch/prune/plugins/__init__.py +24 -0
- modelopt/torch/prune/plugins/mcore_minitron.py +263 -0
- modelopt/torch/prune/plugins/transformers.py +41 -0
- modelopt/torch/prune/pruning.py +211 -0
- modelopt/torch/quantization/__init__.py +26 -0
- modelopt/torch/quantization/algorithms.py +671 -0
- modelopt/torch/quantization/backends/__init__.py +20 -0
- modelopt/torch/quantization/backends/fp8_per_tensor_gemm.py +204 -0
- modelopt/torch/quantization/backends/gemm_registry.py +156 -0
- modelopt/torch/quantization/backends/nvfp4_gemm.py +201 -0
- modelopt/torch/quantization/backends/utils.py +28 -0
- modelopt/torch/quantization/calib/__init__.py +25 -0
- modelopt/torch/quantization/calib/bias.py +172 -0
- modelopt/torch/quantization/calib/calibrator.py +63 -0
- modelopt/torch/quantization/calib/histogram.py +434 -0
- modelopt/torch/quantization/calib/max.py +110 -0
- modelopt/torch/quantization/compress.py +227 -0
- modelopt/torch/quantization/config.py +1180 -0
- modelopt/torch/quantization/conversion.py +389 -0
- modelopt/torch/quantization/export_onnx.py +639 -0
- modelopt/torch/quantization/extensions.py +89 -0
- modelopt/torch/quantization/mode.py +428 -0
- modelopt/torch/quantization/model_calib.py +949 -0
- modelopt/torch/quantization/model_quant.py +477 -0
- modelopt/torch/quantization/nn/__init__.py +26 -0
- modelopt/torch/quantization/nn/functional.py +109 -0
- modelopt/torch/quantization/nn/modules/__init__.py +16 -0
- modelopt/torch/quantization/nn/modules/quant_activations.py +22 -0
- modelopt/torch/quantization/nn/modules/quant_batchnorm.py +24 -0
- modelopt/torch/quantization/nn/modules/quant_conv.py +123 -0
- modelopt/torch/quantization/nn/modules/quant_instancenorm.py +39 -0
- modelopt/torch/quantization/nn/modules/quant_linear.py +258 -0
- modelopt/torch/quantization/nn/modules/quant_module.py +211 -0
- modelopt/torch/quantization/nn/modules/quant_pooling.py +99 -0
- modelopt/torch/quantization/nn/modules/quant_rnn.py +527 -0
- modelopt/torch/quantization/nn/modules/tensor_quantizer.py +1293 -0
- modelopt/torch/quantization/plugins/__init__.py +73 -0
- modelopt/torch/quantization/plugins/accelerate.py +214 -0
- modelopt/torch/quantization/plugins/apex.py +52 -0
- modelopt/torch/quantization/plugins/attention.py +312 -0
- modelopt/torch/quantization/plugins/custom.py +192 -0
- modelopt/torch/quantization/plugins/diffusers.py +237 -0
- modelopt/torch/quantization/plugins/fairscale.py +45 -0
- modelopt/torch/quantization/plugins/huggingface.py +736 -0
- modelopt/torch/quantization/plugins/megatron.py +462 -0
- modelopt/torch/quantization/plugins/peft.py +148 -0
- modelopt/torch/quantization/plugins/transformer_engine.py +60 -0
- modelopt/torch/quantization/plugins/transformers.py +52 -0
- modelopt/torch/quantization/plugins/transformers_trainer.py +426 -0
- modelopt/torch/quantization/plugins/trl.py +27 -0
- modelopt/torch/quantization/plugins/vllm.py +199 -0
- modelopt/torch/quantization/qtensor/__init__.py +24 -0
- modelopt/torch/quantization/qtensor/base_qtensor.py +370 -0
- modelopt/torch/quantization/qtensor/fp8_tensor.py +151 -0
- modelopt/torch/quantization/qtensor/int4_tensor.py +130 -0
- modelopt/torch/quantization/qtensor/int8_tensor.py +124 -0
- modelopt/torch/quantization/qtensor/mxfp4_tensor.py +144 -0
- modelopt/torch/quantization/qtensor/nf4_tensor.py +199 -0
- modelopt/torch/quantization/qtensor/nvfp4_tensor.py +295 -0
- modelopt/torch/quantization/src/tensor_quant.cpp +77 -0
- modelopt/torch/quantization/src/tensor_quant.h +69 -0
- modelopt/torch/quantization/src/tensor_quant_fp8.cpp +48 -0
- modelopt/torch/quantization/src/tensor_quant_gpu.cu +361 -0
- modelopt/torch/quantization/src/tensor_quant_gpu_fp8.cu +122 -0
- modelopt/torch/quantization/src/tensor_quant_mx.cu +411 -0
- modelopt/torch/quantization/src/tensor_quant_mx.h +247 -0
- modelopt/torch/quantization/tensor_quant.py +816 -0
- modelopt/torch/quantization/triton/__init__.py +36 -0
- modelopt/torch/quantization/triton/fp4_kernel.py +303 -0
- modelopt/torch/quantization/utils.py +443 -0
- modelopt/torch/sparsity/__init__.py +19 -0
- modelopt/torch/sparsity/config.py +51 -0
- modelopt/torch/sparsity/magnitude.py +148 -0
- modelopt/torch/sparsity/mode.py +203 -0
- modelopt/torch/sparsity/module.py +87 -0
- modelopt/torch/sparsity/plugins/__init__.py +27 -0
- modelopt/torch/sparsity/plugins/megatron.py +93 -0
- modelopt/torch/sparsity/searcher.py +84 -0
- modelopt/torch/sparsity/sparsegpt.py +276 -0
- modelopt/torch/sparsity/sparsification.py +123 -0
- modelopt/torch/speculative/__init__.py +20 -0
- modelopt/torch/speculative/config.py +100 -0
- modelopt/torch/speculative/eagle/__init__.py +20 -0
- modelopt/torch/speculative/eagle/conversion.py +67 -0
- modelopt/torch/speculative/eagle/default_config.py +50 -0
- modelopt/torch/speculative/eagle/eagle_model.py +51 -0
- modelopt/torch/speculative/eagle/utils.py +91 -0
- modelopt/torch/speculative/medusa/__init__.py +19 -0
- modelopt/torch/speculative/medusa/conversion.py +59 -0
- modelopt/torch/speculative/medusa/medusa_model.py +32 -0
- modelopt/torch/speculative/mode.py +86 -0
- modelopt/torch/speculative/plugins/__init__.py +33 -0
- modelopt/torch/speculative/plugins/megatron_eagle.py +2119 -0
- modelopt/torch/speculative/plugins/megatron_medusa.py +312 -0
- modelopt/torch/speculative/plugins/transformers.py +1138 -0
- modelopt/torch/speculative/speculative_decoding.py +59 -0
- modelopt/torch/speculative/utils.py +364 -0
- modelopt/torch/trace/__init__.py +25 -0
- modelopt/torch/trace/analyzer.py +1368 -0
- modelopt/torch/trace/modules/__init__.py +19 -0
- modelopt/torch/trace/modules/concat.py +384 -0
- modelopt/torch/trace/modules/nn.py +153 -0
- modelopt/torch/trace/plugins/__init__.py +34 -0
- modelopt/torch/trace/plugins/megatron.py +36 -0
- modelopt/torch/trace/plugins/transformers.py +58 -0
- modelopt/torch/trace/symbols.py +545 -0
- modelopt/torch/trace/tracer.py +331 -0
- modelopt/torch/utils/__init__.py +28 -0
- modelopt/torch/utils/_pytree.py +133 -0
- modelopt/torch/utils/cpp_extension.py +91 -0
- modelopt/torch/utils/dataset_utils.py +484 -0
- modelopt/torch/utils/distributed.py +311 -0
- modelopt/torch/utils/graph.py +123 -0
- modelopt/torch/utils/image_processor.py +112 -0
- modelopt/torch/utils/import_utils.py +35 -0
- modelopt/torch/utils/list.py +54 -0
- modelopt/torch/utils/logging.py +127 -0
- modelopt/torch/utils/memory_monitor.py +146 -0
- modelopt/torch/utils/network.py +658 -0
- modelopt/torch/utils/perf.py +174 -0
- modelopt/torch/utils/plugins/__init__.py +27 -0
- modelopt/torch/utils/plugins/megatron_generate.py +299 -0
- modelopt/torch/utils/plugins/megatron_mmlu.py +152 -0
- modelopt/torch/utils/plugins/megatron_preprocess_data.py +200 -0
- modelopt/torch/utils/random.py +163 -0
- modelopt/torch/utils/speech_dataset_utils.py +134 -0
- modelopt/torch/utils/tensor.py +87 -0
- modelopt/torch/utils/vlm_dataset_utils.py +110 -0
- nvidia_modelopt-0.35.0.dist-info/METADATA +171 -0
- nvidia_modelopt-0.35.0.dist-info/RECORD +272 -0
- nvidia_modelopt-0.35.0.dist-info/WHEEL +5 -0
- nvidia_modelopt-0.35.0.dist-info/licenses/LICENSE +14 -0
- nvidia_modelopt-0.35.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Code that export quantized Hugging Face models for deployment."""
|
|
17
|
+
|
|
18
|
+
import collections.abc
|
|
19
|
+
import json
|
|
20
|
+
import re
|
|
21
|
+
import tempfile
|
|
22
|
+
import warnings
|
|
23
|
+
from collections import defaultdict
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
27
|
+
import torch
|
|
28
|
+
import torch.nn as nn
|
|
29
|
+
|
|
30
|
+
from modelopt.torch.quantization import set_quantizer_by_cfg_context
|
|
31
|
+
from modelopt.torch.quantization.nn import SequentialQuantizer, TensorQuantizer
|
|
32
|
+
from modelopt.torch.quantization.qtensor import NVFP4QTensor
|
|
33
|
+
from modelopt.torch.quantization.utils import quantizer_attr_names
|
|
34
|
+
|
|
35
|
+
from .convert_hf_config import convert_hf_quant_config_format
|
|
36
|
+
from .layer_utils import (
|
|
37
|
+
get_expert_linear_names,
|
|
38
|
+
get_experts_list,
|
|
39
|
+
is_layernorm,
|
|
40
|
+
is_moe,
|
|
41
|
+
is_quantlinear,
|
|
42
|
+
set_expert_quantizer_amax,
|
|
43
|
+
)
|
|
44
|
+
from .model_config import (
|
|
45
|
+
KV_CACHE_FP8,
|
|
46
|
+
KV_CACHE_NVFP4,
|
|
47
|
+
KV_CACHE_NVFP4_AFFINE,
|
|
48
|
+
QUANTIZATION_FP8,
|
|
49
|
+
QUANTIZATION_FP8_PB_REAL,
|
|
50
|
+
QUANTIZATION_NONE,
|
|
51
|
+
QUANTIZATION_NVFP4,
|
|
52
|
+
QUANTIZATION_NVFP4_AWQ,
|
|
53
|
+
QUANTIZATION_W4A8_AWQ,
|
|
54
|
+
)
|
|
55
|
+
from .quant_utils import (
|
|
56
|
+
fuse_prequant_layernorm,
|
|
57
|
+
get_activation_scaling_factor,
|
|
58
|
+
get_quant_config,
|
|
59
|
+
get_quantization_format,
|
|
60
|
+
get_weight_block_size,
|
|
61
|
+
get_weight_scaling_factor,
|
|
62
|
+
get_weight_scaling_factor_2,
|
|
63
|
+
maybe_transpose_expert_weight_dimensions,
|
|
64
|
+
postprocess_state_dict,
|
|
65
|
+
preprocess_linear_fusion,
|
|
66
|
+
to_quantized_weight,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
__all__ = ["export_hf_checkpoint"]
|
|
70
|
+
|
|
71
|
+
SPECULATIVE_DECODING_MODULE_NAMES = ["medusa_heads", "eagle_module", "drafter"]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _is_enabled_quantizer(quantizer):
|
|
75
|
+
if hasattr(quantizer, "is_enabled") and quantizer.is_enabled:
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
if isinstance(quantizer, SequentialQuantizer):
|
|
79
|
+
return any(q.is_enabled for q in quantizer)
|
|
80
|
+
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def requantize_resmooth_fused_llm_layers(model: torch.nn.Module):
|
|
85
|
+
"""Group modules that take the same input and register shared parameters in module."""
|
|
86
|
+
# TODO: Handle DBRX MoE
|
|
87
|
+
input_to_linear = defaultdict(list)
|
|
88
|
+
output_to_layernorm = defaultdict(None)
|
|
89
|
+
quantization_format = get_quantization_format(model)
|
|
90
|
+
|
|
91
|
+
def _input_hook(module, input, output):
|
|
92
|
+
"""Update dictionary with list of all modules that share the same input."""
|
|
93
|
+
# TODO: Handle DBRX MoE case
|
|
94
|
+
input_to_linear[input[0]].append(module)
|
|
95
|
+
|
|
96
|
+
def _output_hook(module, input, output):
|
|
97
|
+
"""Update dictionary with mapping of layernorms and their outputs."""
|
|
98
|
+
output_to_layernorm[output] = module
|
|
99
|
+
|
|
100
|
+
handles = []
|
|
101
|
+
model_type = type(model).__name__.lower()
|
|
102
|
+
|
|
103
|
+
fused_linears = {}
|
|
104
|
+
module_names = set()
|
|
105
|
+
|
|
106
|
+
for name, module in model.named_modules():
|
|
107
|
+
module_names.add(name)
|
|
108
|
+
|
|
109
|
+
# For MoE models update pre_quant_scale to average pre_quant_scale amongst experts
|
|
110
|
+
if is_moe(module) and ("awq" in quantization_format):
|
|
111
|
+
# update_experts_avg_prequant_scale(module)
|
|
112
|
+
grouped_experts = get_experts_list(module, model_type)
|
|
113
|
+
for modules in grouped_experts:
|
|
114
|
+
preprocess_linear_fusion(modules, resmooth_only=True)
|
|
115
|
+
|
|
116
|
+
# Attach hook to layernorm modules that need to be fused
|
|
117
|
+
if is_layernorm(module):
|
|
118
|
+
module.name = name
|
|
119
|
+
handle = module.register_forward_hook(_output_hook)
|
|
120
|
+
handles.append(handle)
|
|
121
|
+
elif is_quantlinear(module) and (
|
|
122
|
+
_is_enabled_quantizer(module.input_quantizer)
|
|
123
|
+
or _is_enabled_quantizer(module.weight_quantizer)
|
|
124
|
+
):
|
|
125
|
+
module.name = name
|
|
126
|
+
handle = module.register_forward_hook(_input_hook)
|
|
127
|
+
handles.append(handle)
|
|
128
|
+
|
|
129
|
+
with torch.no_grad():
|
|
130
|
+
fake_input = torch.ones([1, 2], dtype=torch.long).to(model.device)
|
|
131
|
+
decoder_fake_input = fake_input
|
|
132
|
+
if model_type.startswith("whisper"):
|
|
133
|
+
# For Whisper models, we need to pass a fake input with the specific sequence length
|
|
134
|
+
from transformers import AutoFeatureExtractor
|
|
135
|
+
|
|
136
|
+
feature_extractor = AutoFeatureExtractor.from_pretrained(model.name_or_path)
|
|
137
|
+
fake_input = torch.ones(
|
|
138
|
+
[1, model.config.num_mel_bins, feature_extractor.nb_max_frames], dtype=model.dtype
|
|
139
|
+
).to(model.device)
|
|
140
|
+
|
|
141
|
+
# Run forward pass so that all modules sharing the same input are collected using forward hook.
|
|
142
|
+
|
|
143
|
+
with set_quantizer_by_cfg_context(model, {"*": {"enable": False}}):
|
|
144
|
+
if getattr(model.config, "is_encoder_decoder", False):
|
|
145
|
+
# For encoder-decoder models, we need to pass both the encoder and decoder input ids
|
|
146
|
+
model(fake_input, decoder_input_ids=decoder_fake_input)
|
|
147
|
+
else:
|
|
148
|
+
model(fake_input)
|
|
149
|
+
|
|
150
|
+
for handle in handles:
|
|
151
|
+
handle.remove()
|
|
152
|
+
|
|
153
|
+
for tensor, modules in input_to_linear.items():
|
|
154
|
+
quantization_format = get_quantization_format(modules[0])
|
|
155
|
+
if len(modules) > 1 and quantization_format not in [
|
|
156
|
+
QUANTIZATION_FP8,
|
|
157
|
+
QUANTIZATION_NONE,
|
|
158
|
+
QUANTIZATION_FP8_PB_REAL,
|
|
159
|
+
]:
|
|
160
|
+
# Fuse modules that have the same input
|
|
161
|
+
preprocess_linear_fusion(modules)
|
|
162
|
+
fused_linears[modules[0].name] = [module.name for module in modules]
|
|
163
|
+
|
|
164
|
+
# Fuse layernorms
|
|
165
|
+
if (
|
|
166
|
+
quantization_format is not QUANTIZATION_NONE
|
|
167
|
+
and "awq" in quantization_format
|
|
168
|
+
and tensor in output_to_layernorm
|
|
169
|
+
):
|
|
170
|
+
# Pre quant scale of modules is already updated to avg_pre_quant_scale
|
|
171
|
+
fuse_prequant_layernorm(output_to_layernorm[tensor], modules)
|
|
172
|
+
|
|
173
|
+
# The dummy forward may not be able to activate all the experts.
|
|
174
|
+
# Process experts by naming rules like experts.0, experts.1, etc.
|
|
175
|
+
for name, modules_fused in fused_linears.items():
|
|
176
|
+
if re.search(r"experts?\.\d+", name):
|
|
177
|
+
expert_id = 0
|
|
178
|
+
while True:
|
|
179
|
+
new_expert_name = re.sub(r"(experts?\.)\d+", rf"\g<1>{expert_id}", name, count=1)
|
|
180
|
+
if new_expert_name in fused_linears:
|
|
181
|
+
expert_id += 1
|
|
182
|
+
continue
|
|
183
|
+
if new_expert_name not in module_names:
|
|
184
|
+
break
|
|
185
|
+
|
|
186
|
+
new_expert_modules = []
|
|
187
|
+
for name_fused in modules_fused:
|
|
188
|
+
new_expert_name = re.sub(r"(experts?\.)\d+", rf"\g<1>{expert_id}", name_fused)
|
|
189
|
+
assert new_expert_name in module_names
|
|
190
|
+
new_expert_modules.append(model.get_submodule(new_expert_name))
|
|
191
|
+
|
|
192
|
+
preprocess_linear_fusion(new_expert_modules)
|
|
193
|
+
|
|
194
|
+
expert_id += 1
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _export_quantized_weight(
|
|
198
|
+
sub_module: nn.Module, dtype: torch.dtype, weight_name: str = "weight"
|
|
199
|
+
):
|
|
200
|
+
"""For the given weight attr of the sub_module, export the quantization info of it.
|
|
201
|
+
|
|
202
|
+
The export includes converting weight tensor to correct quantized values and quantized dtype,
|
|
203
|
+
and registering scaling factors.
|
|
204
|
+
"""
|
|
205
|
+
quantization_format = get_quantization_format(sub_module)
|
|
206
|
+
if quantization_format == QUANTIZATION_NONE:
|
|
207
|
+
return
|
|
208
|
+
|
|
209
|
+
block_size = get_weight_block_size(sub_module, weight_name)
|
|
210
|
+
quantizer_attrs = quantizer_attr_names(weight_name)
|
|
211
|
+
weight: nn.Parameter = getattr(sub_module, weight_name)
|
|
212
|
+
weight_quantizer: TensorQuantizer | SequentialQuantizer = getattr(
|
|
213
|
+
sub_module, quantizer_attrs.weight_quantizer
|
|
214
|
+
)
|
|
215
|
+
input_quantizer: TensorQuantizer | SequentialQuantizer | None = getattr(
|
|
216
|
+
sub_module, quantizer_attrs.input_quantizer, None
|
|
217
|
+
)
|
|
218
|
+
output_quantizer: TensorQuantizer | SequentialQuantizer | None = getattr(
|
|
219
|
+
sub_module, quantizer_attrs.output_quantizer, None
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
if quantization_format == QUANTIZATION_FP8:
|
|
223
|
+
# Convert amax to float32
|
|
224
|
+
weight_quantizer._amax = weight_quantizer._amax.to(torch.float32)
|
|
225
|
+
|
|
226
|
+
if weight_quantizer._amax.dim() == 1:
|
|
227
|
+
# Per-tensor amax
|
|
228
|
+
weight_scaling_factor = torch.tensor(
|
|
229
|
+
weight_quantizer.amax.item() / weight_quantizer.maxbound
|
|
230
|
+
)
|
|
231
|
+
else:
|
|
232
|
+
# Per-channel amax
|
|
233
|
+
weight_scaling_factor = torch.tensor(weight_quantizer.amax / weight_quantizer.maxbound)
|
|
234
|
+
|
|
235
|
+
sub_module.register_buffer(
|
|
236
|
+
quantizer_attrs.weight_scale,
|
|
237
|
+
weight_scaling_factor,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
if hasattr(input_quantizer, "_amax"):
|
|
241
|
+
assert input_quantizer is not None
|
|
242
|
+
input_quantizer._amax = input_quantizer._amax.to(torch.float32)
|
|
243
|
+
|
|
244
|
+
sub_module.register_buffer(
|
|
245
|
+
quantizer_attrs.input_scale,
|
|
246
|
+
get_activation_scaling_factor(
|
|
247
|
+
sub_module, input_quantizer_name=quantizer_attrs.input_quantizer
|
|
248
|
+
).squeeze(),
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if hasattr(output_quantizer, "_amax"):
|
|
252
|
+
assert output_quantizer is not None
|
|
253
|
+
output_quantizer._amax = output_quantizer._amax.to(torch.float32)
|
|
254
|
+
else:
|
|
255
|
+
# Register weight_scale and input_scale
|
|
256
|
+
if quantization_format == QUANTIZATION_FP8_PB_REAL:
|
|
257
|
+
sub_module.register_buffer(
|
|
258
|
+
quantizer_attrs.weight_scale,
|
|
259
|
+
weight_quantizer._scale.to(torch.float32),
|
|
260
|
+
)
|
|
261
|
+
del weight_quantizer._scale
|
|
262
|
+
else:
|
|
263
|
+
sub_module.register_buffer(
|
|
264
|
+
quantizer_attrs.weight_scale, get_weight_scaling_factor(sub_module, weight_name)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
if (
|
|
268
|
+
input_quantizer is not None
|
|
269
|
+
and "disabled" not in repr(input_quantizer)
|
|
270
|
+
and input_quantizer.amax is not None
|
|
271
|
+
):
|
|
272
|
+
sub_module.register_buffer(
|
|
273
|
+
quantizer_attrs.input_scale,
|
|
274
|
+
get_activation_scaling_factor(
|
|
275
|
+
sub_module, input_quantizer_name=quantizer_attrs.input_quantizer
|
|
276
|
+
).squeeze(),
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
if quantization_format in [
|
|
280
|
+
QUANTIZATION_NVFP4_AWQ,
|
|
281
|
+
QUANTIZATION_NVFP4,
|
|
282
|
+
QUANTIZATION_W4A8_AWQ,
|
|
283
|
+
]:
|
|
284
|
+
# Register weight_scale_2
|
|
285
|
+
sub_module.register_buffer(
|
|
286
|
+
quantizer_attrs.weight_scale_2,
|
|
287
|
+
get_weight_scaling_factor_2(sub_module, weight_name).squeeze(),
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
weight_scale: torch.Tensor | None = getattr(sub_module, quantizer_attrs.weight_scale, None)
|
|
291
|
+
weight_scale_2: torch.Tensor | None = getattr(sub_module, quantizer_attrs.weight_scale_2, None)
|
|
292
|
+
|
|
293
|
+
# Transpose weight for bmm-style expert quantization (llama4, gpt-oss)
|
|
294
|
+
if quantization_format in [QUANTIZATION_NVFP4, QUANTIZATION_NVFP4_AWQ]:
|
|
295
|
+
# Transpose weight from (num_experts, input_dim, output_dim) to (num_experts, output_dim, input_dim)
|
|
296
|
+
# for NVFP4 quantization functions that expect input_dim as the last dimension for block quantization
|
|
297
|
+
is_bmm_expert_weight = weight.dim() == 3 and any(
|
|
298
|
+
expert_type in type(sub_module).__name__
|
|
299
|
+
for expert_type in ["Llama4TextExperts", "GptOssExperts"]
|
|
300
|
+
)
|
|
301
|
+
weight, _ = maybe_transpose_expert_weight_dimensions(
|
|
302
|
+
weight, is_bmm_expert_weight=is_bmm_expert_weight
|
|
303
|
+
)
|
|
304
|
+
weight_scale = NVFP4QTensor.get_weights_scaling_factor(
|
|
305
|
+
weight,
|
|
306
|
+
block_size=block_size,
|
|
307
|
+
weights_scaling_factor_2=weight_scale_2,
|
|
308
|
+
)[0]
|
|
309
|
+
|
|
310
|
+
quantized_weight = to_quantized_weight(
|
|
311
|
+
weight.to(dtype),
|
|
312
|
+
weight_scale,
|
|
313
|
+
quantization_format,
|
|
314
|
+
weight_scale_2,
|
|
315
|
+
block_size,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
quantized_weight, weight_scale = maybe_transpose_expert_weight_dimensions(
|
|
319
|
+
quantized_weight, weight_scale, is_bmm_expert_weight=is_bmm_expert_weight
|
|
320
|
+
)
|
|
321
|
+
else:
|
|
322
|
+
quantized_weight = to_quantized_weight(
|
|
323
|
+
weight.to(dtype),
|
|
324
|
+
weight_scale,
|
|
325
|
+
quantization_format,
|
|
326
|
+
weight_scale_2,
|
|
327
|
+
block_size,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
setattr(sub_module, weight_name, nn.Parameter(quantized_weight, requires_grad=False))
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _export_hf_checkpoint(
|
|
334
|
+
model: nn.Module, dtype: torch.dtype | None = None
|
|
335
|
+
) -> tuple[dict[str, Any], dict[str, Any]]:
|
|
336
|
+
"""Exports the torch model to the packed checkpoint with original HF naming.
|
|
337
|
+
|
|
338
|
+
The packed checkpoint will be consumed by the TensorRT-LLM unified converter.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
model: the torch model.
|
|
342
|
+
dtype: the weights data type to export the unquantized layers or the default model data type if None.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
post_state_dict: Dict containing quantized weights
|
|
346
|
+
quant_config: config information to export hf_quant_cfg.json
|
|
347
|
+
"""
|
|
348
|
+
if dtype is None:
|
|
349
|
+
dtype = model.config.torch_dtype
|
|
350
|
+
elif dtype != model.config.torch_dtype:
|
|
351
|
+
warnings.warn(
|
|
352
|
+
f"Model's original dtype ({model.config.torch_dtype}) differs from target dtype "
|
|
353
|
+
f"({dtype}), which may lead to numerical errors."
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
# Create a model layer pool
|
|
357
|
+
# If `model.model` exists use that, otherwise use `model` itself, e.g., Nemotron-H
|
|
358
|
+
root = getattr(model, "model", model)
|
|
359
|
+
# If that has a `.layers`, use it, otherwise fall back to the object itself
|
|
360
|
+
root = getattr(root, "layers", root)
|
|
361
|
+
layer_pool = {f"model.layers.{name}": sub_module for name, sub_module in root.named_modules()}
|
|
362
|
+
|
|
363
|
+
# Handle input quantizers of experts that are not calibrated
|
|
364
|
+
for name, sub_module in model.named_modules():
|
|
365
|
+
if is_moe(sub_module) and hasattr(sub_module, "experts"):
|
|
366
|
+
expert_linear_names = get_expert_linear_names(sub_module)
|
|
367
|
+
for linear_name in expert_linear_names:
|
|
368
|
+
# Handle DBRX experts specifically
|
|
369
|
+
if "QuantDbrxExperts" in type(sub_module.experts).__name__:
|
|
370
|
+
# For DBRX, experts are in sub_module.experts.mlp and linear layers are ModuleLists
|
|
371
|
+
experts_mlp = sub_module.experts.mlp
|
|
372
|
+
if hasattr(experts_mlp, linear_name):
|
|
373
|
+
linear_modulelist = getattr(experts_mlp, linear_name)
|
|
374
|
+
if hasattr(linear_modulelist, "__iter__"):
|
|
375
|
+
set_expert_quantizer_amax(
|
|
376
|
+
modules=list(linear_modulelist),
|
|
377
|
+
quantizer_attrs=["input_quantizer"],
|
|
378
|
+
)
|
|
379
|
+
elif "QuantGptOssExperts" in type(sub_module.experts).__name__:
|
|
380
|
+
# Handle GPT-OSS experts specifically
|
|
381
|
+
# GPT-OSS experts use gate_up_proj and down_proj
|
|
382
|
+
gpt_oss_linear_names = ["gate_up_proj", "down_proj"]
|
|
383
|
+
for linear_name in gpt_oss_linear_names:
|
|
384
|
+
if hasattr(sub_module.experts, linear_name):
|
|
385
|
+
linear_module = getattr(sub_module.experts, linear_name)
|
|
386
|
+
if hasattr(linear_module, "input_quantizer"):
|
|
387
|
+
set_expert_quantizer_amax(
|
|
388
|
+
modules=[linear_module],
|
|
389
|
+
quantizer_attrs=["input_quantizer"],
|
|
390
|
+
)
|
|
391
|
+
elif isinstance(sub_module.experts, collections.abc.Iterable):
|
|
392
|
+
# For other MoE models (like Mixtral) with iterable experts
|
|
393
|
+
try:
|
|
394
|
+
set_expert_quantizer_amax(
|
|
395
|
+
modules=[getattr(expert, linear_name) for expert in sub_module.experts],
|
|
396
|
+
quantizer_attrs=["input_quantizer"],
|
|
397
|
+
)
|
|
398
|
+
except AttributeError as e:
|
|
399
|
+
# Provide more helpful debugging information
|
|
400
|
+
expert_types = [type(expert).__name__ for expert in sub_module.experts]
|
|
401
|
+
raise AttributeError(
|
|
402
|
+
f"Failed to access attribute '{linear_name}' on experts. "
|
|
403
|
+
f"MoE module type: {type(sub_module).__name__}, "
|
|
404
|
+
f"Expert types: {expert_types}, "
|
|
405
|
+
f"Expected linear names: {expert_linear_names}. "
|
|
406
|
+
f"This suggests the get_expert_linear_names function may need "
|
|
407
|
+
f"to be updated for this model architecture. "
|
|
408
|
+
f"Original error: {e}"
|
|
409
|
+
) from e
|
|
410
|
+
else:
|
|
411
|
+
# Unsupported MoE model structure
|
|
412
|
+
raise NotImplementedError(
|
|
413
|
+
f"MoE model with experts type '{type(sub_module.experts).__name__}' is not supported in export."
|
|
414
|
+
f"Please file an issue or add support for this model architecture."
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
# NOTE: Speculative decoding models have extra modules that may be quantized
|
|
418
|
+
# Need to add these modules to the layer_pool
|
|
419
|
+
for key in SPECULATIVE_DECODING_MODULE_NAMES:
|
|
420
|
+
if hasattr(model, key):
|
|
421
|
+
for name, sub_module in getattr(model, key).named_modules():
|
|
422
|
+
layer_pool.update({f"{key}.{name}": sub_module})
|
|
423
|
+
|
|
424
|
+
# Resmooth and requantize fused layers
|
|
425
|
+
# TODO: Handle mixed precision
|
|
426
|
+
requantize_resmooth_fused_llm_layers(model)
|
|
427
|
+
|
|
428
|
+
# Remove all hooks from the model
|
|
429
|
+
try:
|
|
430
|
+
from accelerate.hooks import remove_hook_from_module
|
|
431
|
+
|
|
432
|
+
remove_hook_from_module(model, recurse=True)
|
|
433
|
+
except ImportError:
|
|
434
|
+
warnings.warn("accelerate is not installed, hooks will not be removed")
|
|
435
|
+
|
|
436
|
+
quant_config = get_quant_config(layer_pool)
|
|
437
|
+
|
|
438
|
+
kv_cache_max_bound = 0
|
|
439
|
+
kv_cache_format = quant_config["quantization"]["kv_cache_quant_algo"]
|
|
440
|
+
|
|
441
|
+
cache_bound_mapping = {
|
|
442
|
+
KV_CACHE_NVFP4: 6 * 448,
|
|
443
|
+
KV_CACHE_NVFP4_AFFINE: 6 * 448,
|
|
444
|
+
KV_CACHE_FP8: 448,
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
# Only update kv_cache_max_bound if a quantization is applied.
|
|
448
|
+
if kv_cache_format != QUANTIZATION_NONE:
|
|
449
|
+
kv_cache_max_bound = cache_bound_mapping.get(kv_cache_format)
|
|
450
|
+
|
|
451
|
+
# Track if any layers are quantized to properly set exclude_modules
|
|
452
|
+
has_quantized_layers = False
|
|
453
|
+
|
|
454
|
+
for name, sub_module in layer_pool.items():
|
|
455
|
+
if get_quantization_format(sub_module) != QUANTIZATION_NONE:
|
|
456
|
+
has_quantized_layers = True
|
|
457
|
+
if is_quantlinear(sub_module):
|
|
458
|
+
_export_quantized_weight(sub_module, dtype)
|
|
459
|
+
elif (
|
|
460
|
+
"Llama4TextExperts" in type(sub_module).__name__
|
|
461
|
+
or "GptOssExperts" in type(sub_module).__name__
|
|
462
|
+
):
|
|
463
|
+
# TODO: consolidate uncalibrated experts handling logic
|
|
464
|
+
# Handle weight quantizers amax values using smart fallback logic
|
|
465
|
+
set_expert_quantizer_amax(
|
|
466
|
+
modules=sub_module,
|
|
467
|
+
quantizer_attrs=["gate_up_proj_weight_quantizer", "down_proj_weight_quantizer"],
|
|
468
|
+
)
|
|
469
|
+
# Handle input quantizers amax values using smart fallback logic
|
|
470
|
+
set_expert_quantizer_amax(
|
|
471
|
+
modules=sub_module,
|
|
472
|
+
quantizer_attrs=["gate_up_proj_input_quantizer", "down_proj_input_quantizer"],
|
|
473
|
+
)
|
|
474
|
+
# Export the quantized weights
|
|
475
|
+
for weight_name in ["gate_up_proj", "down_proj"]:
|
|
476
|
+
_export_quantized_weight(sub_module, dtype, weight_name)
|
|
477
|
+
|
|
478
|
+
quantized_state_dict = model.state_dict()
|
|
479
|
+
|
|
480
|
+
quantized_state_dict = postprocess_state_dict(
|
|
481
|
+
quantized_state_dict, kv_cache_max_bound, kv_cache_format
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
# Check if any layers are quantized
|
|
485
|
+
if has_quantized_layers:
|
|
486
|
+
quant_config["quantization"].setdefault("exclude_modules", []).append("lm_head")
|
|
487
|
+
|
|
488
|
+
return quantized_state_dict, quant_config
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def export_hf_checkpoint(
|
|
492
|
+
model: nn.Module,
|
|
493
|
+
dtype: torch.dtype | None = None,
|
|
494
|
+
export_dir: Path | str = tempfile.gettempdir(),
|
|
495
|
+
save_modelopt_state: bool = False,
|
|
496
|
+
):
|
|
497
|
+
"""Exports the torch model to unified checkpoint and saves to export_dir.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
model: the torch model.
|
|
501
|
+
dtype: the weights data type to export the unquantized layers or the default model data type if None.
|
|
502
|
+
export_dir: the target export path.
|
|
503
|
+
save_modelopt_state: whether to save the modelopt state_dict.
|
|
504
|
+
"""
|
|
505
|
+
export_dir = Path(export_dir)
|
|
506
|
+
export_dir.mkdir(parents=True, exist_ok=True)
|
|
507
|
+
try:
|
|
508
|
+
post_state_dict, hf_quant_config = _export_hf_checkpoint(model, dtype)
|
|
509
|
+
|
|
510
|
+
# Save hf_quant_config.json for backward compatibility
|
|
511
|
+
with open(f"{export_dir}/hf_quant_config.json", "w") as file:
|
|
512
|
+
json.dump(hf_quant_config, file, indent=4)
|
|
513
|
+
|
|
514
|
+
hf_quant_config = convert_hf_quant_config_format(hf_quant_config)
|
|
515
|
+
|
|
516
|
+
# Save model
|
|
517
|
+
model.save_pretrained(
|
|
518
|
+
export_dir, state_dict=post_state_dict, save_modelopt_state=save_modelopt_state
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
original_config = f"{export_dir}/config.json"
|
|
522
|
+
config_data = {}
|
|
523
|
+
|
|
524
|
+
with open(original_config) as file:
|
|
525
|
+
config_data = json.load(file)
|
|
526
|
+
|
|
527
|
+
config_data["quantization_config"] = hf_quant_config
|
|
528
|
+
|
|
529
|
+
with open(original_config, "w") as file:
|
|
530
|
+
json.dump(config_data, file, indent=4)
|
|
531
|
+
|
|
532
|
+
except Exception as e:
|
|
533
|
+
warnings.warn(
|
|
534
|
+
"Cannot export model to the model_config. The modelopt-optimized model state_dict"
|
|
535
|
+
" can be saved with torch.save for further inspection."
|
|
536
|
+
)
|
|
537
|
+
raise e
|