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.
Files changed (272) hide show
  1. modelopt/__init__.py +20 -0
  2. modelopt/deploy/__init__.py +16 -0
  3. modelopt/deploy/llm/__init__.py +30 -0
  4. modelopt/deploy/llm/generate.py +345 -0
  5. modelopt/onnx/__init__.py +34 -0
  6. modelopt/onnx/autocast/__init__.py +19 -0
  7. modelopt/onnx/autocast/__main__.py +187 -0
  8. modelopt/onnx/autocast/convert.py +202 -0
  9. modelopt/onnx/autocast/graphsanitizer.py +422 -0
  10. modelopt/onnx/autocast/logging_config.py +78 -0
  11. modelopt/onnx/autocast/nodeclassifier.py +416 -0
  12. modelopt/onnx/autocast/precisionconverter.py +1032 -0
  13. modelopt/onnx/autocast/referencerunner.py +159 -0
  14. modelopt/onnx/autocast/utils.py +117 -0
  15. modelopt/onnx/llm_export_utils/__init__.py +16 -0
  16. modelopt/onnx/llm_export_utils/export_utils.py +162 -0
  17. modelopt/onnx/llm_export_utils/quantization_utils.py +122 -0
  18. modelopt/onnx/llm_export_utils/surgeon_utils.py +120 -0
  19. modelopt/onnx/logging_config.py +77 -0
  20. modelopt/onnx/op_types.py +300 -0
  21. modelopt/onnx/quantization/__init__.py +20 -0
  22. modelopt/onnx/quantization/__main__.py +291 -0
  23. modelopt/onnx/quantization/calib_utils.py +178 -0
  24. modelopt/onnx/quantization/extensions.py +35 -0
  25. modelopt/onnx/quantization/fp8.py +375 -0
  26. modelopt/onnx/quantization/graph_utils.py +1479 -0
  27. modelopt/onnx/quantization/gs_patching.py +112 -0
  28. modelopt/onnx/quantization/int4.py +1347 -0
  29. modelopt/onnx/quantization/int8.py +283 -0
  30. modelopt/onnx/quantization/operators.py +121 -0
  31. modelopt/onnx/quantization/ort_patching.py +1766 -0
  32. modelopt/onnx/quantization/ort_utils.py +346 -0
  33. modelopt/onnx/quantization/partitioning.py +439 -0
  34. modelopt/onnx/quantization/qdq_utils.py +1349 -0
  35. modelopt/onnx/quantization/quant_utils.py +283 -0
  36. modelopt/onnx/quantization/quantize.py +528 -0
  37. modelopt/onnx/quantization/src/modelopt_round_and_pack_ext.cpp +127 -0
  38. modelopt/onnx/trt_utils.py +424 -0
  39. modelopt/onnx/utils.py +753 -0
  40. modelopt/torch/__init__.py +41 -0
  41. modelopt/torch/_deploy/__init__.py +23 -0
  42. modelopt/torch/_deploy/_runtime/__init__.py +29 -0
  43. modelopt/torch/_deploy/_runtime/common.py +72 -0
  44. modelopt/torch/_deploy/_runtime/ort_client.py +193 -0
  45. modelopt/torch/_deploy/_runtime/registry.py +83 -0
  46. modelopt/torch/_deploy/_runtime/runtime_client.py +154 -0
  47. modelopt/torch/_deploy/_runtime/tensorrt/constants.py +108 -0
  48. modelopt/torch/_deploy/_runtime/tensorrt/engine_builder.py +324 -0
  49. modelopt/torch/_deploy/_runtime/tensorrt/hw_param_config.py +51 -0
  50. modelopt/torch/_deploy/_runtime/tensorrt/layerwise_profiling.py +178 -0
  51. modelopt/torch/_deploy/_runtime/tensorrt/parse_trtexec_log.py +151 -0
  52. modelopt/torch/_deploy/_runtime/tensorrt/tensorrt_utils.py +200 -0
  53. modelopt/torch/_deploy/_runtime/trt_client.py +219 -0
  54. modelopt/torch/_deploy/compilation.py +142 -0
  55. modelopt/torch/_deploy/device_model.py +157 -0
  56. modelopt/torch/_deploy/profiling.py +193 -0
  57. modelopt/torch/_deploy/utils/__init__.py +18 -0
  58. modelopt/torch/_deploy/utils/onnx_optimizer.py +120 -0
  59. modelopt/torch/_deploy/utils/onnx_utils.py +58 -0
  60. modelopt/torch/_deploy/utils/torch_onnx.py +593 -0
  61. modelopt/torch/distill/__init__.py +28 -0
  62. modelopt/torch/distill/config.py +130 -0
  63. modelopt/torch/distill/distillation.py +84 -0
  64. modelopt/torch/distill/distillation_model.py +318 -0
  65. modelopt/torch/distill/loss_balancers.py +140 -0
  66. modelopt/torch/distill/losses.py +275 -0
  67. modelopt/torch/distill/mode.py +223 -0
  68. modelopt/torch/distill/plugins/__init__.py +24 -0
  69. modelopt/torch/distill/plugins/huggingface.py +110 -0
  70. modelopt/torch/distill/plugins/megatron.py +476 -0
  71. modelopt/torch/distill/registry.py +23 -0
  72. modelopt/torch/export/__init__.py +24 -0
  73. modelopt/torch/export/convert_hf_config.py +117 -0
  74. modelopt/torch/export/distribute.py +300 -0
  75. modelopt/torch/export/hf_config_map.py +84 -0
  76. modelopt/torch/export/layer_utils.py +1893 -0
  77. modelopt/torch/export/mcore_config_map.py +25 -0
  78. modelopt/torch/export/model_config.py +623 -0
  79. modelopt/torch/export/model_config_export.py +552 -0
  80. modelopt/torch/export/model_config_utils.py +392 -0
  81. modelopt/torch/export/model_utils.py +71 -0
  82. modelopt/torch/export/plugins/__init__.py +21 -0
  83. modelopt/torch/export/plugins/mcore_common.py +67 -0
  84. modelopt/torch/export/plugins/mcore_custom.py +530 -0
  85. modelopt/torch/export/plugins/mcore_deepseek.py +143 -0
  86. modelopt/torch/export/plugins/mcore_gptoss.py +71 -0
  87. modelopt/torch/export/plugins/mcore_llama.py +164 -0
  88. modelopt/torch/export/plugins/mcore_nemotron.py +90 -0
  89. modelopt/torch/export/plugins/mcore_qwen.py +99 -0
  90. modelopt/torch/export/plugins/megatron_importer.py +647 -0
  91. modelopt/torch/export/postprocess.py +847 -0
  92. modelopt/torch/export/quant_utils.py +1069 -0
  93. modelopt/torch/export/tensorrt_llm_type.py +42 -0
  94. modelopt/torch/export/tensorrt_llm_utils.py +405 -0
  95. modelopt/torch/export/transformer_engine.py +94 -0
  96. modelopt/torch/export/unified_export_hf.py +537 -0
  97. modelopt/torch/export/unified_export_megatron.py +1164 -0
  98. modelopt/torch/nas/__init__.py +27 -0
  99. modelopt/torch/nas/algorithms.py +856 -0
  100. modelopt/torch/nas/autonas.py +808 -0
  101. modelopt/torch/nas/conversion.py +119 -0
  102. modelopt/torch/nas/hparams/__init__.py +19 -0
  103. modelopt/torch/nas/hparams/concat.py +319 -0
  104. modelopt/torch/nas/hparams/container.py +48 -0
  105. modelopt/torch/nas/modules/__init__.py +21 -0
  106. modelopt/torch/nas/modules/container.py +99 -0
  107. modelopt/torch/nas/modules/conv.py +254 -0
  108. modelopt/torch/nas/modules/linear.py +76 -0
  109. modelopt/torch/nas/modules/norm.py +193 -0
  110. modelopt/torch/nas/modules/utils.py +61 -0
  111. modelopt/torch/nas/patch.py +261 -0
  112. modelopt/torch/nas/plugins/__init__.py +29 -0
  113. modelopt/torch/nas/plugins/megatron.py +1497 -0
  114. modelopt/torch/nas/plugins/torch.py +71 -0
  115. modelopt/torch/nas/plugins/transformer_engine.py +42 -0
  116. modelopt/torch/nas/plugins/transformers.py +210 -0
  117. modelopt/torch/nas/registry.py +23 -0
  118. modelopt/torch/nas/search_space.py +260 -0
  119. modelopt/torch/nas/traced_hp.py +149 -0
  120. modelopt/torch/nas/utils.py +408 -0
  121. modelopt/torch/opt/__init__.py +41 -0
  122. modelopt/torch/opt/_hooks.py +98 -0
  123. modelopt/torch/opt/config.py +383 -0
  124. modelopt/torch/opt/conversion.py +620 -0
  125. modelopt/torch/opt/dynamic.py +1367 -0
  126. modelopt/torch/opt/hparam.py +275 -0
  127. modelopt/torch/opt/mode.py +353 -0
  128. modelopt/torch/opt/plugins/__init__.py +38 -0
  129. modelopt/torch/opt/plugins/diffusers.py +40 -0
  130. modelopt/torch/opt/plugins/huggingface.py +162 -0
  131. modelopt/torch/opt/plugins/mcore_dist_checkpointing.py +211 -0
  132. modelopt/torch/opt/plugins/megatron.py +142 -0
  133. modelopt/torch/opt/plugins/peft.py +108 -0
  134. modelopt/torch/opt/plugins/transformers.py +160 -0
  135. modelopt/torch/opt/searcher.py +363 -0
  136. modelopt/torch/opt/utils.py +125 -0
  137. modelopt/torch/prune/__init__.py +26 -0
  138. modelopt/torch/prune/fastnas.py +376 -0
  139. modelopt/torch/prune/gradnas.py +349 -0
  140. modelopt/torch/prune/plugins/__init__.py +24 -0
  141. modelopt/torch/prune/plugins/mcore_minitron.py +263 -0
  142. modelopt/torch/prune/plugins/transformers.py +41 -0
  143. modelopt/torch/prune/pruning.py +211 -0
  144. modelopt/torch/quantization/__init__.py +26 -0
  145. modelopt/torch/quantization/algorithms.py +671 -0
  146. modelopt/torch/quantization/backends/__init__.py +20 -0
  147. modelopt/torch/quantization/backends/fp8_per_tensor_gemm.py +204 -0
  148. modelopt/torch/quantization/backends/gemm_registry.py +156 -0
  149. modelopt/torch/quantization/backends/nvfp4_gemm.py +201 -0
  150. modelopt/torch/quantization/backends/utils.py +28 -0
  151. modelopt/torch/quantization/calib/__init__.py +25 -0
  152. modelopt/torch/quantization/calib/bias.py +172 -0
  153. modelopt/torch/quantization/calib/calibrator.py +63 -0
  154. modelopt/torch/quantization/calib/histogram.py +434 -0
  155. modelopt/torch/quantization/calib/max.py +110 -0
  156. modelopt/torch/quantization/compress.py +227 -0
  157. modelopt/torch/quantization/config.py +1180 -0
  158. modelopt/torch/quantization/conversion.py +389 -0
  159. modelopt/torch/quantization/export_onnx.py +639 -0
  160. modelopt/torch/quantization/extensions.py +89 -0
  161. modelopt/torch/quantization/mode.py +428 -0
  162. modelopt/torch/quantization/model_calib.py +949 -0
  163. modelopt/torch/quantization/model_quant.py +477 -0
  164. modelopt/torch/quantization/nn/__init__.py +26 -0
  165. modelopt/torch/quantization/nn/functional.py +109 -0
  166. modelopt/torch/quantization/nn/modules/__init__.py +16 -0
  167. modelopt/torch/quantization/nn/modules/quant_activations.py +22 -0
  168. modelopt/torch/quantization/nn/modules/quant_batchnorm.py +24 -0
  169. modelopt/torch/quantization/nn/modules/quant_conv.py +123 -0
  170. modelopt/torch/quantization/nn/modules/quant_instancenorm.py +39 -0
  171. modelopt/torch/quantization/nn/modules/quant_linear.py +258 -0
  172. modelopt/torch/quantization/nn/modules/quant_module.py +211 -0
  173. modelopt/torch/quantization/nn/modules/quant_pooling.py +99 -0
  174. modelopt/torch/quantization/nn/modules/quant_rnn.py +527 -0
  175. modelopt/torch/quantization/nn/modules/tensor_quantizer.py +1293 -0
  176. modelopt/torch/quantization/plugins/__init__.py +73 -0
  177. modelopt/torch/quantization/plugins/accelerate.py +214 -0
  178. modelopt/torch/quantization/plugins/apex.py +52 -0
  179. modelopt/torch/quantization/plugins/attention.py +312 -0
  180. modelopt/torch/quantization/plugins/custom.py +192 -0
  181. modelopt/torch/quantization/plugins/diffusers.py +237 -0
  182. modelopt/torch/quantization/plugins/fairscale.py +45 -0
  183. modelopt/torch/quantization/plugins/huggingface.py +736 -0
  184. modelopt/torch/quantization/plugins/megatron.py +462 -0
  185. modelopt/torch/quantization/plugins/peft.py +148 -0
  186. modelopt/torch/quantization/plugins/transformer_engine.py +60 -0
  187. modelopt/torch/quantization/plugins/transformers.py +52 -0
  188. modelopt/torch/quantization/plugins/transformers_trainer.py +426 -0
  189. modelopt/torch/quantization/plugins/trl.py +27 -0
  190. modelopt/torch/quantization/plugins/vllm.py +199 -0
  191. modelopt/torch/quantization/qtensor/__init__.py +24 -0
  192. modelopt/torch/quantization/qtensor/base_qtensor.py +370 -0
  193. modelopt/torch/quantization/qtensor/fp8_tensor.py +151 -0
  194. modelopt/torch/quantization/qtensor/int4_tensor.py +130 -0
  195. modelopt/torch/quantization/qtensor/int8_tensor.py +124 -0
  196. modelopt/torch/quantization/qtensor/mxfp4_tensor.py +144 -0
  197. modelopt/torch/quantization/qtensor/nf4_tensor.py +199 -0
  198. modelopt/torch/quantization/qtensor/nvfp4_tensor.py +295 -0
  199. modelopt/torch/quantization/src/tensor_quant.cpp +77 -0
  200. modelopt/torch/quantization/src/tensor_quant.h +69 -0
  201. modelopt/torch/quantization/src/tensor_quant_fp8.cpp +48 -0
  202. modelopt/torch/quantization/src/tensor_quant_gpu.cu +361 -0
  203. modelopt/torch/quantization/src/tensor_quant_gpu_fp8.cu +122 -0
  204. modelopt/torch/quantization/src/tensor_quant_mx.cu +411 -0
  205. modelopt/torch/quantization/src/tensor_quant_mx.h +247 -0
  206. modelopt/torch/quantization/tensor_quant.py +816 -0
  207. modelopt/torch/quantization/triton/__init__.py +36 -0
  208. modelopt/torch/quantization/triton/fp4_kernel.py +303 -0
  209. modelopt/torch/quantization/utils.py +443 -0
  210. modelopt/torch/sparsity/__init__.py +19 -0
  211. modelopt/torch/sparsity/config.py +51 -0
  212. modelopt/torch/sparsity/magnitude.py +148 -0
  213. modelopt/torch/sparsity/mode.py +203 -0
  214. modelopt/torch/sparsity/module.py +87 -0
  215. modelopt/torch/sparsity/plugins/__init__.py +27 -0
  216. modelopt/torch/sparsity/plugins/megatron.py +93 -0
  217. modelopt/torch/sparsity/searcher.py +84 -0
  218. modelopt/torch/sparsity/sparsegpt.py +276 -0
  219. modelopt/torch/sparsity/sparsification.py +123 -0
  220. modelopt/torch/speculative/__init__.py +20 -0
  221. modelopt/torch/speculative/config.py +100 -0
  222. modelopt/torch/speculative/eagle/__init__.py +20 -0
  223. modelopt/torch/speculative/eagle/conversion.py +67 -0
  224. modelopt/torch/speculative/eagle/default_config.py +50 -0
  225. modelopt/torch/speculative/eagle/eagle_model.py +51 -0
  226. modelopt/torch/speculative/eagle/utils.py +91 -0
  227. modelopt/torch/speculative/medusa/__init__.py +19 -0
  228. modelopt/torch/speculative/medusa/conversion.py +59 -0
  229. modelopt/torch/speculative/medusa/medusa_model.py +32 -0
  230. modelopt/torch/speculative/mode.py +86 -0
  231. modelopt/torch/speculative/plugins/__init__.py +33 -0
  232. modelopt/torch/speculative/plugins/megatron_eagle.py +2119 -0
  233. modelopt/torch/speculative/plugins/megatron_medusa.py +312 -0
  234. modelopt/torch/speculative/plugins/transformers.py +1138 -0
  235. modelopt/torch/speculative/speculative_decoding.py +59 -0
  236. modelopt/torch/speculative/utils.py +364 -0
  237. modelopt/torch/trace/__init__.py +25 -0
  238. modelopt/torch/trace/analyzer.py +1368 -0
  239. modelopt/torch/trace/modules/__init__.py +19 -0
  240. modelopt/torch/trace/modules/concat.py +384 -0
  241. modelopt/torch/trace/modules/nn.py +153 -0
  242. modelopt/torch/trace/plugins/__init__.py +34 -0
  243. modelopt/torch/trace/plugins/megatron.py +36 -0
  244. modelopt/torch/trace/plugins/transformers.py +58 -0
  245. modelopt/torch/trace/symbols.py +545 -0
  246. modelopt/torch/trace/tracer.py +331 -0
  247. modelopt/torch/utils/__init__.py +28 -0
  248. modelopt/torch/utils/_pytree.py +133 -0
  249. modelopt/torch/utils/cpp_extension.py +91 -0
  250. modelopt/torch/utils/dataset_utils.py +484 -0
  251. modelopt/torch/utils/distributed.py +311 -0
  252. modelopt/torch/utils/graph.py +123 -0
  253. modelopt/torch/utils/image_processor.py +112 -0
  254. modelopt/torch/utils/import_utils.py +35 -0
  255. modelopt/torch/utils/list.py +54 -0
  256. modelopt/torch/utils/logging.py +127 -0
  257. modelopt/torch/utils/memory_monitor.py +146 -0
  258. modelopt/torch/utils/network.py +658 -0
  259. modelopt/torch/utils/perf.py +174 -0
  260. modelopt/torch/utils/plugins/__init__.py +27 -0
  261. modelopt/torch/utils/plugins/megatron_generate.py +299 -0
  262. modelopt/torch/utils/plugins/megatron_mmlu.py +152 -0
  263. modelopt/torch/utils/plugins/megatron_preprocess_data.py +200 -0
  264. modelopt/torch/utils/random.py +163 -0
  265. modelopt/torch/utils/speech_dataset_utils.py +134 -0
  266. modelopt/torch/utils/tensor.py +87 -0
  267. modelopt/torch/utils/vlm_dataset_utils.py +110 -0
  268. nvidia_modelopt-0.35.0.dist-info/METADATA +171 -0
  269. nvidia_modelopt-0.35.0.dist-info/RECORD +272 -0
  270. nvidia_modelopt-0.35.0.dist-info/WHEEL +5 -0
  271. nvidia_modelopt-0.35.0.dist-info/licenses/LICENSE +14 -0
  272. nvidia_modelopt-0.35.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,462 @@
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
+ """Support quantization for megatron linear layers."""
17
+
18
+ import warnings
19
+ from typing import Any
20
+
21
+ import megatron.core.parallel_state as mcore_parallel
22
+ import megatron.core.tensor_parallel.layers as megatron_parallel
23
+ import megatron.core.transformer.mlp as megatron_mlp
24
+ import torch
25
+ from megatron.core.tensor_parallel.mappings import gather_from_sequence_parallel_region
26
+ from megatron.core.transformer import MegatronModule
27
+ from megatron.core.transformer.utils import make_sharded_tensors_for_checkpoint
28
+ from megatron.core.utils import get_tensor_model_parallel_group_if_none
29
+
30
+ from modelopt.torch.opt.plugins.megatron import (
31
+ _MegatronMLP,
32
+ register_modelopt_extra_state_callbacks,
33
+ )
34
+ from modelopt.torch.utils.distributed import ParallelState
35
+
36
+ from ..nn import QuantModuleRegistry, TensorQuantizer
37
+ from ..nn.modules.quant_linear import RealQuantLinear
38
+ from ..qtensor import QTensorWrapper
39
+ from .custom import CUSTOM_MODEL_PLUGINS, _ParallelLinear
40
+
41
+ __all__ = []
42
+
43
+
44
+ def real_quant_module_get_extra_state(self) -> dict:
45
+ """Populating real_quantizer_state and q_tensor_state."""
46
+ extra_state = {}
47
+
48
+ if isinstance(self, RealQuantLinear) and isinstance(self.weight, QTensorWrapper):
49
+ real_quantizer_state = self.weight_quantizer.get_modelopt_state()
50
+ q_tensor_state = self.weight.get_state()
51
+ elif isinstance(self, RealQuantLinear):
52
+ real_quantizer_state = self.weight_quantizer.get_modelopt_state()
53
+ q_tensor_state = {}
54
+ else:
55
+ real_quantizer_state = None
56
+ q_tensor_state = None
57
+
58
+ extra_state["modelopt_real_quantizer_state"] = real_quantizer_state
59
+ extra_state["modelopt_q_tensor_state"] = q_tensor_state
60
+
61
+ return extra_state
62
+
63
+
64
+ def quant_module_get_extra_state(self) -> dict:
65
+ """Populating the extra_state when state_dict() is called.
66
+
67
+ quantizer_state, real_quantizer_state, and q_tensor_state are usually stored
68
+ with in the modelopt_state metadata where the keys are the full module name. The issue
69
+ is that NeMo-MCore model's full module name can change
70
+ if pipeline-parallelism (PP) and expert-parallelism (EP)
71
+ are changing. Alternatively, we store quantizer_state in
72
+ QuantModule's extra_state with QuantModule.get_extra_state()
73
+ which avoids the need to store the full module name.
74
+ """
75
+ extra_state = {}
76
+
77
+ is_enabled = self.weight_quantizer.is_enabled if hasattr(self, "weight_quantizer") else False
78
+
79
+ if not is_enabled:
80
+ return extra_state
81
+
82
+ quantizer_state = {}
83
+ for name, module in self.named_modules():
84
+ if isinstance(module, TensorQuantizer):
85
+ quantizer_state[name] = module.get_modelopt_state()
86
+
87
+ extra_state["modelopt_quantizer_state"] = quantizer_state
88
+
89
+ # Handle real_quantizer_state and q_tensor_state
90
+ extra_state.update(real_quant_module_get_extra_state(self))
91
+
92
+ return extra_state
93
+
94
+
95
+ def real_quant_module_set_extra_state(self, state: Any):
96
+ """Restore q_tensor_state when load_state_dict() is called.
97
+
98
+ We skip restoring real_quantizer_state (if exists), since it is the same as
99
+ the weight_quantizer fake quantizer_state.
100
+
101
+ Finally, q_tensor_state is restored if meta device initialization is used. During
102
+ meta-device initialization, real_quantize is not called.
103
+ QTensorWrapper should replace the original weight parameter. Due to TP, we also need
104
+ to adjust q_tensor_data_shape and its metadata shape attribute to use the local weight shape.
105
+
106
+ When not using meta device initialization, real_quantize is called during compress mode
107
+ restore where the QTensor will be recomputed based on the local weights. Hence we don't
108
+ need to restore q_tensor_state.
109
+
110
+ Note:
111
+ The entire restore process can happen on meta device and be materialized later
112
+ with to_empty(). However, to_empty() will reassign the parameter and the
113
+ QTensorWrapper will be removed. We patch RealQuantLinear._apply to preserve
114
+ QTensorWrapper when to_empty() is applied.
115
+ """
116
+ q_tensor_state = state.get("modelopt_q_tensor_state", None)
117
+
118
+ if q_tensor_state is not None:
119
+ q_tensor_metadata = q_tensor_state["metadata"]
120
+ q_tensor_metadata["shape"] = self.weight.shape
121
+ q_tensor_data_dtype = q_tensor_state["quantized_data.dtype"]
122
+ q_tensor_shape = self.weight.shape
123
+
124
+ # If q_tensor_data_type is uint8, then it is compressed format of 2 elements.
125
+ if q_tensor_data_dtype == torch.uint8:
126
+ q_tensor_shape = list(q_tensor_shape)
127
+ q_tensor_shape[-1] = q_tensor_shape[-1] // 2
128
+ q_tensor_shape = torch.Size(q_tensor_shape)
129
+
130
+ self._parameters["weight"] = QTensorWrapper(
131
+ qtensor=torch.empty(
132
+ q_tensor_shape, # Use the local shape directly (TP-aware)
133
+ dtype=q_tensor_data_dtype,
134
+ device=self.weight.device,
135
+ ),
136
+ metadata=q_tensor_metadata,
137
+ )
138
+
139
+
140
+ def quant_module_set_extra_state(self, state: Any):
141
+ """Restore quantizer_state when load_state_dict() is called.
142
+
143
+ With quantizer_state stored in extra_state (NeMo-MCore `torch-dist`),
144
+ set_extra_state() is used to perform the functionality
145
+ conversion.restore_quantizer_state().
146
+ load_state_dict() are called twice during NeMo-MCore resume.
147
+ The state_dict only contains the extra_state in the first time.
148
+ set_extra_state() is trigger by the end of the load_state_dict()
149
+ where QuantModule.modelopt_post_restore() will reinitialize
150
+ amax and scalars to the correct shape.
151
+ The 2nd load_state_dict() is loading all states including amax and
152
+ scalars. We disable QuantModule.modelopt_post_restore() to avoid
153
+ reinitialization since set_extra_state() is called at the end.
154
+
155
+ We first restore all fake quantizer_state. Per QuantModule can have
156
+ weight_quantizer, input_quantizer, and output_quantizer.
157
+
158
+ Once all quantizer_state are resumed, modelopt_post_restore() is called
159
+ to adjust the shape of all buffers (amax, pre_qunat_scale, _scale, ...) since
160
+ the local shape can be different from the shape in the state due to change
161
+ in tensor parallelism (TP).
162
+ """
163
+ if state is None or not self.allow_post_restore:
164
+ return
165
+
166
+ quantizer_state = state.get("modelopt_quantizer_state", None)
167
+
168
+ if quantizer_state is not None:
169
+ for name, module in self.named_modules():
170
+ if isinstance(module, TensorQuantizer):
171
+ module.set_from_modelopt_state(quantizer_state[name], properties_only=False)
172
+ self.modelopt_post_restore()
173
+
174
+ # Handle real_quantizer_state and q_tensor_state
175
+ real_quant_module_set_extra_state(self, state)
176
+
177
+ self.allow_post_restore = False
178
+
179
+
180
+ def megatron_replace_quant_module_hook(model: torch.nn.Module):
181
+ """Configure Megatron-Core model quantization support.
182
+
183
+ This callback is called before the QuantModule replacement to reuse the current
184
+ custom callback infra. However, it is meant to target each QuantModule.
185
+ Since the callback is called when megatron is installed, we do a type check on
186
+ MegatronModule first. For each MegatronModule,
187
+ 1. We change TransformerConfig to enable heterogenous distributed checkpointing.
188
+ 2. We enable all sub- QuantModule to store quantizer_state as extra_state by
189
+ typing-matching the QuantModuleRegistry.
190
+ """
191
+
192
+ def _register_extra_state_callbacks(model: torch.nn.Module):
193
+ for name, module in model.named_modules():
194
+ if type(module) in QuantModuleRegistry:
195
+ # This module will be replaced as a QuantModule
196
+ register_modelopt_extra_state_callbacks(
197
+ module,
198
+ quant_module_get_extra_state,
199
+ quant_module_set_extra_state,
200
+ )
201
+
202
+ for name, module in model.named_modules():
203
+ if isinstance(module, MegatronModule):
204
+ if "vision_model" not in name:
205
+ # We only enable hetereogenous_dist_checkpoint for language model, vision model is not quantized
206
+ module.config.hetereogenous_dist_checkpoint = True
207
+ _register_extra_state_callbacks(module)
208
+
209
+
210
+ CUSTOM_MODEL_PLUGINS.add(megatron_replace_quant_module_hook)
211
+
212
+
213
+ class _MegatronParallelLinear(_ParallelLinear):
214
+ _functionals_to_replace = [
215
+ (megatron_parallel, "linear_with_grad_accumulation_and_async_allreduce"),
216
+ (megatron_parallel, "linear_with_frozen_weight"),
217
+ ]
218
+
219
+ def _setup(self):
220
+ self.parallel_state = ParallelState(
221
+ getattr(mcore_parallel, "get_expert_data_parallel_group", "get_data_parallel_group")(),
222
+ mcore_parallel.get_tensor_model_parallel_group(),
223
+ )
224
+ super()._setup()
225
+
226
+ def _process_quantizer_amax(self, k, v, quantizer_state_dict):
227
+ if v.ndim == 4:
228
+ quantizer_state_dict[k] = v.squeeze(1).squeeze(-1)
229
+ else:
230
+ quantizer_state_dict[k] = (
231
+ v.view(self.weight.shape[0], -1) if v.numel() > 1 else v.view(-1)
232
+ )
233
+
234
+ def _process_activation_quantizer_pre_quant_scale(self, k, v, quantizer_state_dict):
235
+ quantizer_state_dict[k] = v
236
+
237
+ def _get_shard_axis_dict(self, state_dict):
238
+ raise NotImplementedError
239
+
240
+ def _parameter_to_keep_in_quantizer_state_dict(self, key):
241
+ """Determine whether a parameter should be kept in the quantizer_state_dict.
242
+
243
+ Used to include additional quantization parameters (e.g., _scale for real quant)
244
+ beyond the default amax and pre_quant_scale tensors.
245
+
246
+ Note: When adding parameters here, update _get_shard_axis_dict accordingly for sharding.
247
+ """
248
+ return False
249
+
250
+ def sharded_state_dict(self, prefix="", sharded_offsets=(), metadata=None):
251
+ # [WAR]: although we disable output_layer quantization by default but it will
252
+ # still be picked up by mtq.quantize since it is a ColumnParallelLinear. We need
253
+ # to further ensure that its sharded state_dict has no scalars or amax since
254
+ # 1) NeMo-MCore's vocabulary padding may change but we didn't support this feature
255
+ # 2) When embedding and output_layer are sharing weights, PP>1 will have
256
+ # output_layer.input_quantizer._amax but TP-only does not. This lead to
257
+ # state_dict mismatch.
258
+ if prefix.endswith("output_layer."):
259
+ # assert not any("_quantizer" in k for k in self.state_dict()), "quantized output_layer"
260
+ return super().sharded_state_dict(prefix, sharded_offsets)
261
+
262
+ quantizer_state_dict = {}
263
+ for k, v in self.state_dict(prefix="", keep_vars=True).items():
264
+ if "_quantizer" in k and "_amax" in k:
265
+ self._process_quantizer_amax(k, v, quantizer_state_dict)
266
+ elif k == "input_quantizer._pre_quant_scale":
267
+ self._process_activation_quantizer_pre_quant_scale(k, v, quantizer_state_dict)
268
+ elif self._parameter_to_keep_in_quantizer_state_dict(k):
269
+ quantizer_state_dict[k] = v
270
+ elif "quantizer" in k:
271
+ warnings.warn(
272
+ f"Quantizer state {k} is not supported for sharded_state_dict. "
273
+ "Please use regular state_dict."
274
+ )
275
+ sharded_axis_dict = self._get_shard_axis_dict(quantizer_state_dict)
276
+ sharded_state_dict = super().sharded_state_dict(prefix, sharded_offsets)
277
+ sharded_state_dict.update(
278
+ **make_sharded_tensors_for_checkpoint(
279
+ quantizer_state_dict, prefix, sharded_axis_dict, sharded_offsets
280
+ )
281
+ )
282
+ return sharded_state_dict
283
+
284
+ def _load_from_state_dict(self, state_dict, prefix, *args, **kwargs):
285
+ for k in list(state_dict.keys()):
286
+ if not any(qt + "_quantizer" in k for qt in ["weight", "input", "output"]):
287
+ continue
288
+ name = k.split(prefix)[-1] if prefix else k
289
+ state_dict[k] = state_dict[k].view_as(self.state_dict()[name])
290
+ super()._load_from_state_dict(state_dict, prefix, *args, **kwargs)
291
+
292
+
293
+ @QuantModuleRegistry.register(
294
+ {megatron_parallel.ColumnParallelLinear: "megatron_ColumnParallelLinear"}
295
+ )
296
+ class _MegatronColumnParallelLinear(_MegatronParallelLinear):
297
+ _is_column_parallel = True
298
+
299
+ def _get_shard_axis_dict(self, state_dict):
300
+ """Getting the sharded axis for amax and pre_quant_scale.
301
+
302
+ By default, ColumnParallelLinear shards the output dimension (dim=0). However,
303
+ depending the quantization algorithm, not all amax or pre_quant_scale need
304
+ to be sharded.
305
+
306
+ We check the quantizer.axis to decide whether an amax needs to be sharded.
307
+ Except for dynamic block quantization (NVFP4, axis: None) or per-tensor (FP8,
308
+ axis: None), the rest of algorithms all need to be sharded
309
+
310
+ Prequant scaling is applied per-input-channel; hence no sharding is required.
311
+ """
312
+ shard_axis_dict = {}
313
+ for k in state_dict:
314
+ if "weight_quantizer." in k:
315
+ weight_quantizer_axis = self.get_submodule(k.rsplit(".", 1)[0]).axis
316
+ if weight_quantizer_axis is not None:
317
+ shard_axis_dict[k] = 0
318
+ return shard_axis_dict
319
+
320
+
321
+ @QuantModuleRegistry.register({megatron_parallel.RowParallelLinear: "megatron_RowParallelLinear"})
322
+ class _MegatronRowParallelLinear(_MegatronParallelLinear):
323
+ _is_row_parallel = True
324
+
325
+ def _get_shard_axis_dict(self, state_dict):
326
+ """Getting the sharded axis for amax and pre_quant_scale.
327
+
328
+ By default, RowParallelLinear shards the input dimension (dim=1). However,
329
+ depending the quantization algorithm, not all amax or pre_quant_scale need
330
+ to be shard.
331
+
332
+ We check the quantizer.axis to decide whether an amax needs to be sharded.
333
+ Only static block quantization needs to be sharded and its axis is either (0,) or (0, 2).
334
+ The first case is used in AWQ the later case is used in blocked 2D quantization.
335
+ Dynamic block quantization (NVFP4 axis:None), per-tensor (FP8, axis: None)
336
+ and per-channel (INT8_SQ or FP8_PER_CHANNEL, axis: 1) do not require input sharding.
337
+
338
+ Prequant scaling is applied per-input-channel; hence it is always sharded.
339
+ """
340
+ shard_axis_dict = {}
341
+ for k in state_dict:
342
+ if "weight_quantizer." in k:
343
+ weight_quantizer_axis = None
344
+ if isinstance(self.weight_quantizer, TensorQuantizer):
345
+ weight_quantizer_axis = self.weight_quantizer.axis
346
+ elif "weight_quantizer.0." in k:
347
+ weight_quantizer_axis = self.weight_quantizer[0].axis
348
+ elif "weight_quantizer.1." in k:
349
+ weight_quantizer_axis = self.weight_quantizer[1].axis
350
+ if isinstance(weight_quantizer_axis, tuple):
351
+ shard_axis_dict[k] = 1
352
+ if k == "input_quantizer._pre_quant_scale":
353
+ shard_axis_dict[k] = 0
354
+ return shard_axis_dict
355
+
356
+
357
+ @QuantModuleRegistry.register({megatron_mlp.MLP: "megatron_MegatronMLP"})
358
+ class _QuantMegatronMLP(_MegatronMLP):
359
+ """Module to support special handling of `linear_fc1` in `sharded_state_dict()` of MCore `MLP`."""
360
+
361
+ _modelopt_state_keys = [
362
+ r"weight_quantizer\.(\d+\.)*_amax$",
363
+ r"weight_quantizer\.(\d+\.)*_scale$",
364
+ ]
365
+
366
+
367
+ class _RealQuantMegatronParallelLinear(RealQuantLinear):
368
+ allow_real_quant_gemm = True
369
+ _scale_tensor_shard_axis = None
370
+
371
+ def _parameter_to_keep_in_quantizer_state_dict(self, key):
372
+ return any(k in key for k in self.list_of_scale_tensors)
373
+
374
+ def _get_shard_axis_dict(self, state_dict):
375
+ shard_axis_dict = super()._get_shard_axis_dict(state_dict)
376
+ for k in state_dict:
377
+ if (
378
+ any(k.endswith(suffix) for suffix in self.list_of_scale_tensors)
379
+ and state_dict[k].dim() > 1
380
+ ):
381
+ assert self._scale_tensor_shard_axis is not None, (
382
+ "scale_tensor_shard_axis is not set, please set it in the subclass"
383
+ )
384
+ shard_axis_dict[k] = self._scale_tensor_shard_axis
385
+ return shard_axis_dict
386
+
387
+ def modelopt_post_restore(self, prefix: str = ""):
388
+ """Post restore to correctly configure the realquant scales.
389
+
390
+ ModelOpt restores the TensorQuantizer states such as `_amax` and `_pre_quant_scale` to their
391
+ shape before saving. However this is not enough for MCore/distributed frameworks since the tensor parallelism
392
+ could change between saving and restoring. If the tensor parallelism changes, the shape of the quantizer
393
+ states also changes. So we need to re-calculate the quantizer states.
394
+
395
+ Note:
396
+ During real quantization, weight_quantizer._fake_quant is set to False which trigger the real quant
397
+ forward path and lead to error. We enable the weight_quantizer fake_quant forward path while recompute
398
+ the correct shape.
399
+ """
400
+ self.weight_quantizer._fake_quant = True
401
+ super().modelopt_post_restore(prefix=prefix)
402
+ self.weight_quantizer._fake_quant = False
403
+
404
+ if hasattr(self.weight_quantizer, "_scale"):
405
+ # Recompute all real quantization buffer shapes
406
+ self.weight_quantizer._real_quantize(self.weight)
407
+
408
+ def _forward_impl(self, input, *args, **kwargs):
409
+ """Use real quant gemm if available.
410
+
411
+ Here the forward is patched such that real quant gemm can be called if available. Both conditions
412
+ below must be satisfied (static and dynamic check based on input args) to use the kernel.
413
+ Otherwise, we fallback.
414
+
415
+ Note:
416
+ RealQuantLinear.forward() is doing the same check inside and will fall back to use the super
417
+ class forward(). This is not desired since _forward_impl introduces much more args and kwargs
418
+ while the original forward only takes 1 positional argument. We must above the fallback path
419
+ in RealQuantLinear.forward().
420
+ """
421
+ if self._should_run_real_quant_gemm and self.get_real_quant_gemm_impl(
422
+ input, *args, **kwargs
423
+ ):
424
+ allreduce_dgrad = kwargs.get("allreduce_dgrad", False)
425
+ tp_group = kwargs.get("tp_group")
426
+ sequence_parallel = kwargs.get("sequence_parallel", False)
427
+
428
+ tp_group = get_tensor_model_parallel_group_if_none(tp_group)
429
+
430
+ if sequence_parallel:
431
+ input = gather_from_sequence_parallel_region(
432
+ input, tensor_parallel_output_grad=True, group=tp_group
433
+ )
434
+ else:
435
+ input = input
436
+
437
+ return RealQuantLinear.forward(
438
+ self,
439
+ input,
440
+ allreduce_dgrad=allreduce_dgrad,
441
+ tp_group=tp_group,
442
+ )
443
+ else:
444
+ return super()._forward_impl(input, *args, **kwargs)
445
+
446
+
447
+ class _RealQuantMegatronColumnParallelLinear(
448
+ _RealQuantMegatronParallelLinear, _MegatronColumnParallelLinear
449
+ ):
450
+ _scale_tensor_shard_axis = 0
451
+
452
+ def forward(self, input, *args, **kwargs):
453
+ return _MegatronColumnParallelLinear.forward(self, input, *args, **kwargs)
454
+
455
+
456
+ class _RealQuantMegatronRowParallelLinear(
457
+ _RealQuantMegatronParallelLinear, _MegatronRowParallelLinear
458
+ ):
459
+ _scale_tensor_shard_axis = 1
460
+
461
+ def forward(self, input, *args, **kwargs):
462
+ return _MegatronRowParallelLinear.forward(self, input, *args, **kwargs)
@@ -0,0 +1,148 @@
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
+ """Support quantization for peft LoRA linear layers."""
17
+
18
+ from contextlib import contextmanager
19
+
20
+ import torch.nn.functional as F
21
+ from peft.tuners.lora.layer import Linear as LoraLinear
22
+ from peft.tuners.lora.layer import ParamWrapper
23
+
24
+ from modelopt.torch.opt.dynamic import DynamicModule
25
+ from modelopt.torch.quantization.qtensor.base_qtensor import QTensorWrapper
26
+
27
+ from ..nn import QuantModule, QuantModuleRegistry, TensorQuantizer
28
+ from .huggingface import _transposed_quantize
29
+
30
+ __all__ = []
31
+
32
+
33
+ @QuantModuleRegistry.register({LoraLinear: "LoraLinear"})
34
+ class _QuantLoraLinear(QuantModule):
35
+ def _setup(self):
36
+ self.input_quantizer = TensorQuantizer()
37
+ self.weight_quantizer = TensorQuantizer()
38
+ self.output_quantizer = TensorQuantizer()
39
+
40
+ def _is_compressed_weight(self, weight):
41
+ return isinstance(weight, QTensorWrapper)
42
+
43
+ def forward(self, x, *args, **kwargs):
44
+ adapter_names = kwargs.pop("adapter_names", None)
45
+ if self.disable_adapters or adapter_names is not None or self.merged:
46
+ return super().forward(x, *args, **kwargs)
47
+
48
+ x = self.input_quantizer(x)
49
+ weight = self.base_layer.weight
50
+
51
+ if not self._is_compressed_weight(weight):
52
+ for active_adapter in self.active_adapters:
53
+ if active_adapter not in self.lora_A.keys(): # noqa: SIM118
54
+ continue
55
+ lora_a = self.lora_A[active_adapter]
56
+ lora_b = self.lora_B[active_adapter]
57
+ scaling = self.scaling[active_adapter]
58
+
59
+ if not self.use_dora[active_adapter]:
60
+ weight = weight + ((scaling * lora_b.weight) @ lora_a.weight).to(
61
+ weight.device, weight.dtype
62
+ )
63
+ else:
64
+ raise NotImplementedError("dora not implemented")
65
+ weight = self.weight_quantizer(weight)
66
+ output = F.linear(x, weight, self.base_layer.bias)
67
+ else:
68
+ # TODO: Move this to RealQuantLoraLinear
69
+ # For compressed weights, compute base output and LoRA outputs separately
70
+ base_output = self.base_layer(x)
71
+
72
+ # Only compute LoRA outputs if there are active adapters
73
+ if self.active_adapters:
74
+ # Start with zero LoRA output
75
+ lora_output = None
76
+
77
+ for active_adapter in self.active_adapters:
78
+ if active_adapter not in self.lora_A.keys(): # noqa: SIM118
79
+ continue
80
+ lora_a = self.lora_A[active_adapter]
81
+ lora_b = self.lora_B[active_adapter]
82
+ scaling = self.scaling[active_adapter]
83
+
84
+ if not self.use_dora[active_adapter]:
85
+ # Compute LoRA output step by step to maintain gradient flow
86
+ lora_a_output = F.linear(x, lora_a.weight)
87
+ lora_b_output = F.linear(lora_a_output, lora_b.weight)
88
+ adapter_output = scaling * lora_b_output
89
+
90
+ lora_output = (
91
+ adapter_output if lora_output is None else lora_output + adapter_output
92
+ )
93
+
94
+ output = base_output + lora_output
95
+ else:
96
+ output = base_output
97
+
98
+ output = self.output_quantizer(output)
99
+ return output
100
+
101
+ def merge(self, *args, **kwargs):
102
+ assert not self._is_compressed_weight(self.base_layer.weight), (
103
+ "We dont support merging for QLoRA yet!"
104
+ )
105
+ super().merge(*args, **kwargs)
106
+ base_layer = self.get_base_layer()
107
+ base_layer.input_quantizer = self.input_quantizer
108
+ base_layer.weight_quantizer = self.weight_quantizer
109
+ base_layer.output_quantizer = self.output_quantizer
110
+
111
+
112
+ @QuantModuleRegistry.register({ParamWrapper: "ParamWrapper"})
113
+ class _QuantParamWrapper(QuantModule):
114
+ def _setup(self):
115
+ pass
116
+
117
+ @contextmanager
118
+ def _activate_lora(self, active_adapters: list[str]):
119
+ base_layer = self.get_base_layer()
120
+ if not isinstance(base_layer, DynamicModule) or not hasattr(
121
+ base_layer, self.parameter_name + "_weight_quantizer"
122
+ ):
123
+ with super()._activate_lora(active_adapters):
124
+ yield
125
+ return
126
+
127
+ delta_weight = None
128
+ for active_adapter in active_adapters:
129
+ if active_adapter not in self.lora_A:
130
+ continue
131
+ delta_weight = (
132
+ self.get_delta_weight(active_adapter)
133
+ if delta_weight is None
134
+ else delta_weight + self.get_delta_weight(active_adapter)
135
+ )
136
+
137
+ quantizer = getattr(base_layer, self.parameter_name + "_weight_quantizer")
138
+ with base_layer.reset_dynamic_attributes():
139
+ base_param = getattr(base_layer, self.parameter_name)
140
+ quantized_val = _transposed_quantize(
141
+ base_param if delta_weight is None else base_param + delta_weight, quantizer
142
+ )
143
+ delattr(base_layer, self.parameter_name)
144
+ setattr(base_layer, self.parameter_name, quantized_val)
145
+ try:
146
+ yield
147
+ finally:
148
+ setattr(base_layer, self.parameter_name, base_param)
@@ -0,0 +1,60 @@
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
+ """Support quantization for Transformer Engine layers."""
17
+
18
+ import torch
19
+ import transformer_engine as te
20
+ import transformer_engine.pytorch.module.linear as te_linear
21
+
22
+ from ..nn import QuantModuleRegistry
23
+ from .custom import _ParallelLinear
24
+
25
+
26
+ @QuantModuleRegistry.register({te.pytorch.Linear: "te_Linear"})
27
+ class _QuantTELinear(_ParallelLinear):
28
+ _functionals_to_replace = [
29
+ (
30
+ te_linear._Linear,
31
+ "apply" if torch.is_grad_enabled() else "forward",
32
+ ),
33
+ ]
34
+
35
+ @staticmethod
36
+ def te_quantized_linear_fn(package, func_name, self, *args, **kwargs):
37
+ """Quantized version specifically for TE with weight first, then input."""
38
+ if te.__version__ >= "2.0":
39
+ weight, inputs = args[0], args[1]
40
+ remaining_args = args[2:]
41
+ output = getattr(package, func_name)(
42
+ self.weight_quantizer(weight),
43
+ self.input_quantizer(inputs),
44
+ *remaining_args,
45
+ **kwargs,
46
+ )
47
+ else:
48
+ weight, weight_fp8, inputs = args[0], args[1], args[2]
49
+ remaining_args = args[3:]
50
+ output = getattr(package, func_name)(
51
+ self.weight_quantizer(weight),
52
+ weight_fp8,
53
+ self.input_quantizer(inputs),
54
+ *remaining_args,
55
+ **kwargs,
56
+ )
57
+ return self.output_quantizer(output)
58
+
59
+ # Override the quantized linear function
60
+ _quantized_linear_fn = te_quantized_linear_fn