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,99 @@
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 Pooling modules."""
17
+
18
+ from torch.nn.modules import pooling
19
+
20
+ from .quant_module import QuantInputBase, QuantModuleRegistry, _LegacyQuantInputBaseMixin
21
+
22
+ __all__ = [
23
+ "AdaptiveAvgPool1d",
24
+ "AdaptiveAvgPool2d",
25
+ "AdaptiveAvgPool3d",
26
+ "AvgPool1d",
27
+ "AvgPool2d",
28
+ "AvgPool3d",
29
+ "MaxPool1d",
30
+ "MaxPool2d",
31
+ "MaxPool3d",
32
+ "QuantAdaptiveAvgPool1d",
33
+ "QuantAdaptiveAvgPool2d",
34
+ "QuantAdaptiveAvgPool3d",
35
+ "QuantAvgPool1d",
36
+ "QuantAvgPool2d",
37
+ "QuantAvgPool3d",
38
+ "QuantMaxPool1d",
39
+ "QuantMaxPool2d",
40
+ "QuantMaxPool3d",
41
+ ]
42
+
43
+
44
+ class QuantMaxPool1d(_LegacyQuantInputBaseMixin, pooling.MaxPool1d):
45
+ """Quantized version of nn.MaxPool1d."""
46
+
47
+
48
+ class QuantMaxPool2d(_LegacyQuantInputBaseMixin, pooling.MaxPool2d):
49
+ """Quantized version of nn.MaxPool2d."""
50
+
51
+
52
+ class QuantMaxPool3d(_LegacyQuantInputBaseMixin, pooling.MaxPool3d):
53
+ """Quantized version of nn.MaxPool3d."""
54
+
55
+
56
+ class QuantAvgPool1d(_LegacyQuantInputBaseMixin, pooling.AvgPool1d):
57
+ """Quantized version of nn.AvgPool1d."""
58
+
59
+
60
+ class QuantAvgPool2d(_LegacyQuantInputBaseMixin, pooling.AvgPool2d):
61
+ """Quantized version of nn.AvgPool2d."""
62
+
63
+
64
+ class QuantAvgPool3d(_LegacyQuantInputBaseMixin, pooling.AvgPool3d):
65
+ """Quantized version of nn.AvgPool3d."""
66
+
67
+
68
+ class QuantAdaptiveAvgPool1d(_LegacyQuantInputBaseMixin, pooling.AdaptiveAvgPool1d):
69
+ """Quantized version of nn.AdaptiveAvgPool1d."""
70
+
71
+
72
+ class QuantAdaptiveAvgPool2d(_LegacyQuantInputBaseMixin, pooling.AdaptiveAvgPool2d):
73
+ """Quantized version of nn.AdaptiveAvgPool2d."""
74
+
75
+
76
+ class QuantAdaptiveAvgPool3d(_LegacyQuantInputBaseMixin, pooling.AdaptiveAvgPool3d):
77
+ """Quantized version of nn.AdaptiveAvgPool3d."""
78
+
79
+
80
+ # Define alias with Quant prefix
81
+ MaxPool1d = QuantMaxPool1d
82
+ MaxPool2d = QuantMaxPool2d
83
+ MaxPool3d = QuantMaxPool3d
84
+ AvgPool1d = QuantAvgPool1d
85
+ AvgPool2d = QuantAvgPool2d
86
+ AvgPool3d = QuantAvgPool3d
87
+ AdaptiveAvgPool1d = QuantAdaptiveAvgPool1d
88
+ AdaptiveAvgPool2d = QuantAdaptiveAvgPool2d
89
+ AdaptiveAvgPool3d = QuantAdaptiveAvgPool3d
90
+
91
+ QuantModuleRegistry.register({pooling.MaxPool1d: "nn.MaxPool1d"})(QuantInputBase)
92
+ QuantModuleRegistry.register({pooling.MaxPool2d: "nn.MaxPool2d"})(QuantInputBase)
93
+ QuantModuleRegistry.register({pooling.MaxPool3d: "nn.MaxPool3d"})(QuantInputBase)
94
+ QuantModuleRegistry.register({pooling.AvgPool1d: "nn.AvgPool1d"})(QuantInputBase)
95
+ QuantModuleRegistry.register({pooling.AvgPool2d: "nn.AvgPool2d"})(QuantInputBase)
96
+ QuantModuleRegistry.register({pooling.AvgPool3d: "nn.AvgPool3d"})(QuantInputBase)
97
+ QuantModuleRegistry.register({pooling.AdaptiveAvgPool1d: "nn.AdaptiveAvgPool1d"})(QuantInputBase)
98
+ QuantModuleRegistry.register({pooling.AdaptiveAvgPool2d: "nn.AdaptiveAvgPool2d"})(QuantInputBase)
99
+ QuantModuleRegistry.register({pooling.AdaptiveAvgPool3d: "nn.AdaptiveAvgPool3d"})(QuantInputBase)
@@ -0,0 +1,527 @@
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 RNN."""
17
+
18
+ import contextlib
19
+ from collections.abc import Callable, Iterator
20
+ from types import ModuleType
21
+ from typing import Any
22
+
23
+ import torch
24
+ import torch._VF as _VF
25
+ import torch.nn as nn
26
+ import torch.nn.functional as F
27
+
28
+ from ...tensor_quant import QUANT_DESC_8BIT_PER_TENSOR
29
+ from ...utils import is_torch_export_mode, multi_context, replace_function
30
+ from .quant_module import QuantModule, QuantModuleRegistry
31
+ from .tensor_quantizer import SequentialQuantizer, TensorQuantizer
32
+
33
+ _cell_call_map = {
34
+ "RNN_TANH": _VF.rnn_tanh_cell,
35
+ "RNN_RELU": _VF.rnn_relu_cell,
36
+ "LSTM": _VF.lstm_cell,
37
+ "GRU": _VF.gru_cell,
38
+ }
39
+ _layer_call_name_map = {
40
+ "RNN_TANH": "rnn_tanh",
41
+ "RNN_RELU": "rnn_relu",
42
+ "LSTM": "lstm",
43
+ "GRU": "gru",
44
+ }
45
+
46
+
47
+ class QuantRNNBase(QuantModule):
48
+ """Base class for quantized RNN modules."""
49
+
50
+ weight_quantizer: TensorQuantizer | SequentialQuantizer
51
+ _enable_weight_quantization: bool
52
+ default_quant_desc_weight = QUANT_DESC_8BIT_PER_TENSOR
53
+ default_quant_desc_input = QUANT_DESC_8BIT_PER_TENSOR
54
+ _functionals_to_replace: list[tuple[ModuleType, str, Callable]] = []
55
+
56
+ @property
57
+ def functionals_to_replace(self) -> Iterator[tuple[ModuleType, str, Callable]]:
58
+ """Replace functions of packages on the fly."""
59
+ return (
60
+ (package, func_name, quantized_func)
61
+ for package, func_name, quantized_func in self._functionals_to_replace
62
+ if hasattr(package, func_name)
63
+ )
64
+
65
+ @property
66
+ def all_input_quantizers_disabled(self):
67
+ """Check if all input quantizer are disabled."""
68
+ return all(not iq.is_enabled for iq in self._input_quantizers + self._proj_input_quantizers)
69
+
70
+ @contextlib.contextmanager
71
+ def quantize_weight(self):
72
+ """Context in which ``self.weight`` is quantized."""
73
+ self._enable_weight_quantization = True
74
+ yield
75
+ self._enable_weight_quantization = False
76
+
77
+ @staticmethod
78
+ def _get_quantized_weight_handler(weight_quantizer_name: str):
79
+ def _get_quantized_weight(module: "QuantRNNBase", weight: torch.Tensor):
80
+ if module._enable_weight_quantization:
81
+ weight_quantizer = getattr(module, weight_quantizer_name)
82
+ return weight_quantizer(weight)
83
+ return weight
84
+
85
+ return _get_quantized_weight
86
+
87
+ def forward(self, input, *args, **kwargs):
88
+ """Quantize the input and the weight before calling the original forward method."""
89
+ contexts = (
90
+ replace_function(package, func_name, quantized_func)
91
+ for package, func_name, quantized_func in self.functionals_to_replace
92
+ )
93
+ if is_torch_export_mode():
94
+ return super().forward(input, *args, **kwargs)
95
+ with multi_context(
96
+ self.quantize_weight(),
97
+ *contexts,
98
+ ):
99
+ return super().forward(input, *args, **kwargs)
100
+
101
+ def _setup(self):
102
+ for name, _ in self.named_parameters():
103
+ if name.startswith("weight"):
104
+ # to be compatible with our current config, the name is some what weird
105
+ # it would be weight_xxx_weight_quantizer
106
+ weight_quantizer_name = name + "_weight_quantizer"
107
+ self._register_temp_attribute(
108
+ weight_quantizer_name, TensorQuantizer(self.default_quant_desc_weight)
109
+ )
110
+ self._register_dynamic_attribute(
111
+ name, self._get_quantized_weight_handler(weight_quantizer_name)
112
+ )
113
+ # for cells
114
+ self._register_temp_attribute("_input_quantizers", [])
115
+ num_directions = 2 if self.bidirectional else 1
116
+ # for projection layer if exists
117
+ self._register_temp_attribute("_proj_input_quantizers", [])
118
+
119
+ # the input quantizer is per cell (or per layer) based
120
+ for layer in range(self.num_layers * num_directions):
121
+ for direction in range(num_directions):
122
+ suffix = "_reverse" if direction == 1 else ""
123
+ name = f"layer_{layer}{suffix}_input_quantizer"
124
+ quantizer = TensorQuantizer(self.default_quant_desc_input)
125
+ self._register_temp_attribute(name, quantizer)
126
+ self._input_quantizers.append(quantizer)
127
+ if self.proj_size > 0:
128
+ name = f"proj_{layer}{suffix}_input_quantizer"
129
+ quantizer = TensorQuantizer(self.default_quant_desc_input)
130
+ self._register_temp_attribute(name, quantizer)
131
+ self._proj_input_quantizers.append(quantizer)
132
+ self._register_temp_attribute("_enable_weight_quantization", False)
133
+
134
+
135
+ class QuantRNNFullBase(QuantRNNBase):
136
+ """Quantized RNN with input quantizer."""
137
+
138
+ def _disable_input_quantizers(self):
139
+ for iq in self._input_quantizers + self._proj_input_quantizers:
140
+ iq.disable()
141
+
142
+ def _enable_input_quantizers(self):
143
+ for iq in self._input_quantizers + self._proj_input_quantizers:
144
+ iq.enable()
145
+
146
+ def _disable_weight_quantizers(self):
147
+ for name, module in self.named_modules():
148
+ if name.endswith("weight_quantizer"):
149
+ module.disable()
150
+
151
+ def _enable_weight_quantizer(self):
152
+ for name, module in self.named_modules():
153
+ if name.endswith("weight_quantizer"):
154
+ module.enable()
155
+
156
+ def _setup(self):
157
+ super()._setup()
158
+ vf_rnn = VFRNNForward(
159
+ self.mode,
160
+ self.bidirectional,
161
+ self.num_layers,
162
+ self.proj_size > 0,
163
+ self.bias,
164
+ self._input_quantizers,
165
+ self._proj_input_quantizers if self.proj_size > 0 else None,
166
+ self.batch_first,
167
+ )
168
+ self._functionals_to_replace = [(_VF, _layer_call_name_map[self.mode], vf_rnn)]
169
+
170
+
171
+ class VFRNNForward:
172
+ """Reimplement the _VF rnn calls with python to enable input quantizers.
173
+
174
+ It's less efficient compared to original calls.
175
+ """
176
+
177
+ def __init__(
178
+ self,
179
+ mode: str,
180
+ bidirectional: bool,
181
+ num_layers: int,
182
+ has_proj: bool,
183
+ has_bias: bool,
184
+ input_quantizers: list[TensorQuantizer],
185
+ proj_input_quantizers: list[TensorQuantizer] | None = None,
186
+ batch_first: bool | None = False,
187
+ ):
188
+ """Pre-construct necessary parameters for vf calls to reduce overhead.
189
+
190
+ Refer to torch RNN modules for parameter information.
191
+ """
192
+ cell = _cell_call_map[mode]
193
+ if has_proj:
194
+ cell = lstm_cell_with_proj
195
+ self.layer_forwards_const = (RNNLayerForward(cell, variable_len=False),)
196
+ self.layer_forwards_variable = (RNNLayerForward(cell, variable_len=True),)
197
+ if bidirectional:
198
+ self.layer_forwards_const += (RNNLayerForward(cell, reverse=True, variable_len=False),)
199
+ self.layer_forwards_variable += (
200
+ RNNLayerForward(cell, reverse=True, variable_len=True),
201
+ )
202
+ self.num_directions = 2 if bidirectional else 1
203
+ self.total_layers = num_layers * self.num_directions
204
+ self.num_layers = num_layers
205
+ self.is_lstm = mode == "LSTM"
206
+ self.has_proj = has_proj
207
+
208
+ self.num_weights_per_layer = self.num_cell_weights_per_layer = 4 if has_bias else 2
209
+ if has_proj:
210
+ self.num_weights_per_layer += 1
211
+
212
+ self.input_quantizers = input_quantizers
213
+
214
+ self.proj_input_quantizers = proj_input_quantizers
215
+ self.batch_first = batch_first
216
+
217
+ def forward(
218
+ self,
219
+ layer_forwards: tuple[Callable],
220
+ input: torch.Tensor,
221
+ flat_weights: list[torch.Tensor],
222
+ hidden: torch.Tensor | tuple[torch.Tensor],
223
+ dropout: float | None = 0,
224
+ training: bool | None = True,
225
+ batch_sizes: torch.Tensor | None = None,
226
+ ):
227
+ """This this the core implementation of vf rnn calls."""
228
+ all_hiddens = []
229
+
230
+ if self.is_lstm:
231
+ hidden = list(zip(*hidden))
232
+ if self.batch_first and batch_sizes is None:
233
+ input = input.transpose(0, 1)
234
+
235
+ for i in range(self.num_layers):
236
+ all_output = []
237
+ for j, layer_forward in enumerate(layer_forwards):
238
+ l_i = i * self.num_directions + j
239
+ # the flat_weights is a list of tensors, we need extract weights of each layer
240
+ w_start = l_i * self.num_weights_per_layer
241
+ w_end = w_start + self.num_weights_per_layer
242
+ proj_input_quantizer = (
243
+ self.proj_input_quantizers[l_i] if self.proj_input_quantizers else None
244
+ )
245
+
246
+ hx, output = layer_forward(
247
+ input,
248
+ hidden[l_i],
249
+ flat_weights[w_start:w_end],
250
+ self.input_quantizers[l_i],
251
+ batch_sizes,
252
+ proj_input_quantizer=proj_input_quantizer,
253
+ )
254
+
255
+ all_hiddens.append(hx)
256
+ all_output.append(output)
257
+
258
+ input = torch.cat(all_output, -1)
259
+
260
+ if dropout != 0 and i < self.num_layers - 1:
261
+ input = F.dropout(input, p=dropout, training=training, inplace=False)
262
+
263
+ if self.batch_first and batch_sizes is None:
264
+ input = input.transpose(0, 1)
265
+
266
+ if self.is_lstm:
267
+ hn, cn = zip(*all_hiddens)
268
+ all_hiddens = (torch.stack(hn, 0), torch.stack(cn, 0))
269
+ output_tuple = (input, *all_hiddens)
270
+ else:
271
+ all_hiddens = torch.stack(all_hiddens, 0)
272
+ output_tuple = (input, all_hiddens)
273
+
274
+ return output_tuple
275
+
276
+ def __call__(self, *args) -> tuple[torch.Tensor, torch.Tensor]:
277
+ """Entry of vf calls.
278
+
279
+ Original vf funcs are overloaded cpp funcs. Each has two different signatures,
280
+ one accepts inputs with variable length (packed sequence), the other accepts constant length.
281
+ The difference is that the fourth arg is a bool for constant length.
282
+ """
283
+ if isinstance(args[3], bool):
284
+ # constant
285
+ (
286
+ input,
287
+ hidden,
288
+ flat_weights,
289
+ bias,
290
+ num_layers,
291
+ dropout,
292
+ training,
293
+ bidirectional,
294
+ batch_first,
295
+ ) = args
296
+ batch_sizes = None
297
+ layer_forwards = self.layer_forwards_const
298
+ else:
299
+ # variable
300
+ (
301
+ input,
302
+ batch_sizes,
303
+ hidden,
304
+ flat_weights,
305
+ bias,
306
+ num_layers,
307
+ dropout,
308
+ training,
309
+ bidirectional,
310
+ ) = args
311
+ layer_forwards = self.layer_forwards_variable
312
+
313
+ return self.forward(
314
+ layer_forwards,
315
+ input,
316
+ flat_weights,
317
+ hidden,
318
+ dropout,
319
+ training,
320
+ batch_sizes,
321
+ )
322
+
323
+
324
+ class RNNLayerForward:
325
+ """A single layer of rnn modules."""
326
+
327
+ def __init__(self, cell, reverse=False, variable_len=False):
328
+ """Init the layer forward for different cells, directions, and inputs."""
329
+ self.cell = cell
330
+ self.reverse = reverse
331
+ self.variable_len = variable_len
332
+ if variable_len:
333
+ if reverse:
334
+ self.forward = get_quantized_rnn_layer_variable_len_reverse_forward(cell)
335
+ else:
336
+ self.forward = get_quantized_rnn_layer_variable_len_forward(cell)
337
+ else:
338
+ self.forward = get_quantized_rnn_layer_forward(cell, reverse=reverse)
339
+
340
+ def __call__(
341
+ self, input, hidden, weights, input_quantizer, batch_sizes=None, proj_input_quantizer=None
342
+ ) -> Any:
343
+ """Layer forward."""
344
+ return self.forward(
345
+ input,
346
+ hidden,
347
+ weights,
348
+ input_quantizer,
349
+ batch_sizes=batch_sizes,
350
+ proj_input_quantizer=proj_input_quantizer,
351
+ )
352
+
353
+
354
+ def lstm_cell_with_proj(input, hidden, *weights, proj_input_quantizer=None):
355
+ """Currently the _VF.lstm_cell doesn't accept projected inputs. i.e. h_n and c_n must be same shape.
356
+
357
+ This implementation is not optimized for cuda compared to _VF.lstm_cell, so we only use it when projection exists.
358
+ """
359
+ if len(weights) == 3:
360
+ weight_ih, weight_hh, weight_hr = weights
361
+ bias_ih = bias_hh = None
362
+ else:
363
+ weight_ih, weight_hh, bias_ih, bias_hh, weight_hr = weights
364
+ hn, cn = hidden
365
+
366
+ gates = F.linear(input, weight_ih, bias_ih) + F.linear(hn, weight_hh, bias_hh)
367
+
368
+ ingate, forgetgate, cellgate, outgate = gates.chunk(4, 1)
369
+
370
+ ingate = torch.sigmoid(ingate)
371
+ forgetgate = torch.sigmoid(forgetgate)
372
+ cellgate = torch.tanh(cellgate)
373
+ outgate = torch.sigmoid(outgate)
374
+
375
+ cy = (forgetgate * cn) + (ingate * cellgate)
376
+ hy = outgate * torch.tanh(cy)
377
+ if proj_input_quantizer is not None:
378
+ hy = proj_input_quantizer(hy)
379
+ hy = F.linear(hy, weight_hr)
380
+ return hy, cy
381
+
382
+
383
+ def quantized_cell_forward(
384
+ cell, input, hidden, weights, input_quantizer, proj_input_quantizer=None
385
+ ):
386
+ """Call input quantizer before calling cell."""
387
+ quant_input = input_quantizer(input)
388
+ quant_hidden = (
389
+ (input_quantizer(hidden[0]), input_quantizer(hidden[1]))
390
+ if isinstance(hidden, tuple)
391
+ else input_quantizer(hidden)
392
+ )
393
+ kwargs = {} if proj_input_quantizer is None else {"proj_input_quantizer": proj_input_quantizer}
394
+ hidden = cell(quant_input, quant_hidden, *weights, **kwargs)
395
+ return hidden
396
+
397
+
398
+ def get_quantized_rnn_layer_forward(cell, reverse=False):
399
+ """Construct the forward call for different rnn cells.
400
+
401
+ Note that batch_sizes is here for keeping a consistent signature with the forward of variable length.
402
+ """
403
+
404
+ def forward(
405
+ input, hidden, weights, input_quantizer, batch_sizes=None, proj_input_quantizer=None
406
+ ):
407
+ seq_len = input.shape[0]
408
+ steps = reversed(range(seq_len)) if reverse else range(seq_len)
409
+
410
+ output = []
411
+ for i in steps:
412
+ hidden = quantized_cell_forward(
413
+ cell,
414
+ input[i],
415
+ hidden,
416
+ weights,
417
+ input_quantizer,
418
+ proj_input_quantizer=proj_input_quantizer,
419
+ )
420
+ output.append(hidden[0] if isinstance(hidden, tuple) else hidden)
421
+
422
+ if reverse:
423
+ output.reverse()
424
+ output = torch.stack(output, 0)
425
+
426
+ return hidden, output
427
+
428
+ return forward
429
+
430
+
431
+ def get_quantized_rnn_layer_variable_len_forward(cell):
432
+ """Construct the forward call for packed sequence."""
433
+
434
+ def forward(input, hidden, weights, input_quantizer, batch_sizes, proj_input_quantizer=None):
435
+ output = []
436
+ input_offset = 0
437
+ last_batch_size = batch_sizes[0]
438
+ hiddens = []
439
+ flat_hidden = not isinstance(hidden, tuple)
440
+ if flat_hidden:
441
+ hidden = (hidden,)
442
+ for batch_size in batch_sizes:
443
+ step_input = input[input_offset : input_offset + batch_size]
444
+ input_offset += batch_size
445
+
446
+ dec = last_batch_size - batch_size
447
+ if dec > 0:
448
+ hiddens.append(tuple(h[-dec:] for h in hidden))
449
+ hidden = tuple(h[:-dec] for h in hidden)
450
+ last_batch_size = batch_size
451
+ hx = hidden[0] if flat_hidden else hidden
452
+ hidden = quantized_cell_forward(
453
+ cell,
454
+ step_input,
455
+ hx,
456
+ weights,
457
+ input_quantizer,
458
+ proj_input_quantizer=proj_input_quantizer,
459
+ )
460
+ if flat_hidden:
461
+ hidden = (hidden,)
462
+
463
+ output.append(hidden[0])
464
+ hiddens.append(hidden)
465
+ hiddens.reverse()
466
+
467
+ hidden = tuple(torch.cat(h, 0) for h in zip(*hiddens))
468
+ assert hidden[0].shape[0] == batch_sizes[0]
469
+ if flat_hidden:
470
+ hidden = hidden[0]
471
+ output = torch.cat(output, 0)
472
+
473
+ return hidden, output
474
+
475
+ return forward
476
+
477
+
478
+ def get_quantized_rnn_layer_variable_len_reverse_forward(cell):
479
+ """Construct the forward call for packed sequence in the reversed direction."""
480
+
481
+ def forward(input, hidden, weights, input_quantizer, batch_sizes, proj_input_quantizer=None):
482
+ output = []
483
+ input_offset = input.shape[0]
484
+ last_batch_size = batch_sizes[-1]
485
+ initial_hidden = hidden
486
+ flat_hidden = not isinstance(hidden, tuple)
487
+ if flat_hidden:
488
+ hidden = (hidden,)
489
+ initial_hidden = (initial_hidden,)
490
+ hidden = tuple(h[: batch_sizes[-1]] for h in hidden)
491
+ for i in reversed(range(len(batch_sizes))):
492
+ batch_size = batch_sizes[i]
493
+ inc = batch_size - last_batch_size
494
+ if inc > 0:
495
+ hidden = tuple(
496
+ torch.cat((h, ih[last_batch_size:batch_size]), 0)
497
+ for h, ih in zip(hidden, initial_hidden)
498
+ )
499
+ last_batch_size = batch_size
500
+ step_input = input[input_offset - batch_size : input_offset]
501
+ input_offset -= batch_size
502
+
503
+ hx = hidden[0] if flat_hidden else hidden
504
+ hidden = quantized_cell_forward(
505
+ cell,
506
+ step_input,
507
+ hx,
508
+ weights,
509
+ input_quantizer,
510
+ proj_input_quantizer=proj_input_quantizer,
511
+ )
512
+ if flat_hidden:
513
+ hidden = (hidden,)
514
+ output.append(hidden[0])
515
+
516
+ output.reverse()
517
+ output = torch.cat(output, 0)
518
+ if flat_hidden:
519
+ hidden = hidden[0]
520
+ return hidden, output
521
+
522
+ return forward
523
+
524
+
525
+ QuantModuleRegistry.register({nn.RNN: "nn.RNN"})(QuantRNNFullBase)
526
+ QuantModuleRegistry.register({nn.LSTM: "nn.LSTM"})(QuantRNNFullBase)
527
+ QuantModuleRegistry.register({nn.GRU: "nn.GRU"})(QuantRNNFullBase)