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,199 @@
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
+ """Implements NF4 quantization for efficient tensor storage and computation."""
17
+
18
+ import numpy as np
19
+ import torch
20
+
21
+ from ..extensions import get_cuda_ext
22
+ from ..qtensor.base_qtensor import BaseQuantizedTensor
23
+ from ..utils import reduce_amax, reduce_block_padding
24
+
25
+ nf4_table = torch.tensor(
26
+ [
27
+ -1.0000,
28
+ -0.6962,
29
+ -0.5251,
30
+ -0.3949,
31
+ -0.2844,
32
+ -0.1848,
33
+ -0.0911,
34
+ 0.0000,
35
+ 0.0796,
36
+ 0.1609,
37
+ 0.2461,
38
+ 0.3379,
39
+ 0.4407,
40
+ 0.5626,
41
+ 0.7230,
42
+ 1.0000,
43
+ ],
44
+ dtype=torch.bfloat16,
45
+ )
46
+
47
+ __all__ = ["NF4QTensor"]
48
+
49
+
50
+ def _dequantize_scalers(scales, double_scale, scale_zeros, dtype):
51
+ return (scales / double_scale.unsqueeze(-1)).to(dtype) + scale_zeros
52
+
53
+
54
+ def _quantize_to_nearest_lut(flatten_tensor: torch.Tensor, lut: torch.Tensor) -> torch.Tensor:
55
+ """Quantize a float16 tensor to nearest value and return the indices of the look-up table."""
56
+ assert flatten_tensor.dim() == 1, (
57
+ f"Expect flatten tensor but got input with {flatten_tensor.dim()} dimensions."
58
+ )
59
+ diff = (flatten_tensor[:, None] - lut).abs() # Shape: (numel, 16)
60
+ indices = diff.argmin(dim=-1)
61
+ return indices
62
+
63
+
64
+ def _nf4_lookup(quantized_idx: torch.Tensor) -> torch.Tensor:
65
+ """Dequantize uint4 index to nf4 value."""
66
+ return nf4_table.to(quantized_idx.device)[quantized_idx]
67
+
68
+
69
+ class NF4QTensor(BaseQuantizedTensor):
70
+ """Implements the NF4 quantization on tensors for more efficient storage or computation.
71
+
72
+ Attributes:
73
+ quantized_data (torch.Tensor): The quantized data stored as a packed uint8 tensor.
74
+ """
75
+
76
+ @classmethod
77
+ def quantize(
78
+ cls, input: torch.Tensor, block_size: int, scale_block_size: int | None = None
79
+ ) -> tuple:
80
+ """Converting a tensor to a quantized format based on NF4 double quantization.
81
+
82
+ Args:
83
+ input (torch.Tensor): The input tensor to be quantized.
84
+ block_size (int): The size of each block for quantization.
85
+ scale_block_size (int): The block size for scaling during quantization.
86
+
87
+ Returns:
88
+ tuple: Contains quantized data, input quantization config, and scale quantization config.
89
+ """
90
+ cuda_ext = get_cuda_ext()
91
+
92
+ # pad the input if needed
93
+ original_input = input
94
+ input = reduce_block_padding(input.view(-1), block_sizes={-1: block_size})
95
+
96
+ # get scales for each block
97
+ block_input = input.view(-1, block_size)
98
+ scales = reduce_amax(block_input, -1)
99
+
100
+ if cuda_ext and input.is_cuda:
101
+ packed_output_uint8 = cuda_ext.NF4_quantize(input, scales, block_size)
102
+ else:
103
+ # expand scalers to match shape of input
104
+ scales = scales.view(block_input.shape[0], -1) # shape: (block_input.shape[0], 1)
105
+ scaled_blocks = block_input / scales
106
+
107
+ quantized_output = torch.empty(
108
+ block_input.numel(), dtype=torch.uint8, device=block_input.device
109
+ )
110
+ flattened = scaled_blocks.flatten()
111
+ quantized_output = _quantize_to_nearest_lut(
112
+ flattened, nf4_table.to(device=input.device, dtype=input.dtype)
113
+ )
114
+ quantized_output_uint8 = quantized_output.to(torch.uint8)
115
+
116
+ # pack the int4 weights into a uint8 tensor
117
+ # packing format: w0, w1, w2, w3, w4, w5, ...
118
+ # | byte | byte | byte |
119
+ packed_output_uint8 = quantized_output_uint8[::2] << 4 | quantized_output_uint8[1::2]
120
+
121
+ # pad the scales if needed
122
+ scales = reduce_block_padding(scales.view(-1), block_sizes={-1: scale_block_size})
123
+ return cls(original_input.shape, original_input.dtype, packed_output_uint8), scales
124
+
125
+ @classmethod
126
+ def double_quantization(cls, scales: torch.Tensor, scale_block_size: int, num_scale_bits: int):
127
+ """Perform double quantization on the scales.
128
+
129
+ Unlike the `quantize` method quantizing input data, this function quantizes float scales into
130
+ int8 to further reduce memory usage of scales.
131
+ """
132
+ # Double quantization for the scales, int8 per-block quantization
133
+ assert scales.numel() % scale_block_size == 0, (
134
+ "Number of scales elements is not divisible by the scale block size."
135
+ )
136
+ scale_quant_maxbound = 2 ** (num_scale_bits - 1) - 1
137
+ block_scales = scales.view(-1, scale_block_size)
138
+ num_scale_blocks = block_scales.shape[0]
139
+ scalers_zero_point = block_scales.mean()
140
+ block_scales = block_scales - scalers_zero_point
141
+
142
+ double_quant_scales = scale_quant_maxbound / reduce_amax(block_scales, -1)
143
+ quantized_scales = block_scales * double_quant_scales.expand(
144
+ num_scale_blocks, scale_block_size
145
+ )
146
+ quantized_scales = (
147
+ quantized_scales.round()
148
+ .clamp(-scale_quant_maxbound, scale_quant_maxbound)
149
+ .to(torch.int8)
150
+ )
151
+
152
+ return quantized_scales, double_quant_scales.flatten(), scalers_zero_point
153
+
154
+ def dequantize(self, dtype: torch.dtype = None, **kwarg):
155
+ """Dequantze NF4 packed tensor to a target dtype."""
156
+ if dtype is None:
157
+ dtype = self.metadata["dtype"]
158
+ cuda_ext = get_cuda_ext()
159
+
160
+ # get kwargs
161
+ scales = kwarg["scale"]
162
+ block_sizes = kwarg["block_sizes"]
163
+ double_scale = kwarg["double_scale"]
164
+ scale_zeros = kwarg["scale_zeros"]
165
+
166
+ # unpadd the scales if needed
167
+ scales = scales.view(-1)[: (self._quantized_data.numel() * 2) // block_sizes[-1]]
168
+
169
+ if cuda_ext and self._quantized_data.is_cuda:
170
+ # with a custom cuda kernel
171
+ scales = _dequantize_scalers(scales, double_scale, scale_zeros, dtype).flatten()
172
+ output = cuda_ext.NF4_dequantize(self._quantized_data, scales, block_sizes[-1])
173
+ return (
174
+ output.view(-1)[: np.prod(self.metadata["shape"])] # handle padding
175
+ .reshape(self.metadata["shape"])
176
+ .to(dtype)
177
+ )
178
+ else:
179
+ # de-qauntize scales
180
+ scales = _dequantize_scalers(scales, double_scale, scale_zeros, dtype).flatten()
181
+ # indexing in torch required long dtype, we may need to optimize this with customized kernels
182
+ first_half_idx = (self._quantized_data >> 4).to(torch.long)
183
+ second_half_idx = (self._quantized_data & 0x0F).to(torch.long)
184
+ scaled_first_half = _nf4_lookup(first_half_idx) # w0, w2, w4...
185
+ scaled_second_half = _nf4_lookup(second_half_idx) # w1, w3, w5...
186
+
187
+ # de-quantize tensor
188
+ first_half = scaled_first_half.view(-1, block_sizes[-1] // 2) * scales.view(-1, 1)
189
+ second_half = scaled_second_half.view(-1, block_sizes[-1] // 2) * scales.view(-1, 1)
190
+
191
+ # merge the interleaving elements
192
+ first_half = first_half.flatten().unsqueeze(-1).transpose(0, 1)
193
+ second_half = second_half.flatten().unsqueeze(-1).transpose(0, 1)
194
+ return (
195
+ torch.stack([first_half, second_half], dim=-1)
196
+ .view(-1)[: np.prod(self.metadata["shape"])] # handle padding
197
+ .reshape(self.metadata["shape"])
198
+ .to(dtype)
199
+ )
@@ -0,0 +1,295 @@
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
+ """Implements NVFP4 quantization for efficient tensor storage and computation."""
17
+
18
+ import torch
19
+
20
+ from ..backends.utils import fp4_compatible
21
+ from ..qtensor.base_qtensor import BaseQuantizedTensor
22
+ from ..utils import reduce_amax, reduce_block_amax, reduce_block_padding
23
+
24
+ # Define conversion tables
25
+ e2m1_bounds = torch.tensor([0.25, 0.75, 1.25, 1.75, 2.5, 3.5, 5])
26
+ e2m1_values = torch.tensor([0, 0.5, 1, 1.5, 2, 3, 4, 6, 0, -0.5, -1, -1.5, -2, -3, -4, -6])
27
+
28
+ __all__ = ["NVFP4QTensor"]
29
+
30
+
31
+ class NVFP4QTensor(BaseQuantizedTensor):
32
+ """Implements the INT4 quantization on tensors for more efficient storage or computation.
33
+
34
+ Attributes:
35
+ quantized_data (torch.Tensor): The quantized data stored as a packed uint8 tensor.
36
+ """
37
+
38
+ e2m1_values_on_device = {}
39
+ e2m1_bounds_on_device = {}
40
+
41
+ @classmethod
42
+ def get_e2m1_values(cls, device):
43
+ """Returns the e2m1 values on the device."""
44
+ if device not in cls.e2m1_values_on_device:
45
+ cls.e2m1_values_on_device[device] = e2m1_values.to(device)
46
+ return cls.e2m1_values_on_device[device]
47
+
48
+ @classmethod
49
+ def get_e2m1_bounds(cls, device):
50
+ """Returns the e2m1 values on the device."""
51
+ if device not in cls.e2m1_bounds_on_device:
52
+ cls.e2m1_bounds_on_device[device] = e2m1_bounds.to(device)
53
+ return cls.e2m1_bounds_on_device[device]
54
+
55
+ @classmethod
56
+ def get_weights_scaling_factor_2_from_quantizer(cls, weight_quantizer):
57
+ """Returns per tensor weight scaling factor from the weight_quantizer amax."""
58
+ # Assert that weight_quantizer has attribute amax
59
+ assert hasattr(weight_quantizer, "_amax"), "Weight quantizer does not have attribute amax"
60
+ return weight_quantizer._amax.float() / (6.0 * 448.0)
61
+
62
+ @classmethod
63
+ def get_weights_scaling_factor(
64
+ cls,
65
+ input: torch.Tensor,
66
+ block_size: int,
67
+ weights_scaling_factor_2: torch.Tensor | None = None,
68
+ keep_high_precision: bool = False,
69
+ ):
70
+ """Returns quantized per block weight scaling factor."""
71
+ if weights_scaling_factor_2 is None:
72
+ weights_scaling_factor_2 = cls.get_weights_scaling_factor_2(input)
73
+
74
+ # Get per_block amax
75
+ assert block_size != 0, "Block size is zero. Cannot return per_block amax for given input."
76
+
77
+ assert input.shape[-1] % block_size == 0, (
78
+ "Weight shape is not divisible for block size for block quantization."
79
+ )
80
+
81
+ # Get per block amax
82
+ per_block_amax = reduce_block_amax(input, block_sizes={-1: block_size}).float()
83
+ # Get per-block-scale
84
+ per_block_scale = per_block_amax / (6.0 * weights_scaling_factor_2)
85
+ # Set all zero values in scale to 1.0
86
+ per_block_scale[per_block_scale == 0] = 1.0
87
+ # Convert to torch.float8_e4m3fn
88
+ if not keep_high_precision:
89
+ per_block_scale = per_block_scale.to(torch.float8_e4m3fn)
90
+ return per_block_scale, weights_scaling_factor_2
91
+
92
+ @classmethod
93
+ def get_weights_scaling_factor_2(cls, input: torch.Tensor):
94
+ """Returns per tensor weight scaling factor."""
95
+ return reduce_amax(input).float() / (6.0 * 448.0)
96
+
97
+ @classmethod
98
+ def get_activation_scaling_factor(cls, quantizer):
99
+ """Returns the activation scaling factor for export."""
100
+ # TODO: Update to use module and not quantizer
101
+ if not quantizer.is_enabled:
102
+ return None
103
+
104
+ amax = quantizer.export_amax()
105
+
106
+ if amax is None:
107
+ return None
108
+
109
+ activation_scaling_factor = amax.float() / (quantizer.maxbound * 448.0)
110
+
111
+ assert torch.all(activation_scaling_factor > 0), (
112
+ f" activation scaling factor {activation_scaling_factor} not positive."
113
+ )
114
+
115
+ return activation_scaling_factor
116
+
117
+ @classmethod
118
+ def _cast_fp4(cls, weight: torch.Tensor):
119
+ """Converts tensor to uint4."""
120
+ device = weight.device
121
+
122
+ # Extract sign and compute absolute values in one pass
123
+ sign_bit = (weight < 0).to(torch.uint8)
124
+ weight_abs = weight.abs_()
125
+
126
+ # Get bounds and compute ordinal values
127
+ e2m1_bounds = cls.get_e2m1_bounds(device)
128
+ ord = torch.searchsorted(e2m1_bounds, weight_abs, out_int32=True).to(torch.uint8)
129
+
130
+ # Efficiently check for rounding at odd-indexed bounds [0.75, 1.75, 2.5]
131
+ # Only need to check bounds at indices 1, 3, 5
132
+ odd_bounds = e2m1_bounds[[1, 3, 5]] # [0.75, 1.75, 2.5]
133
+ equals_odd_bounds = torch.any(weight_abs.unsqueeze(-1) == odd_bounds, dim=-1).to(
134
+ torch.uint8
135
+ )
136
+
137
+ # Combine sign, ordinal, and rounding adjustment
138
+ return (sign_bit << 3) + ord + equals_odd_bounds
139
+
140
+ @classmethod
141
+ def quantize(
142
+ cls,
143
+ input: torch.Tensor,
144
+ block_size: int,
145
+ weights_scaling_factor: torch.Tensor | None = None,
146
+ weights_scaling_factor_2: torch.Tensor | None = None,
147
+ keep_high_precision: bool = False,
148
+ try_tensorrt: bool = False,
149
+ ):
150
+ """Converting a tensor to a quantized format based on NVFP4 quantization.
151
+
152
+ Args:
153
+ input (torch.Tensor): The input tensor to be quantized.
154
+ block_size (int): The size of each block for quantization.
155
+ weights_scaling_factor (torch.Tensor): The scaling factor for the weights.
156
+ weights_scaling_factor_2 (torch.Tensor): The scaling factor for the weights.
157
+ keep_high_precision (bool): Whether to keep output scales at high precision.
158
+
159
+ Returns:
160
+ tuple: Contains quantized data, quantized per block scaling factor, and per tensor scaling factor.
161
+ """
162
+ # Get original input shape
163
+ input_shape = input.shape
164
+ input_dtype = input.dtype
165
+
166
+ # pad the input if needed
167
+ input = reduce_block_padding(input, block_sizes={-1: block_size})
168
+
169
+ if weights_scaling_factor_2 is None:
170
+ weights_scaling_factor_2 = cls.get_weights_scaling_factor_2(input)
171
+
172
+ # try call trtllm fp4 quantization if possible
173
+ if (
174
+ fp4_compatible()
175
+ and weights_scaling_factor is None
176
+ and try_tensorrt
177
+ and block_size == 16
178
+ and input.is_cuda
179
+ and input.dtype in [torch.half, torch.bfloat16]
180
+ ):
181
+ try:
182
+ import tensorrt_llm # noqa: F401
183
+
184
+ # Make sure this utils is available for dequantize
185
+ from tensorrt_llm._torch.auto_deploy.utils.quantization_utils import (
186
+ cutlass_fp4_scale_to_modelopt_fp4_scale, # noqa: F401
187
+ )
188
+
189
+ packed_weight, weights_scaling_factor = torch.ops.trtllm.fp4_quantize(
190
+ input, 1.0 / weights_scaling_factor_2, block_size, False
191
+ )
192
+ # weights_scaling_factor is ready for nvfp4_gemm to use;
193
+ # however, it is different from the non trtllm version, so when dequantize,
194
+ # it will be converted.
195
+ return (
196
+ cls(input_shape, input_dtype, packed_weight),
197
+ weights_scaling_factor,
198
+ weights_scaling_factor_2,
199
+ )
200
+ except ImportError:
201
+ pass
202
+
203
+ if weights_scaling_factor is None:
204
+ weights_scaling_factor, _ = cls.get_weights_scaling_factor(
205
+ input, block_size, weights_scaling_factor_2
206
+ )
207
+
208
+ # Reshape the weight and scale factors
209
+ original_shape = input.shape
210
+ input = input.view((*tuple(input.shape[:-1]), -1, block_size))
211
+
212
+ # Scale weights
213
+ scaled_weight = input / (
214
+ (weights_scaling_factor.to(torch.float32) * weights_scaling_factor_2).unsqueeze(-1)
215
+ )
216
+
217
+ # Reshape weights to original
218
+ scaled_weight = scaled_weight.view(original_shape)
219
+
220
+ if keep_high_precision:
221
+ return scaled_weight
222
+ # Cast weights to fp4
223
+ q_weight = cls._cast_fp4(scaled_weight)
224
+ # Pack weights
225
+ packed_weight = (q_weight[..., 1::2] << 4) | q_weight[..., 0::2]
226
+ return (
227
+ cls(input_shape, input_dtype, packed_weight),
228
+ weights_scaling_factor,
229
+ weights_scaling_factor_2,
230
+ )
231
+
232
+ def dequantize(self, dtype: torch.dtype = None, fast=False, **kwarg):
233
+ """Dequantze NVFP4 packed tensor to a target dtype."""
234
+ if dtype is None:
235
+ dtype = self.metadata["dtype"]
236
+
237
+ def _unpack_tensor(input: torch.Tensor):
238
+ # Initialize storage for unpacked tensor
239
+ unpacked_shape = list(input.shape)
240
+ unpacked_shape[-1] = unpacked_shape[-1] * 2
241
+ unpacked = torch.empty(unpacked_shape, dtype=dtype, device=input.device)
242
+
243
+ unpacked[..., 1::2] = input >> 4
244
+ unpacked[..., 0::2] = input & 0x0F
245
+
246
+ unpacked = unpacked.reshape(-1)
247
+ unpacked = self.get_e2m1_values(input.device)[unpacked.long()]
248
+
249
+ return unpacked.reshape(unpacked_shape)
250
+
251
+ # Get scales from kwargs
252
+ if kwarg["scale"].dtype == torch.uint8 and kwarg["scale"].ndim == 1:
253
+ # If quantization is done by trtllm, convert cutlass fp4 scale to modelopt fp4 scale
254
+ try:
255
+ from tensorrt_llm._torch.auto_deploy.utils.quantization_utils import (
256
+ cutlass_fp4_scale_to_modelopt_fp4_scale,
257
+ )
258
+
259
+ kwarg["scale"] = cutlass_fp4_scale_to_modelopt_fp4_scale(
260
+ kwarg["scale"], self.metadata["shape"][-2:]
261
+ )
262
+ except ImportError as e:
263
+ raise ImportError(
264
+ "This tensor is quantized by trtllm, but tensorrt_llm cannot be imported."
265
+ ) from e
266
+
267
+ if fast:
268
+ from ..triton.fp4_kernel import fp4_dequantize
269
+
270
+ return fp4_dequantize(
271
+ self._quantized_data,
272
+ kwarg["scale"],
273
+ kwarg["double_scale"],
274
+ block_size=kwarg["block_sizes"][-1],
275
+ dtype=dtype,
276
+ ).reshape(self.metadata["shape"])
277
+ else:
278
+ q_per_block_scale = (
279
+ kwarg["scale"].to(torch.float32)
280
+ if kwarg["scale"].dtype == torch.float8_e4m3fn
281
+ else kwarg["scale"]
282
+ )
283
+ block_size = kwarg["block_sizes"][-1]
284
+ per_block_quant_scale = kwarg["double_scale"]
285
+
286
+ # Dequantize scales
287
+ per_block_scale = q_per_block_scale * per_block_quant_scale
288
+
289
+ # Unpack and unscale weights
290
+ deq_data = _unpack_tensor(self._quantized_data)
291
+
292
+ deq_data = deq_data.view(
293
+ (*tuple(deq_data.shape[:-1]), -1, block_size)
294
+ ) * per_block_scale.unsqueeze(-1)
295
+ return deq_data.reshape(self.metadata["shape"]).to(dtype)
@@ -0,0 +1,77 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "tensor_quant.h"
19
+
20
+ at::Tensor NF4_dequantize(torch::Tensor quantized_data, torch::Tensor scales, int block_size) {
21
+ TORCH_CHECK(quantized_data.is_cuda());
22
+ return NF4_dequantize_cuda(quantized_data, scales, block_size);
23
+ }
24
+ at::Tensor NF4_quantize(torch::Tensor quantized_data, torch::Tensor scales, int block_size) {
25
+ TORCH_CHECK(quantized_data.is_cuda());
26
+ return NF4_quantize_cuda(quantized_data, scales, block_size);
27
+ }
28
+ at::Tensor INT4_dequantize(torch::Tensor quantized_data, torch::Tensor scales, int block_size) {
29
+ TORCH_CHECK(quantized_data.is_cuda());
30
+ return INT4_dequantize_cuda(quantized_data, scales, block_size);
31
+ }
32
+ at::Tensor INT4_quantize(torch::Tensor quantized_data, torch::Tensor scales, int block_size) {
33
+ TORCH_CHECK(quantized_data.is_cuda());
34
+ return INT4_quantize_cuda(quantized_data, scales, block_size);
35
+ }
36
+
37
+ void fake_tensor_quant_(at::Tensor inputs, at::Tensor amax, int num_bits = 8,
38
+ bool is_unsigned = false, bool narrow_range = true) {
39
+ TORCH_CHECK(inputs.is_cuda());
40
+ TORCH_CHECK(inputs.is_contiguous()) // in-place on non-contiguous tensor is
41
+ // more difficult
42
+ TORCH_CHECK(amax.numel(), 1);
43
+ fake_tensor_quant_cuda_inplace(inputs, amax, num_bits, is_unsigned, narrow_range);
44
+ }
45
+ // TODO: Can we add support for CPU tensors here?
46
+ at::Tensor fake_tensor_quant(at::Tensor inputs, at::Tensor amax, int num_bits = 8,
47
+ bool is_unsigned = false, bool narrow_range = true) {
48
+ TORCH_CHECK(inputs.is_cuda());
49
+ TORCH_CHECK(amax.numel(), 1);
50
+ return fake_tensor_quant_cuda(inputs.contiguous(), amax.contiguous(), num_bits, is_unsigned,
51
+ narrow_range);
52
+ }
53
+
54
+ at::Tensor fake_tensor_quant_with_axis(at::Tensor inputs, at::Tensor amax, int axis,
55
+ int num_bits = 8, bool is_unsigned = false,
56
+ bool narrow_range = true) {
57
+ TORCH_CHECK(inputs.is_cuda());
58
+ TORCH_CHECK(amax.numel(), inputs.size(axis));
59
+ return fake_tensor_quant_with_axis_cuda(inputs.contiguous(), amax.contiguous(), axis, num_bits,
60
+ is_unsigned, narrow_range);
61
+ }
62
+
63
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
64
+ m.def("fake_tensor_quant_", &fake_tensor_quant_, "Fake Tensor Quant Inplace", py::arg("inputs"),
65
+ py::arg("amax"), py::arg("num_bits") = 8, py::arg("unsigned") = false,
66
+ py::arg("narrow_range") = true);
67
+ m.def("fake_tensor_quant", &fake_tensor_quant, "Fake Tensor Quant", py::arg("inputs"),
68
+ py::arg("amax"), py::arg("num_bits") = 8, py::arg("unsigned") = false,
69
+ py::arg("narrow_range") = true);
70
+ m.def("fake_tensor_quant_with_axis", &fake_tensor_quant_with_axis, "Fake Tensor Quant with axis",
71
+ py::arg("inputs"), py::arg("amax"), py::arg("axis"), py::arg("num_bits") = 8,
72
+ py::arg("unsigned") = false, py::arg("narrow_range") = true);
73
+ m.def("NF4_dequantize", &NF4_dequantize, "Dequantize NF4 weights.");
74
+ m.def("NF4_quantize", &NF4_quantize, "Quantize NF4 weights.");
75
+ m.def("INT4_dequantize", &INT4_dequantize, "Dequantize INT4 weights.");
76
+ m.def("INT4_quantize", &INT4_quantize, "Quantize INT4 weights.");
77
+ }
@@ -0,0 +1,69 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <torch/extension.h>
19
+
20
+ // TODO: add descriptions for functions
21
+ void fake_tensor_quant_cuda_inplace(at::Tensor, at::Tensor, int, bool, bool);
22
+ at::Tensor fake_tensor_quant_cuda(at::Tensor, at::Tensor, int, bool, bool);
23
+ at::Tensor fake_tensor_quant_with_axis_cuda(at::Tensor, at::Tensor, int, int, bool, bool);
24
+ float bits_to_bound(int, int);
25
+ at::Tensor fake_e4m3fy_cuda(at::Tensor inputs);
26
+
27
+ // Dequantizes data using NF4 quantization scheme and per-block scaling factors.
28
+ //
29
+ // Args:
30
+ // quantized_data (torch::Tensor): Quantized data packed into uint8.
31
+ // scales (torch::Tensor): Scaling factors for each data block.
32
+ // block_size (int): Number of elements per data block.
33
+ //
34
+ // Returns:
35
+ // at::Tensor: Dequantized data as bf16 tensor.
36
+ at::Tensor NF4_dequantize_cuda(torch::Tensor, torch::Tensor, int);
37
+
38
+ // Quantizes data using NF4 quantization scheme and per-block scaling factors.
39
+ //
40
+ // Args:
41
+ // quantized_data (torch::Tensor): High precision data in fp32/fp16/bf16.
42
+ // scales (torch::Tensor): Scaling factors for each data block.
43
+ // block_size (int): Number of elements per data block.
44
+ //
45
+ // Returns:
46
+ // at::Tensor: Quantized data packed in uint8.
47
+ at::Tensor NF4_quantize_cuda(torch::Tensor, torch::Tensor, int);
48
+
49
+ // Dequantizes data using INT4 quantization scheme and per-block scaling factors.
50
+ //
51
+ // Args:
52
+ // quantized_data (torch::Tensor): Quantized data packed into uint8.
53
+ // scales (torch::Tensor): Scaling factors for each data block.
54
+ // block_size (int): Number of elements per data block.
55
+ //
56
+ // Returns:
57
+ // at::Tensor: Dequantized data as the same dtype of scales.
58
+ at::Tensor INT4_dequantize_cuda(torch::Tensor, torch::Tensor, int);
59
+
60
+ // Quantizes data using INT4 quantization scheme and per-block scaling factors.
61
+ //
62
+ // Args:
63
+ // quantized_data (torch::Tensor): High precision data in fp32/fp16/bf16.
64
+ // scales (torch::Tensor): Scaling factors for each data block.
65
+ // block_size (int): Number of elements per data block.
66
+ //
67
+ // Returns:
68
+ // at::Tensor: Quantized data packed in uint8.
69
+ at::Tensor INT4_quantize_cuda(torch::Tensor, torch::Tensor, int);
@@ -0,0 +1,48 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <ATen/ATen.h>
19
+ #include <cuda_fp8.h>
20
+ #include <torch/extension.h>
21
+
22
+ at::Tensor fake_e4m3fy_cuda(at::Tensor inputs);
23
+ at::Tensor fused_fake_e4m3fy_cuda(at::Tensor inputs, at::Tensor amax, const float zero_threshold);
24
+
25
+ at::Tensor fake_e4m3fy(at::Tensor inputs) {
26
+ if (inputs.is_cuda()) {
27
+ return fake_e4m3fy_cuda(inputs.contiguous());
28
+ } else {
29
+ TORCH_CHECK(inputs.dtype() == at::ScalarType::Float);
30
+ TORCH_CHECK(inputs.is_contiguous());
31
+ auto out = at::zeros_like(inputs);
32
+ for (int i = 0; i < inputs.numel(); ++i) {
33
+ out.data_ptr<float>()[i] =
34
+ static_cast<float>(static_cast<__nv_fp8_e4m3>(inputs.data_ptr<float>()[i]));
35
+ }
36
+ return out;
37
+ }
38
+ }
39
+
40
+ at::Tensor fused_fake_e4m3fy(at::Tensor inputs, at::Tensor amax, const float zero_threshold) {
41
+ return fused_fake_e4m3fy_cuda(inputs.contiguous(), amax, zero_threshold);
42
+ }
43
+
44
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
45
+ m.def("fake_e4m3fy", &fake_e4m3fy, "Reduce precision to E4M3", py::arg("inputs"));
46
+ m.def("fused_fake_e4m3fy", &fused_fake_e4m3fy, "Reduce precision to E4M3 (fused)",
47
+ py::arg("inputs"), py::arg("amax"), py::arg("zero_threshold"));
48
+ }