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,73 @@
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
+ """Handles quantization plugins to correctly quantize third-party modules.
17
+
18
+ Please check out the source code of this module for examples of how plugins work and how you can
19
+ write your own one. Currently, we support plugins for
20
+
21
+ - :meth:`apex<modelopt.torch.quantization.plugins.apex>`
22
+ - :meth:`attention<modelopt.torch.quantization.plugins.attention>`
23
+ - :meth:`diffusers<modelopt.torch.quantization.plugins.diffusers>`
24
+ - :meth:`fairscale<modelopt.torch.quantization.plugins.fairscale>`
25
+ - :meth:`huggingface<modelopt.torch.quantization.plugins.huggingface>`
26
+ - :meth:`megatron<modelopt.torch.quantization.plugins.megatron>`
27
+ - :meth:`peft<modelopt.torch.quantization.plugins.peft>`
28
+ - :meth:`transformer_engine<modelopt.torch.quantization.plugins.transformer_engine>`
29
+ """
30
+
31
+ from modelopt.torch.utils import import_plugin
32
+
33
+ with import_plugin("accelerate"):
34
+ from .accelerate import *
35
+
36
+ with import_plugin("apex"):
37
+ from .apex import *
38
+
39
+ from .attention import *
40
+ from .custom import *
41
+
42
+ with import_plugin("diffusers"):
43
+ from .diffusers import *
44
+
45
+ with import_plugin("fairscale"):
46
+ from .fairscale import *
47
+
48
+ with import_plugin("huggingface"):
49
+ from .huggingface import *
50
+
51
+ with import_plugin("megatron"):
52
+ from .megatron import *
53
+
54
+ with import_plugin("nemo"):
55
+ from .nemo import *
56
+
57
+ with import_plugin("peft"):
58
+ from .peft import *
59
+
60
+ with import_plugin("transformer_engine"):
61
+ from .transformer_engine import *
62
+
63
+ with import_plugin("transformers trainer"):
64
+ from .transformers_trainer import *
65
+
66
+ with import_plugin("transformers"):
67
+ from .transformers import *
68
+
69
+ with import_plugin("vllm"):
70
+ from .vllm import *
71
+
72
+ with import_plugin("trl"):
73
+ from .trl import *
@@ -0,0 +1,214 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2023-2025 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
+ """Quantization support for accelerate modified models."""
16
+
17
+ import warnings
18
+ from contextlib import contextmanager
19
+ from typing import Any
20
+
21
+ import torch
22
+ import transformers
23
+ from accelerate import init_empty_weights, load_checkpoint_and_dispatch
24
+ from accelerate.hooks import AlignDevicesHook, SequentialHook
25
+ from accelerate.utils import get_max_memory, infer_auto_device_map
26
+ from accelerate.utils.dataclasses import CustomDtype
27
+ from accelerate.utils.offload import PrefixedDataset
28
+
29
+ import modelopt.torch.quantization as mtq
30
+
31
+ __all__ = ["init_quantized_weights"]
32
+
33
+
34
+ def _get_cpu_offload_hook(hook):
35
+ if isinstance(hook, AlignDevicesHook) and hook.offload and hook.weights_map is not None:
36
+ assert "weight" in hook.weights_map
37
+ if (
38
+ isinstance(hook.weights_map, PrefixedDataset)
39
+ and hook.weights_map.prefix + "weight" not in hook.weights_map.dataset.state_dict
40
+ ):
41
+ raise NotImplementedError(
42
+ "This layer could be offloaded to disk. We don't support this yet."
43
+ )
44
+ return hook
45
+ elif isinstance(hook, SequentialHook):
46
+ for h in hook.hooks:
47
+ align_hook = _get_cpu_offload_hook(h)
48
+ if align_hook is not None:
49
+ return align_hook
50
+ return None
51
+
52
+
53
+ @contextmanager
54
+ def weight_access_and_writeback_context(module):
55
+ """Context manager for weight access and writeback for modules managed by accelerate."""
56
+ assert hasattr(module, "_hf_hook")
57
+ align_hook = _get_cpu_offload_hook(module._hf_hook)
58
+
59
+ if align_hook:
60
+ # Accelerate uses AlignDevicesHook to offload weights to CPU/Disk and then reload them in the forward pass
61
+ # The CPU/Disk offloaded weights are managed by PrefixDataset and OffloadedWeightsLoader
62
+ # See https://github.com/huggingface/accelerate/blame/f48d95c4939b281505a45b3d6e0bf554b65cc1ea/src/accelerate/utils/offload.py#L104-L141
63
+ # TODO: Add support for disk-offloaded models if needed (they will be really slow, hence low priority)
64
+
65
+ # This will load the weights from CPU state_dict and move it to the GPU from meta device
66
+ align_hook.pre_forward(module)
67
+ try:
68
+ yield
69
+ finally:
70
+ if align_hook:
71
+ # Update the weight in the CPU state_dict
72
+ if isinstance(align_hook.weights_map, PrefixedDataset):
73
+ key = align_hook.weights_map.prefix + "weight"
74
+ w_map = align_hook.weights_map.dataset.state_dict
75
+ else:
76
+ key, w_map = "weight", align_hook.weights_map
77
+ w_map[key] = module.weight.data.to(w_map[key].device, dtype=w_map[key].dtype)
78
+ align_hook.post_forward(module, None)
79
+
80
+
81
+ @contextmanager
82
+ def init_quantized_weights(
83
+ quant_cfg: dict[str, Any], gpu_mem_percentage: float = 0.8, quant_gemm: bool = False
84
+ ):
85
+ """Context manager for initializing and loading HuggingFace models with quantized and compressed weights.
86
+
87
+ This context manager patches `from_pretrained` to automatically:
88
+ 1. Initialize the model with an empty config
89
+ 2. Apply quantization configuration
90
+ 3. Compress the weights
91
+ 4. Load and dispatch the model to appropriate devices
92
+
93
+ Args:
94
+ quant_cfg: The quantization config to apply to the model
95
+ gpu_mem_percentage: Percentage of GPU memory to use (0.0-1.0)
96
+ quant_gemm: Whether to enable quantized GEMM
97
+
98
+ Example:
99
+ ```python
100
+ from transformers import AutoModelForCausalLM
101
+ from modelopt.torch.quantization.plugins.huggingface import init_quantized_weights
102
+ import modelopt.torch as mtq
103
+
104
+ # Load quantized and compressed model in one step
105
+ with init_quantized_weights(mtq.NVFP4_DEFAULT_CFG):
106
+ model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-70b-hf")
107
+
108
+
109
+ # The model is already quantized, compressed, and loaded to appropriate devices
110
+
111
+ # calibrate model
112
+ mtq.calibrate(model, "max", forward_loop)
113
+ ```
114
+ """
115
+
116
+ def get_no_split_module_classes(model):
117
+ """Get no-split module classes for device mapping."""
118
+ no_split_classes = set()
119
+
120
+ # Get all named modules
121
+ for name, module in model.named_modules():
122
+ # Look for first layer patterns
123
+ if name.endswith((".layers.0", ".layer.0", ".h.0", ".blocks.0")):
124
+ no_split_classes.add(module.__class__.__name__)
125
+
126
+ return list(no_split_classes)
127
+
128
+ def get_model_device_map(model, gpu_mem_percentage):
129
+ """Create optimized device map for the quantized and compressed model."""
130
+ # Get compression ratio to adjust memory usage
131
+ max_memory = get_max_memory()
132
+ no_split_classes = get_no_split_module_classes(model)
133
+ if len(no_split_classes) == 0:
134
+ warnings.warn(
135
+ "No no-split module classes found for the model. Default device map might be incorrect."
136
+ )
137
+ max_memory = {k: v * gpu_mem_percentage for k, v in max_memory.items()}
138
+
139
+ def _get_special_dtype_map(model):
140
+ special_dtype_map = {}
141
+
142
+ def _get_byte_size(module):
143
+ weight_num_bit = module.weight_quantizer.num_bits
144
+ if isinstance(weight_num_bit, tuple):
145
+ assert len(weight_num_bit) == 2, (
146
+ "Weight num bit must be a tuple of two integers."
147
+ )
148
+ weight_num_bit = weight_num_bit[0] + weight_num_bit[1] + 1
149
+ if weight_num_bit == 8:
150
+ return CustomDtype.FP8
151
+ elif weight_num_bit == 4:
152
+ return CustomDtype.INT4
153
+ else:
154
+ raise ValueError(f"Unsupported weight num bit: {weight_num_bit}")
155
+
156
+ for name, module in model.named_modules():
157
+ if (
158
+ hasattr(module, "weight")
159
+ and hasattr(module, "weight_quantizer")
160
+ and not module.weight_quantizer.fake_quant
161
+ ):
162
+ special_dtype_map[name + ".weight"] = _get_byte_size(module)
163
+ return special_dtype_map
164
+
165
+ special_dtype_map = _get_special_dtype_map(model)
166
+ inferred_device_map = infer_auto_device_map(
167
+ model,
168
+ max_memory=max_memory,
169
+ no_split_module_classes=no_split_classes,
170
+ special_dtypes=special_dtype_map,
171
+ )
172
+ return inferred_device_map
173
+
174
+ # Store original from_pretrained methods that we'll override
175
+ original_auto_causal_lm_from_pretrained = transformers.AutoModelForCausalLM.from_pretrained
176
+
177
+ # Create patched from_pretrained that applies quantization and compression
178
+ def patched_from_pretrained(cls, /, pretrained_model_name_or_path, *args, **kwargs):
179
+ """Patched from_pretrained that handles quantization, compression and device mapping."""
180
+ # Initialize with empty config first to avoid loading weights twice
181
+ config = kwargs.pop("config", None)
182
+ trust_remote_code = kwargs.pop("trust_remote_code", False)
183
+ if config is None:
184
+ # Get config from pretrained model
185
+ from transformers import AutoConfig
186
+
187
+ config = AutoConfig.from_pretrained(
188
+ pretrained_model_name_or_path, trust_remote_code=trust_remote_code
189
+ )
190
+
191
+ with init_empty_weights():
192
+ # Fix torch_dtype to match original model
193
+ torch_dtype = kwargs.get("torch_dtype", getattr(config, "torch_dtype", torch.float16))
194
+ model = cls.from_config(config, torch_dtype=torch_dtype)
195
+
196
+ mtq.quantize(model, quant_cfg)
197
+ mtq.compress(model, config=mtq.CompressConfig(quant_gemm=quant_gemm))
198
+ _device_map = get_model_device_map(model, gpu_mem_percentage)
199
+
200
+ return load_checkpoint_and_dispatch(
201
+ model,
202
+ checkpoint=pretrained_model_name_or_path,
203
+ device_map=_device_map,
204
+ *args,
205
+ **kwargs,
206
+ )
207
+
208
+ try:
209
+ # Apply our patches
210
+ transformers.AutoModelForCausalLM.from_pretrained = classmethod(patched_from_pretrained)
211
+ yield
212
+ finally:
213
+ # Restore original methods
214
+ transformers.AutoModelForCausalLM.from_pretrained = original_auto_causal_lm_from_pretrained
@@ -0,0 +1,52 @@
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 apex linear layers."""
17
+
18
+ from functools import partial
19
+
20
+ import apex.transformer.tensor_parallel.layers as apex_parallel
21
+ from apex.transformer.parallel_state import get_data_parallel_group, get_tensor_model_parallel_group
22
+
23
+ from modelopt.torch.utils.distributed import ParallelState
24
+
25
+ from ..nn import QuantModuleRegistry
26
+ from ..nn.modules.quant_linear import _QuantLinear
27
+ from .custom import _ParallelLinear
28
+
29
+
30
+ class _ApexParallelLinear(_ParallelLinear):
31
+ def _setup(self):
32
+ quantized_linear_fn = partial(
33
+ _QuantLinear.quantized_linear_fn,
34
+ apex_parallel,
35
+ "linear_with_grad_accumulation_and_async_allreduce",
36
+ self,
37
+ )
38
+ self._forward_impl = quantized_linear_fn
39
+ self.parallel_state = ParallelState(
40
+ get_data_parallel_group(), get_tensor_model_parallel_group()
41
+ )
42
+ super()._setup()
43
+
44
+
45
+ @QuantModuleRegistry.register({apex_parallel.ColumnParallelLinear: "apex_ColumnParallelLinear"})
46
+ class _ApexColumnParallelLinear(_ApexParallelLinear):
47
+ _is_column_parallel = True
48
+
49
+
50
+ @QuantModuleRegistry.register({apex_parallel.RowParallelLinear: "apex_RowParallelLinear"})
51
+ class _ApexRowParallelLinear(_ApexParallelLinear):
52
+ _is_row_parallel = True
@@ -0,0 +1,312 @@
1
+ # Inspired by https://github.com/ELS-RD/transformer-deploy/blob/6b88e24ade6ce199e825adc0477b28a07f51f17d/src/transformer_deploy/QDQModels/ast_operator_patch.py
2
+
3
+ # Apache License
4
+ # Copyright 2022, Lefebvre Dalloz Services
5
+
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ # http://www.apache.org/licenses/LICENSE-2.0
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
+ # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17
+ # SPDX-License-Identifier: Apache-2.0
18
+ #
19
+ # Licensed under the Apache License, Version 2.0 (the "License");
20
+ # you may not use this file except in compliance with the License.
21
+ # You may obtain a copy of the License at
22
+ #
23
+ # http://www.apache.org/licenses/LICENSE-2.0
24
+ #
25
+ # Unless required by applicable law or agreed to in writing, software
26
+ # distributed under the License is distributed on an "AS IS" BASIS,
27
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28
+ # See the License for the specific language governing permissions and
29
+ # limitations under the License.
30
+
31
+ """Support quantization for KV Cache in attention layers."""
32
+
33
+ import ast
34
+ import inspect
35
+ import tempfile
36
+ import types
37
+ from warnings import warn
38
+
39
+ from ..conversion import register
40
+ from ..nn import TensorQuantizer
41
+
42
+ __all__ = ["register_attention_for_kv_quant"]
43
+
44
+
45
+ def register_attention_for_kv_quant(attention_cls: type) -> bool:
46
+ """Register attention layer for quantization of KV Cache.
47
+
48
+ Generate a quantized version of the attention class on the fly,
49
+ and register it with the original class for quantization.
50
+ """
51
+ source_code = inspect.getsource(attention_cls)
52
+ model_module = inspect.getmodule(attention_cls)
53
+ head = ast.parse(source_code)
54
+
55
+ bmm_ops = ("matmul", "bmm", "baddbmm")
56
+ sdpa_ops = ("scaled_dot_product_attention",)
57
+
58
+ def is_bmm(node):
59
+ return (
60
+ isinstance(node, ast.Call)
61
+ and isinstance(node.func, ast.Attribute)
62
+ and node.func.attr in bmm_ops
63
+ )
64
+
65
+ def is_sdpa(node):
66
+ return (
67
+ isinstance(node, ast.Call)
68
+ and isinstance(node.func, ast.Attribute)
69
+ and node.func.attr in sdpa_ops
70
+ )
71
+
72
+ def is_bin_matmul(node):
73
+ return isinstance(node, ast.BinOp) and isinstance(node.op, ast.MatMult)
74
+
75
+ def patch(node, quantizer_names, transpose=False):
76
+ for index, quantizer_name in enumerate(quantizer_names):
77
+ if quantizer_name is None:
78
+ continue
79
+ arg = node.args[index]
80
+
81
+ if not transpose:
82
+ node.args[index] = ast.Call(
83
+ func=ast.Attribute(
84
+ value=ast.Name(id="self", ctx=ast.Load()),
85
+ attr=quantizer_name,
86
+ ctx=ast.Load(),
87
+ ),
88
+ args=[arg],
89
+ keywords=[],
90
+ )
91
+ else:
92
+ node.args[index] = ast.Call(
93
+ func=ast.Attribute(
94
+ value=ast.Call(
95
+ func=ast.Attribute(
96
+ value=ast.Name(id="self", ctx=ast.Load()),
97
+ attr=quantizer_name,
98
+ ctx=ast.Load(),
99
+ ),
100
+ args=[
101
+ ast.Call(
102
+ func=ast.Attribute(value=arg, attr="transpose", ctx=ast.Load()),
103
+ args=[ast.Constant(value=-1), ast.Constant(value=-2)],
104
+ keywords=[],
105
+ )
106
+ ],
107
+ keywords=[],
108
+ ),
109
+ attr="transpose",
110
+ ctx=ast.Load(),
111
+ ),
112
+ args=[ast.Constant(value=-1), ast.Constant(value=-2)],
113
+ keywords=[],
114
+ )
115
+
116
+ def patch_binop(node, quantizer_names, transpose=False):
117
+ assert len(quantizer_names) == 2
118
+ if quantizer_names[0] is not None:
119
+ node.left = ast.Call(
120
+ func=ast.Attribute(
121
+ value=ast.Name(id="self", ctx=ast.Load()),
122
+ attr=quantizer_names[0],
123
+ ctx=ast.Load(),
124
+ ),
125
+ args=[node.left],
126
+ keywords=[],
127
+ )
128
+ if quantizer_names[1] is not None:
129
+ arg = node.right
130
+ if transpose:
131
+ arg = ast.Call(
132
+ func=ast.Attribute(
133
+ ast.Name(id="torch", ctx=ast.Load()),
134
+ attr="transpose",
135
+ ctx=ast.Load(),
136
+ ),
137
+ args=[arg, ast.Constant(value=-1), ast.Constant(value=-2)],
138
+ keywords=[],
139
+ )
140
+ quant_arg = ast.Call(
141
+ func=ast.Attribute(
142
+ value=ast.Name(id="self", ctx=ast.Load()),
143
+ attr=quantizer_names[1],
144
+ ctx=ast.Load(),
145
+ ),
146
+ args=[arg],
147
+ keywords=[],
148
+ )
149
+ if transpose:
150
+ quant_arg = ast.Call(
151
+ func=ast.Attribute(
152
+ ast.Name(id="torch", ctx=ast.Load()),
153
+ attr="transpose",
154
+ ctx=ast.Load(),
155
+ ),
156
+ args=[quant_arg, ast.Constant(value=-1), ast.Constant(value=-2)],
157
+ keywords=[],
158
+ )
159
+ node.right = quant_arg
160
+
161
+ nodes = list(ast.walk(head))
162
+ org_class_name = nodes[1].name # type: ignore[attr-defined]
163
+ new_class_name = nodes[1].name = "_Quant" + nodes[1].name # type: ignore[attr-defined]
164
+
165
+ bmm_nodes = []
166
+ sdpa_nodes = []
167
+ bin_matmul_nodes = []
168
+ for node in ast.walk(head):
169
+ if is_bmm(node):
170
+ bmm_nodes.append(node)
171
+ if is_sdpa(node):
172
+ sdpa_nodes.append(node)
173
+ if is_bin_matmul(node):
174
+ bin_matmul_nodes.append(node)
175
+ if len(bmm_nodes) != 2 and len(sdpa_nodes) != 1 and len(bin_matmul_nodes) != 2:
176
+ print(f"Expect 2 bmm/matmul op in the {org_class_name}, found {len(bmm_nodes)}")
177
+ print(f"Or expect 1 sdpa op in the {org_class_name}, found {len(sdpa_nodes)}")
178
+ print(f"Or expect 2 @ op in the {org_class_name}, found {len(bin_matmul_nodes)}")
179
+ print("Auto quantization of KV Cache fails")
180
+ return False
181
+
182
+ if len(bmm_nodes) == 2:
183
+ # transpose k cache here to enable per-token quantization
184
+ # without transpose, the quantization will be per-channel, i.e.,
185
+ # self.k_bmm_quantizer(key_states.transpose(-1, -2))
186
+ # after transpose, the quantization will be per-token, i.e.,
187
+ # self.k_bmm_quantizer(key_states.transpose(-1, -2).transpose(-1, -2)).transpose(-1, -2)
188
+ # removing the additional transpose is doable but not trivial
189
+ patch(bmm_nodes[0], quantizer_names=(None, "v_bmm_quantizer"))
190
+ patch(bmm_nodes[1], quantizer_names=("q_bmm_quantizer", "k_bmm_quantizer"), transpose=True)
191
+ print("Patching 2 BMM/Matmul operators with quantizers")
192
+ if len(bin_matmul_nodes) == 2:
193
+ patch_binop(
194
+ bin_matmul_nodes[1],
195
+ quantizer_names=("q_bmm_quantizer", "k_bmm_quantizer"),
196
+ transpose=True,
197
+ )
198
+ patch_binop(bin_matmul_nodes[0], quantizer_names=(None, "v_bmm_quantizer"))
199
+ print("Patching 2 @ operators with quantizers")
200
+
201
+ if len(sdpa_nodes) == 1:
202
+ patch(
203
+ sdpa_nodes[0], quantizer_names=("q_bmm_quantizer", "k_bmm_quantizer", "v_bmm_quantizer")
204
+ )
205
+ print("Patching 1 scaled_dot_product_attention operator with quantizers")
206
+
207
+ head = ast.fix_missing_locations(head)
208
+ org_class = model_module.__dict__[org_class_name]
209
+
210
+ quant_class = _create_quantized_class_from_ast(head, org_class, new_class_name, model_module)
211
+ register(original_cls=org_class, quantized_cls=quant_class)
212
+ print(f"Successfully registered {org_class_name} for quantization")
213
+ return True
214
+
215
+
216
+ def _create_quantized_class_from_ast(
217
+ head, org_class, new_class_name, model_module, temp_file_name=None
218
+ ):
219
+ """Create a quantized class from an AST representation.
220
+
221
+ Args:
222
+ head: The AST head containing the modified class definition
223
+ org_class: The original class to be quantized
224
+ new_class_name: Name for the new quantized class
225
+ model_module: The module containing the original class
226
+ temp_file_name: Optional file name to save the generated code
227
+
228
+ Returns:
229
+ The newly created quantized class
230
+ """
231
+ head = ast.fix_missing_locations(head)
232
+
233
+ # Save the generated code to a temporary file if requested
234
+ module_code_str = ast.unparse(head)
235
+ if temp_file_name is None:
236
+ with tempfile.NamedTemporaryFile(
237
+ prefix="modelopt_", suffix=".py", delete=False
238
+ ) as temp_file:
239
+ temp_file.write(module_code_str.encode())
240
+ temp_file_name = temp_file.name
241
+ print(f"Definition of {new_class_name} saved to {temp_file_name}")
242
+ else:
243
+ with open(temp_file_name, "w") as f:
244
+ f.write(module_code_str)
245
+
246
+ # Exec with python runtime and extract the new class
247
+ # This could lead to side effects if the class code is not properly isolated
248
+ # Therefore, it is recommended to run this function only when necessary
249
+ # exec(
250
+ # new_class_code,
251
+ # globals=model_module.__dict__,
252
+ # locals=model_module.__dict__
253
+ # ) # bandit throws error here
254
+ # quant_class = model_module.__dict__[new_class_name]
255
+
256
+ # Extract the bytecode and create a new class on the fly
257
+ # This is more tricky but doesn't require runtime execution
258
+ module_code = compile(head, filename=f"{temp_file_name}", mode="exec")
259
+ class_code = module_code.co_consts[0]
260
+ assert class_code.co_name == new_class_name
261
+ method_codes = [const for const in class_code.co_consts if isinstance(const, types.CodeType)]
262
+
263
+ new_methods = {}
264
+ for method_code in method_codes:
265
+ method_name = method_code.co_name
266
+ original_method = getattr(org_class, method_name, None)
267
+ if not isinstance(original_method, types.FunctionType):
268
+ continue
269
+
270
+ # Check if the method is a decorated method
271
+ # The exec path can handle decorated methods, but the safety compliance disallows exec
272
+ closure = original_method.__closure__
273
+ globals = original_method.__globals__
274
+ if method_code.co_freevars != original_method.__code__.co_freevars:
275
+ warn(f"{new_class_name}.{method_name} is a decorated method. Ignoring the decorator!")
276
+
277
+ new_closure = ()
278
+ for freevar in method_code.co_freevars:
279
+ assert freevar in original_method.__closure__
280
+ new_closure += (
281
+ original_method.__closure__[ # type: ignore[index]
282
+ original_method.__code__.co_freevars.index(freevar)
283
+ ],
284
+ )
285
+ closure = new_closure
286
+ for closure_item in original_method.__closure__: # type: ignore[union-attr]
287
+ item = closure_item.cell_contents
288
+ if isinstance(item, types.FunctionType) and item.__name__ == method_name:
289
+ globals = item.__globals__
290
+ break
291
+ else:
292
+ raise ValueError(f"Cannot find the original method {method_name} in the closure")
293
+
294
+ # Create a new class method from bytecode
295
+ new_method = types.FunctionType(method_code, globals=globals, closure=closure)
296
+ new_method.__annotations__ = original_method.__annotations__
297
+ new_method.__defaults__ = original_method.__defaults__
298
+ new_method.__kwdefaults__ = original_method.__kwdefaults__
299
+ new_methods[method_name] = new_method
300
+
301
+ def setup_method(self):
302
+ self.q_bmm_quantizer = TensorQuantizer()
303
+ self.k_bmm_quantizer = TensorQuantizer()
304
+ self.v_bmm_quantizer = TensorQuantizer()
305
+
306
+ assert "_setup" not in new_methods, "Method _setup already exists"
307
+ new_methods["_setup"] = setup_method
308
+
309
+ # Create a new subclass on the fly
310
+ quant_class = type(new_class_name, (org_class,), new_methods)
311
+
312
+ return quant_class