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,477 @@
|
|
|
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
|
+
"""User-facing quantization API."""
|
|
17
|
+
|
|
18
|
+
import fnmatch
|
|
19
|
+
import inspect
|
|
20
|
+
import warnings
|
|
21
|
+
from collections.abc import Callable, Iterable
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
import torch
|
|
25
|
+
import torch.nn as nn
|
|
26
|
+
|
|
27
|
+
import modelopt.torch.quantization as mtq
|
|
28
|
+
from modelopt.torch.opt import apply_mode
|
|
29
|
+
from modelopt.torch.opt.searcher import ForwardLoop
|
|
30
|
+
from modelopt.torch.opt.utils import forward_with_reshard
|
|
31
|
+
from modelopt.torch.quantization.config import QuantizeConfig
|
|
32
|
+
from modelopt.torch.quantization.conversion import set_quantizer_by_cfg
|
|
33
|
+
|
|
34
|
+
from . import config
|
|
35
|
+
from .algorithms import AutoQuantizeSearcher
|
|
36
|
+
from .config import QuantizeAlgoCfgType
|
|
37
|
+
from .conversion import set_quantizer_attribute
|
|
38
|
+
from .mode import QuantizeModeRegistry, get_modelike_from_algo_cfg
|
|
39
|
+
from .nn import QuantModule, TensorQuantizer
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"auto_quantize",
|
|
43
|
+
"calibrate",
|
|
44
|
+
"disable_quantizer",
|
|
45
|
+
"enable_quantizer",
|
|
46
|
+
"fold_weight",
|
|
47
|
+
"postprocess_amax",
|
|
48
|
+
"print_quant_summary",
|
|
49
|
+
"quantize",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# TODO: Descriptors for the supported algorithms
|
|
54
|
+
def calibrate(
|
|
55
|
+
model: nn.Module,
|
|
56
|
+
algorithm: QuantizeAlgoCfgType = "max",
|
|
57
|
+
forward_loop: ForwardLoop | None = None,
|
|
58
|
+
) -> nn.Module:
|
|
59
|
+
"""Adjusts weights and scaling factors based on selected algorithms.
|
|
60
|
+
|
|
61
|
+
In order to calibrate using custom user defined calibration algorithm, refer to
|
|
62
|
+
:ref:`custom calibration algorithm <custom_calibration_algorithm>`
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
model: A pytorch model with quantizer modules.
|
|
66
|
+
algorithm: A string or dictionary specifying the calibration algorithm to use. Supported
|
|
67
|
+
algorithms are ``"max"``, ``"smoothquant"``, ``"awq_lite"``, ``"awq_full"``, and
|
|
68
|
+
``"awq_clip"``. If a dictionary is passed, the key ``"method"`` should specify the
|
|
69
|
+
calibration algorithm to use. Other key-value pairs in this dictionary will be passed
|
|
70
|
+
as kwargs to the algorithm.
|
|
71
|
+
|
|
72
|
+
An example dictionary argument:
|
|
73
|
+
``{"method": "awq_clip", "max_co_batch_size": 4096}``.
|
|
74
|
+
|
|
75
|
+
If ``None``, no calibration is performed.
|
|
76
|
+
forward_loop: A callable which takes the model as argument and forwards calibration data
|
|
77
|
+
through the model. This is not required for weight-only quantization with the ``"max"``
|
|
78
|
+
algorithm.
|
|
79
|
+
|
|
80
|
+
Returns: The calibrated pytorch model.
|
|
81
|
+
"""
|
|
82
|
+
if forward_loop is not None:
|
|
83
|
+
# get the number of arguments of forward_loop
|
|
84
|
+
num_args = len(inspect.signature(forward_loop).parameters)
|
|
85
|
+
if num_args == 0:
|
|
86
|
+
warnings.warn(
|
|
87
|
+
(
|
|
88
|
+
"forward_loop should take model as argument, but got forward_loop without any"
|
|
89
|
+
" arguments. This usage will be deprecated in future versions."
|
|
90
|
+
),
|
|
91
|
+
DeprecationWarning,
|
|
92
|
+
)
|
|
93
|
+
original_forward_loop = forward_loop
|
|
94
|
+
|
|
95
|
+
def forward_loop(model):
|
|
96
|
+
return original_forward_loop() # type: ignore[call-arg]
|
|
97
|
+
|
|
98
|
+
# move the model to eval mode
|
|
99
|
+
is_training = model.training
|
|
100
|
+
model.eval()
|
|
101
|
+
|
|
102
|
+
with forward_with_reshard(model):
|
|
103
|
+
apply_mode(
|
|
104
|
+
model,
|
|
105
|
+
mode=get_modelike_from_algo_cfg(algorithm),
|
|
106
|
+
mode_kwargs={"forward_loop": forward_loop},
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# TODO: Re-enable when the CUDA error: unspecified launch failure is fixed.
|
|
110
|
+
# clear_cuda_cache()
|
|
111
|
+
|
|
112
|
+
model.train(is_training)
|
|
113
|
+
|
|
114
|
+
return model
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def postprocess_amax(model: nn.Module, key: str, post_process_fn) -> nn.Module:
|
|
118
|
+
"""Experimental API to postprocess the amax values after calibration."""
|
|
119
|
+
assert isinstance(key, str), "key should be a string"
|
|
120
|
+
for name, module in model.named_modules():
|
|
121
|
+
if not isinstance(module, TensorQuantizer):
|
|
122
|
+
continue
|
|
123
|
+
if not hasattr(module, "_amax"):
|
|
124
|
+
continue
|
|
125
|
+
if not fnmatch.fnmatch(name, key):
|
|
126
|
+
continue
|
|
127
|
+
module.amax = post_process_fn(module.amax)
|
|
128
|
+
|
|
129
|
+
return model
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def quantize(
|
|
133
|
+
model: nn.Module,
|
|
134
|
+
config: dict[str, Any | QuantizeConfig],
|
|
135
|
+
forward_loop: ForwardLoop | None = None,
|
|
136
|
+
) -> nn.Module:
|
|
137
|
+
"""Quantizes and calibrates the model in-place.
|
|
138
|
+
|
|
139
|
+
This method performs replacement of modules with their quantized counterparts and
|
|
140
|
+
performs calibration as specified by ``quant_cfg``.
|
|
141
|
+
``forward_loop`` is used to forward data through the model and gather statistics for calibration.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
model: A pytorch model
|
|
145
|
+
config: A dictionary or an instance of
|
|
146
|
+
:class:`QuantizeConfig <modelopt.torch.quantization.config.QuantizeConfig>` specifying the
|
|
147
|
+
values for keys ``"quant_cfg"`` and ``"algorithm"``.
|
|
148
|
+
It is basically a dictionary specifying the values for keys ``"quant_cfg"`` and ``"algorithm"``.
|
|
149
|
+
The ``"quant_cfg"`` key specifies the quantization configurations.
|
|
150
|
+
The ``"algorithm"`` key specifies the ``algorithm`` argument to
|
|
151
|
+
:meth:`calibrate <modelopt.torch.quantization.model_quant.calibrate>`.
|
|
152
|
+
|
|
153
|
+
Quantization configurations is a dictionary mapping wildcards or filter functions
|
|
154
|
+
to its quantizer attributes. The wildcards or filter functions are matched
|
|
155
|
+
against the quantizer module names. The quantizer modules have names ending with
|
|
156
|
+
``weight_quantizer`` and ``input_quantizer`` and they perform weight quantization and
|
|
157
|
+
input quantization (or activation quantization) respectively. The quantizer modules
|
|
158
|
+
are instances of
|
|
159
|
+
:class:`TensorQuantizer <modelopt.torch.quantization.nn.modules.tensor_quantizer.TensorQuantizer>`.
|
|
160
|
+
The quantizer attributes are defined by :class:`QuantizerAttributeConfig`. See
|
|
161
|
+
:class:`QuantizerAttributeConfig` for details on the quantizer attributes and their values.
|
|
162
|
+
|
|
163
|
+
An example ``config`` dictionary is given below:
|
|
164
|
+
|
|
165
|
+
.. code-block::python
|
|
166
|
+
|
|
167
|
+
config = {
|
|
168
|
+
|
|
169
|
+
"quant_cfg": {
|
|
170
|
+
# "num_bits" specifies the number of bits for quantization
|
|
171
|
+
# "axis" specifies the axis for quantization
|
|
172
|
+
"*weight_quantizer": {"num_bits": 8, "axis": 0},
|
|
173
|
+
"*input_quantizer": {"num_bits": 8, "axis": -1},
|
|
174
|
+
|
|
175
|
+
# Default quantization settings
|
|
176
|
+
"default": {"num_bits": 8, "axis": None},
|
|
177
|
+
}
|
|
178
|
+
"algorithm": "max"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
See :ref:`Quantization Formats <quantization-formats>` to learn more about the supported
|
|
182
|
+
quantization formats. See :ref:`Quantization Configs <quantization-configs>` for more details on
|
|
183
|
+
``config`` dictionary.
|
|
184
|
+
|
|
185
|
+
forward_loop: A callable that forwards all calibration data through the model. This is used
|
|
186
|
+
to gather statistics for calibration. It should take model as the argument. It does not need
|
|
187
|
+
to return anything.
|
|
188
|
+
|
|
189
|
+
This argument is not required for weight-only quantization with the ``"max"``
|
|
190
|
+
algorithm.
|
|
191
|
+
|
|
192
|
+
Here are a few examples for correct ``forward_loop`` definitions:
|
|
193
|
+
Example 1:
|
|
194
|
+
|
|
195
|
+
.. code-block::
|
|
196
|
+
|
|
197
|
+
def forward_loop(model) -> None:
|
|
198
|
+
# iterate over the data loader and forward data through the model
|
|
199
|
+
for batch in data_loader:
|
|
200
|
+
model(batch)
|
|
201
|
+
|
|
202
|
+
Example 2:
|
|
203
|
+
|
|
204
|
+
.. code-block::
|
|
205
|
+
|
|
206
|
+
def forward_loop(model) -> float:
|
|
207
|
+
# evaluate the model on the task
|
|
208
|
+
return evaluate(model, task, ....)
|
|
209
|
+
|
|
210
|
+
Example 3:
|
|
211
|
+
|
|
212
|
+
.. code-block::
|
|
213
|
+
|
|
214
|
+
def forward_loop(model) -> None:
|
|
215
|
+
# run evaluation pipeline
|
|
216
|
+
evaluator.model = model
|
|
217
|
+
evaluator.evaluate()
|
|
218
|
+
|
|
219
|
+
.. note::
|
|
220
|
+
|
|
221
|
+
Calibration does not require forwarding the entire dataset through the model.
|
|
222
|
+
Please subsample the dataset or reduce the number of batches if needed.
|
|
223
|
+
|
|
224
|
+
Returns: A pytorch model which has been quantized and calibrated.
|
|
225
|
+
"""
|
|
226
|
+
model = apply_mode(model, mode=[("quantize", config)], registry=QuantizeModeRegistry)
|
|
227
|
+
return calibrate(model, config["algorithm"], forward_loop=forward_loop)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def auto_quantize(
|
|
231
|
+
model: nn.Module,
|
|
232
|
+
constraints: dict[str, float | str] = {"effective_bits": 4.8},
|
|
233
|
+
quantization_formats: list[dict[str, Any] | str] = [
|
|
234
|
+
mtq.NVFP4_AWQ_LITE_CFG,
|
|
235
|
+
mtq.FP8_DEFAULT_CFG,
|
|
236
|
+
],
|
|
237
|
+
data_loader: Iterable | None = None,
|
|
238
|
+
forward_step: Callable[[nn.Module, Any], Any | torch.Tensor] | None = None,
|
|
239
|
+
loss_func: Callable[[Any, Any], torch.Tensor] | None = None,
|
|
240
|
+
forward_backward_step: Callable[[nn.Module, Any], Any] | None = None,
|
|
241
|
+
disabled_layers: list[str] | str | None = None,
|
|
242
|
+
num_calib_steps: int = 512,
|
|
243
|
+
num_score_steps: int = 128,
|
|
244
|
+
verbose: bool = False,
|
|
245
|
+
):
|
|
246
|
+
r"""Perform optimal per-layer quantization by searching for the best quantization formats per-layer.
|
|
247
|
+
|
|
248
|
+
``auto_quantize`` uses a gradient based sensitivity score to rank the per-layer quantization formats and search
|
|
249
|
+
for the best quantization formats per-layer.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
model: A pytorch model with quantizer modules.
|
|
253
|
+
constraints: Constraints for the search. Currently we support only ``effective_bits``.
|
|
254
|
+
``effective_bits`` specifies the effective number of bits for the quantized model.
|
|
255
|
+
|
|
256
|
+
Here is an example for valid ``effective_bits`` argument:
|
|
257
|
+
|
|
258
|
+
.. code-block:: python
|
|
259
|
+
|
|
260
|
+
# For an effective quantization bits of 4.8
|
|
261
|
+
constraints = {"effective_bits": 4.8}
|
|
262
|
+
|
|
263
|
+
quantization_formats: A list of quantization format config dictionaries or string names to search for.
|
|
264
|
+
Each config dictionary should be valid as a ``config`` argument in
|
|
265
|
+
:meth:`quantize <modelopt.torch.quantization.model_quant.quantize>`.
|
|
266
|
+
The supported quantization format names are as listed by :attr:`modelopt.torch.quantization.config.choices`.
|
|
267
|
+
|
|
268
|
+
Internally we always add "do not quantize" as a choice. Therefore, it is possible that a layer is
|
|
269
|
+
not quantized by any of the quantization formats.
|
|
270
|
+
|
|
271
|
+
Custom quantization formats can also be defined and used as a quantization format. This is a experimental
|
|
272
|
+
feature and the results may not be optimal. Here is an example:
|
|
273
|
+
|
|
274
|
+
.. code-block:: python
|
|
275
|
+
|
|
276
|
+
INT8_CUSTOM_QUANT_CFG = {
|
|
277
|
+
"quant_cfg": {
|
|
278
|
+
"*weight_quantizer": {"num_bits": 8, "axis": 0},
|
|
279
|
+
"*input_quantizer": {"num_bits": 8, "axis": None},
|
|
280
|
+
},
|
|
281
|
+
"algorithm": "smoothquant",
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
mtq.auto_quantize(
|
|
285
|
+
model,
|
|
286
|
+
constraints,
|
|
287
|
+
quantization_formats=["INT4_AWQ_CFG", INT8_CUSTOM_QUANT_CFG],
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
Internally we always add "do not quantize" as a choice. Therefore, it is possible that a layer is
|
|
291
|
+
not quantized by any of the quantization formats.
|
|
292
|
+
|
|
293
|
+
.. note::
|
|
294
|
+
|
|
295
|
+
The quantization formats will be applied on a per-layer match basis. The global model level name
|
|
296
|
+
based quantizer attribute setting will be ignored. For example, in ``FP8_DEFAULT_CFG`` quantizer
|
|
297
|
+
configuration the key ``"*lm_head*": {"enable": False}`` disables quantization for the ``lm_head``
|
|
298
|
+
layer. However in ``auto_quantize``, the quantization format for the ``lm_head`` layer will be searched.
|
|
299
|
+
This is because the key ``"*lm_head*"`` sets the quantizer attributes based on the global model level
|
|
300
|
+
name, not per-layer basis. The keys ``"*input_quantizer"``, ``"*weight_quantizer"`` etc. in
|
|
301
|
+
``FP8_DEFAULT_CFG`` match on a per-layer basis - hence the corresponding quantizers
|
|
302
|
+
will be set as specified.
|
|
303
|
+
|
|
304
|
+
Here is an example `quantization_formats` argument:
|
|
305
|
+
|
|
306
|
+
.. code-block:: python
|
|
307
|
+
|
|
308
|
+
# A valid `quantization_formats` argument
|
|
309
|
+
# This will search for the best per-layer quantization from FP8, W4A8_AWQ_BETA_CFG or No quantization
|
|
310
|
+
quantization_formats = [mtq.FP8_DEFAULT_CFG, mtq.W4A8_AWQ_BETA_CFG]
|
|
311
|
+
|
|
312
|
+
data_loader: An iterator that yields data that is to be used for calibrating quantized layers and estimating
|
|
313
|
+
``auto_quantize`` scores.
|
|
314
|
+
forward_step: A callable that takes the model and a batch of data from ``data_loader`` as input, forwards
|
|
315
|
+
the data through the model and returns the model output.
|
|
316
|
+
This is a required argument.
|
|
317
|
+
|
|
318
|
+
Here is an example for a valid ``forward_step``:
|
|
319
|
+
|
|
320
|
+
.. code-block:: python
|
|
321
|
+
|
|
322
|
+
# Takes the model and a batch of data as input and returns the model output
|
|
323
|
+
def forward_step(model, batch) -> torch.Tensor:
|
|
324
|
+
output = model(batch)
|
|
325
|
+
return output
|
|
326
|
+
|
|
327
|
+
loss_func: (Optional) A callable that takes the model output and the batch of data as input and computes the
|
|
328
|
+
loss. The model output is the output given by ``forward_step``. `.backward()` will be called on the loss.
|
|
329
|
+
|
|
330
|
+
Here is an example for a valid ``loss_func``:
|
|
331
|
+
|
|
332
|
+
.. code-block:: python
|
|
333
|
+
|
|
334
|
+
# Takes the model output and a batch of data as input and returns the loss
|
|
335
|
+
def loss_func(output, batch) -> torch.Tensor:
|
|
336
|
+
...
|
|
337
|
+
return loss
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
# loss should be a scalar tensor such that loss.backward() can be called
|
|
341
|
+
loss = loss_func(output, batch)
|
|
342
|
+
loss.backward()
|
|
343
|
+
|
|
344
|
+
If this argument is not provided, ``forward_backward_step`` should be provided.
|
|
345
|
+
|
|
346
|
+
forward_backward_step: (Optional) A callable that takes batch of data from ``data_loader``, forwards it
|
|
347
|
+
through the model, computes the loss and runs backward on the loss.
|
|
348
|
+
|
|
349
|
+
Here is an example for a valid ``forward_backward_step`` argument:
|
|
350
|
+
|
|
351
|
+
.. code-block:: python
|
|
352
|
+
|
|
353
|
+
# Takes the model and a batch of data as input and runs forward and backward pass
|
|
354
|
+
def forward_backward_step(model, batch) -> None:
|
|
355
|
+
output = model(batch)
|
|
356
|
+
loss = my_loss_func(output, batch)
|
|
357
|
+
run_custom_backward(loss)
|
|
358
|
+
|
|
359
|
+
If this argument is not provided, ``loss_func`` should be provided.
|
|
360
|
+
|
|
361
|
+
disabled_layers: (Optional) One or a list of wildcard strings to disable quantization for the layers. Example:
|
|
362
|
+
|
|
363
|
+
.. code-block:: python
|
|
364
|
+
|
|
365
|
+
disabled_layers = "*lm_head*"
|
|
366
|
+
disabled_layers = ["*lm_head*", "*mlp*"]
|
|
367
|
+
|
|
368
|
+
num_calib_steps: Number of batches to use for calibrating the quantized model. Suggested value is 512.
|
|
369
|
+
num_score_steps: Number of batches to use for estimating ``auto_quantize`` scores. Suggested value is 128.
|
|
370
|
+
A higher value could increase the time taken for performing ``auto_quantize``.
|
|
371
|
+
verbose: If True, prints the search progress/intermediate results.
|
|
372
|
+
|
|
373
|
+
Returns: A tuple (model, state_dict) where ``model`` is the searched and quantized model and
|
|
374
|
+
``state_dict`` contains the history and detailed stats of the search procedure.
|
|
375
|
+
|
|
376
|
+
.. note::
|
|
377
|
+
|
|
378
|
+
``auto_quantize`` groups certain layers and restricts the quantization formats for them to be same. For example,
|
|
379
|
+
Q, K, V linear layers belonging to the same transformer layer will have the same quantization format.
|
|
380
|
+
This is to ensure compatibility with TensorRT-LLM which fuses these three linear layers into a single linear
|
|
381
|
+
layer.
|
|
382
|
+
|
|
383
|
+
A list of regex pattern rules as defined in :attr:`rules <.algorithms.AutoQuantizeSearcher.rules>`
|
|
384
|
+
are used to specify the group of layers. The first captured group
|
|
385
|
+
in the regex pattern (i.e, ``pattern.match(name).group(1)``) is used to group the layers. All the layers
|
|
386
|
+
that share the same first captured group will have the same quantization format..
|
|
387
|
+
|
|
388
|
+
For example, the rule ``r"^(.*?)\.(q_proj|k_proj|v_proj)$"``
|
|
389
|
+
groups the `q_proj`, `k_proj`, `v_proj` linear layers belonging to the same transformer layer.
|
|
390
|
+
|
|
391
|
+
You may modify the rules to group the layers as per your requirement.
|
|
392
|
+
|
|
393
|
+
.. code-block:: python
|
|
394
|
+
|
|
395
|
+
from modelopt.torch.quantization.algorithms import AutoQuantizeSearcher
|
|
396
|
+
|
|
397
|
+
# To additionally group the layers belonging to same `mlp` layer,
|
|
398
|
+
# add the following rule
|
|
399
|
+
AutoQuantizeSearcher.rules.append(r"^(.*?)\.mlp")
|
|
400
|
+
|
|
401
|
+
# Perform `auto_quantize`
|
|
402
|
+
model, state_dict = auto_quantize(model, ...)
|
|
403
|
+
|
|
404
|
+
.. note::
|
|
405
|
+
|
|
406
|
+
The ``auto_quantize`` API and algorithm is experimental and subject to change. ``auto_quantize`` searched models
|
|
407
|
+
might not be readily deployable to TensorRT-LLM yet.
|
|
408
|
+
|
|
409
|
+
"""
|
|
410
|
+
processed_quantization_formats = []
|
|
411
|
+
for i, quant_cfg in enumerate(quantization_formats):
|
|
412
|
+
if quant_cfg is None:
|
|
413
|
+
continue
|
|
414
|
+
if isinstance(quant_cfg, str):
|
|
415
|
+
assert quant_cfg in config.choices, f"Invalid quantization format: {quant_cfg}"
|
|
416
|
+
quant_cfg = getattr(config, quant_cfg)
|
|
417
|
+
elif not any(quant_cfg is getattr(config, choice) for choice in config.choices):
|
|
418
|
+
warnings.warn(
|
|
419
|
+
"Received custom quantization formats for search, auto_quantize results may not be optimal."
|
|
420
|
+
)
|
|
421
|
+
processed_quantization_formats.append(quant_cfg)
|
|
422
|
+
|
|
423
|
+
assert len(processed_quantization_formats) > 0, "`quantization_formats` should not be empty"
|
|
424
|
+
model = apply_mode(
|
|
425
|
+
model,
|
|
426
|
+
mode="auto_quantize",
|
|
427
|
+
registry=QuantizeModeRegistry,
|
|
428
|
+
)
|
|
429
|
+
searcher = AutoQuantizeSearcher()
|
|
430
|
+
search_config = {
|
|
431
|
+
"quantization_formats": processed_quantization_formats,
|
|
432
|
+
"data_loader": data_loader,
|
|
433
|
+
"forward_step": forward_step,
|
|
434
|
+
"loss_func": loss_func,
|
|
435
|
+
"forward_backward_step": forward_backward_step,
|
|
436
|
+
"num_calib_steps": num_calib_steps,
|
|
437
|
+
"num_score_steps": num_score_steps,
|
|
438
|
+
"verbose": verbose,
|
|
439
|
+
}
|
|
440
|
+
# Disable all quantizers; AutoQuantize will enable the needed ones
|
|
441
|
+
set_quantizer_by_cfg(model, {"*": {"enable": False}})
|
|
442
|
+
searcher.search(model, constraints, config=search_config) # type: ignore[arg-type]
|
|
443
|
+
|
|
444
|
+
if disabled_layers:
|
|
445
|
+
if isinstance(disabled_layers, str):
|
|
446
|
+
disabled_layers = [disabled_layers]
|
|
447
|
+
for layer_pattern in disabled_layers:
|
|
448
|
+
disable_quantizer(model, layer_pattern)
|
|
449
|
+
|
|
450
|
+
return model, searcher.state_dict()
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def disable_quantizer(model: nn.Module, wildcard_or_filter_func: str | Callable):
|
|
454
|
+
"""Disable quantizer by wildcard or filter function."""
|
|
455
|
+
set_quantizer_attribute(model, wildcard_or_filter_func, {"enable": False})
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def enable_quantizer(model: nn.Module, wildcard_or_filter_func: str | Callable):
|
|
459
|
+
"""Enable quantizer by wildcard or filter function."""
|
|
460
|
+
set_quantizer_attribute(model, wildcard_or_filter_func, {"enable": True})
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def print_quant_summary(model: nn.Module):
|
|
464
|
+
"""Print summary of all quantizer modules in the model."""
|
|
465
|
+
count = 0
|
|
466
|
+
for name, mod in model.named_modules():
|
|
467
|
+
if isinstance(mod, TensorQuantizer):
|
|
468
|
+
print(f"{name:80} {mod}")
|
|
469
|
+
count += 1
|
|
470
|
+
print(f"{count} TensorQuantizers found in model")
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def fold_weight(model: nn.Module):
|
|
474
|
+
"""Fold weight quantizer for fast evaluation."""
|
|
475
|
+
for name, module in model.named_modules():
|
|
476
|
+
if isinstance(module, QuantModule):
|
|
477
|
+
module.fold_weight()
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
"""Modules with quantization support."""
|
|
17
|
+
|
|
18
|
+
from .modules.quant_activations import *
|
|
19
|
+
from .modules.quant_batchnorm import *
|
|
20
|
+
from .modules.quant_conv import *
|
|
21
|
+
from .modules.quant_instancenorm import *
|
|
22
|
+
from .modules.quant_linear import *
|
|
23
|
+
from .modules.quant_module import *
|
|
24
|
+
from .modules.quant_pooling import *
|
|
25
|
+
from .modules.quant_rnn import *
|
|
26
|
+
from .modules.tensor_quantizer import *
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
"""Some supportive functions."""
|
|
17
|
+
|
|
18
|
+
import warnings
|
|
19
|
+
|
|
20
|
+
import torch
|
|
21
|
+
from torch.autograd import Function
|
|
22
|
+
|
|
23
|
+
from .. import utils
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ClipFunction(Function):
|
|
27
|
+
"""An universal tensor clip function.
|
|
28
|
+
|
|
29
|
+
Pytorch's clamp() only supports scalar range and doesn't support broadcast. This implementation uses min/max which
|
|
30
|
+
is more general. The gradient is defined according to IBM's PACT paper https://arxiv.org/abs/1805.06085, which is
|
|
31
|
+
also the behavior of Tensorflow's clip_by_value()
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def forward(ctx, input, clip_value_min, clip_value_max):
|
|
36
|
+
"""Forward pass for the clip function."""
|
|
37
|
+
output = torch.min(input, clip_value_max)
|
|
38
|
+
output = torch.max(output, clip_value_min)
|
|
39
|
+
ctx.save_for_backward(input, clip_value_min, clip_value_max)
|
|
40
|
+
return output
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def backward(ctx, grad_output):
|
|
44
|
+
"""Backward pass for the clip function."""
|
|
45
|
+
input, clip_value_min, clip_value_max = ctx.saved_tensors
|
|
46
|
+
min_mask = (input > clip_value_min).to(grad_output.dtype)
|
|
47
|
+
max_mask = (input < clip_value_max).to(grad_output.dtype)
|
|
48
|
+
grad_input = grad_output * min_mask * max_mask
|
|
49
|
+
|
|
50
|
+
if clip_value_min.requires_grad or clip_value_max.requires_grad:
|
|
51
|
+
warnings.warn("Learning enabled for clip min/max. This is an experimental feature.")
|
|
52
|
+
if clip_value_min.numel() != 1 or clip_value_max.numel() != 1:
|
|
53
|
+
raise ValueError(
|
|
54
|
+
f"Learnable min/max can only be scalar, got size {clip_value_min.size()} and {clip_value_max.size()}."
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Ensure the dtypes of min/max grads matches the input dtype
|
|
58
|
+
# This might be necessary if running w/ AMP which will cast to fp32 before `sum()`
|
|
59
|
+
grad_clip_value_min = (
|
|
60
|
+
(grad_output * (1.0 - min_mask)).sum().to(clip_value_min.dtype)
|
|
61
|
+
if clip_value_min.requires_grad
|
|
62
|
+
else None
|
|
63
|
+
)
|
|
64
|
+
grad_clip_value_max = (
|
|
65
|
+
(grad_output * (1.0 - max_mask)).sum().to(clip_value_min.dtype)
|
|
66
|
+
if clip_value_max.requires_grad
|
|
67
|
+
else None
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return grad_input, grad_clip_value_min, grad_clip_value_max
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
clip = ClipFunction.apply
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class FastHadamardTransform(Function):
|
|
77
|
+
"""The fast Hadamard transform.
|
|
78
|
+
|
|
79
|
+
This only works for inputs.shape[-1] == power of 2.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def forward(ctx, inputs):
|
|
84
|
+
"""Hadamard forward."""
|
|
85
|
+
assert utils.is_pow2(inputs.shape[-1]), (
|
|
86
|
+
"Fast hadamard only works for inputs.shape[-1] == power of 2."
|
|
87
|
+
)
|
|
88
|
+
return fast_hadamard_transform.hadamard_transform(inputs) # type: ignore[name-defined]
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def backward(ctx, grad_outputs):
|
|
92
|
+
"""Hadamard backward."""
|
|
93
|
+
return fast_hadamard_transform.hadamard_transform(grad_outputs) # type: ignore[name-defined]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def normalized_hadamard_transform(inputs):
|
|
97
|
+
"""Normalized fast hadamard transform."""
|
|
98
|
+
global fast_hadamard_transform
|
|
99
|
+
try:
|
|
100
|
+
import fast_hadamard_transform
|
|
101
|
+
except ModuleNotFoundError:
|
|
102
|
+
raise ModuleNotFoundError(
|
|
103
|
+
"Package `fast_hadamard_transform` not found, please install it using "
|
|
104
|
+
"`pip install git+https://github.com/Dao-AILab/fast-hadamard-transform.git`"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return FastHadamardTransform.apply(inputs) / torch.sqrt(
|
|
108
|
+
torch.tensor(inputs.shape[-1], dtype=torch.float32)
|
|
109
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
"""Modules with quantization support."""
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
"""Quantized activations module."""
|
|
17
|
+
|
|
18
|
+
import torch.nn as nn
|
|
19
|
+
|
|
20
|
+
from .quant_module import QuantInputBase, QuantModuleRegistry
|
|
21
|
+
|
|
22
|
+
QuantModuleRegistry.register({nn.LeakyReLU: "nn.LeakyReLU"})(QuantInputBase)
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
"""Quantized batch normalization module."""
|
|
17
|
+
|
|
18
|
+
import torch.nn as nn
|
|
19
|
+
|
|
20
|
+
from .quant_module import QuantInputBase, QuantModuleRegistry
|
|
21
|
+
|
|
22
|
+
QuantModuleRegistry.register({nn.BatchNorm1d: "nn.BatchNorm1d"})(QuantInputBase)
|
|
23
|
+
QuantModuleRegistry.register({nn.BatchNorm2d: "nn.BatchNorm2d"})(QuantInputBase)
|
|
24
|
+
QuantModuleRegistry.register({nn.BatchNorm3d: "nn.BatchNorm3d"})(QuantInputBase)
|