nvidia-modelopt 0.35.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelopt/__init__.py +20 -0
- modelopt/deploy/__init__.py +16 -0
- modelopt/deploy/llm/__init__.py +30 -0
- modelopt/deploy/llm/generate.py +345 -0
- modelopt/onnx/__init__.py +34 -0
- modelopt/onnx/autocast/__init__.py +19 -0
- modelopt/onnx/autocast/__main__.py +187 -0
- modelopt/onnx/autocast/convert.py +202 -0
- modelopt/onnx/autocast/graphsanitizer.py +422 -0
- modelopt/onnx/autocast/logging_config.py +78 -0
- modelopt/onnx/autocast/nodeclassifier.py +416 -0
- modelopt/onnx/autocast/precisionconverter.py +1032 -0
- modelopt/onnx/autocast/referencerunner.py +159 -0
- modelopt/onnx/autocast/utils.py +117 -0
- modelopt/onnx/llm_export_utils/__init__.py +16 -0
- modelopt/onnx/llm_export_utils/export_utils.py +162 -0
- modelopt/onnx/llm_export_utils/quantization_utils.py +122 -0
- modelopt/onnx/llm_export_utils/surgeon_utils.py +120 -0
- modelopt/onnx/logging_config.py +77 -0
- modelopt/onnx/op_types.py +300 -0
- modelopt/onnx/quantization/__init__.py +20 -0
- modelopt/onnx/quantization/__main__.py +291 -0
- modelopt/onnx/quantization/calib_utils.py +178 -0
- modelopt/onnx/quantization/extensions.py +35 -0
- modelopt/onnx/quantization/fp8.py +375 -0
- modelopt/onnx/quantization/graph_utils.py +1479 -0
- modelopt/onnx/quantization/gs_patching.py +112 -0
- modelopt/onnx/quantization/int4.py +1347 -0
- modelopt/onnx/quantization/int8.py +283 -0
- modelopt/onnx/quantization/operators.py +121 -0
- modelopt/onnx/quantization/ort_patching.py +1766 -0
- modelopt/onnx/quantization/ort_utils.py +346 -0
- modelopt/onnx/quantization/partitioning.py +439 -0
- modelopt/onnx/quantization/qdq_utils.py +1349 -0
- modelopt/onnx/quantization/quant_utils.py +283 -0
- modelopt/onnx/quantization/quantize.py +528 -0
- modelopt/onnx/quantization/src/modelopt_round_and_pack_ext.cpp +127 -0
- modelopt/onnx/trt_utils.py +424 -0
- modelopt/onnx/utils.py +753 -0
- modelopt/torch/__init__.py +41 -0
- modelopt/torch/_deploy/__init__.py +23 -0
- modelopt/torch/_deploy/_runtime/__init__.py +29 -0
- modelopt/torch/_deploy/_runtime/common.py +72 -0
- modelopt/torch/_deploy/_runtime/ort_client.py +193 -0
- modelopt/torch/_deploy/_runtime/registry.py +83 -0
- modelopt/torch/_deploy/_runtime/runtime_client.py +154 -0
- modelopt/torch/_deploy/_runtime/tensorrt/constants.py +108 -0
- modelopt/torch/_deploy/_runtime/tensorrt/engine_builder.py +324 -0
- modelopt/torch/_deploy/_runtime/tensorrt/hw_param_config.py +51 -0
- modelopt/torch/_deploy/_runtime/tensorrt/layerwise_profiling.py +178 -0
- modelopt/torch/_deploy/_runtime/tensorrt/parse_trtexec_log.py +151 -0
- modelopt/torch/_deploy/_runtime/tensorrt/tensorrt_utils.py +200 -0
- modelopt/torch/_deploy/_runtime/trt_client.py +219 -0
- modelopt/torch/_deploy/compilation.py +142 -0
- modelopt/torch/_deploy/device_model.py +157 -0
- modelopt/torch/_deploy/profiling.py +193 -0
- modelopt/torch/_deploy/utils/__init__.py +18 -0
- modelopt/torch/_deploy/utils/onnx_optimizer.py +120 -0
- modelopt/torch/_deploy/utils/onnx_utils.py +58 -0
- modelopt/torch/_deploy/utils/torch_onnx.py +593 -0
- modelopt/torch/distill/__init__.py +28 -0
- modelopt/torch/distill/config.py +130 -0
- modelopt/torch/distill/distillation.py +84 -0
- modelopt/torch/distill/distillation_model.py +318 -0
- modelopt/torch/distill/loss_balancers.py +140 -0
- modelopt/torch/distill/losses.py +275 -0
- modelopt/torch/distill/mode.py +223 -0
- modelopt/torch/distill/plugins/__init__.py +24 -0
- modelopt/torch/distill/plugins/huggingface.py +110 -0
- modelopt/torch/distill/plugins/megatron.py +476 -0
- modelopt/torch/distill/registry.py +23 -0
- modelopt/torch/export/__init__.py +24 -0
- modelopt/torch/export/convert_hf_config.py +117 -0
- modelopt/torch/export/distribute.py +300 -0
- modelopt/torch/export/hf_config_map.py +84 -0
- modelopt/torch/export/layer_utils.py +1893 -0
- modelopt/torch/export/mcore_config_map.py +25 -0
- modelopt/torch/export/model_config.py +623 -0
- modelopt/torch/export/model_config_export.py +552 -0
- modelopt/torch/export/model_config_utils.py +392 -0
- modelopt/torch/export/model_utils.py +71 -0
- modelopt/torch/export/plugins/__init__.py +21 -0
- modelopt/torch/export/plugins/mcore_common.py +67 -0
- modelopt/torch/export/plugins/mcore_custom.py +530 -0
- modelopt/torch/export/plugins/mcore_deepseek.py +143 -0
- modelopt/torch/export/plugins/mcore_gptoss.py +71 -0
- modelopt/torch/export/plugins/mcore_llama.py +164 -0
- modelopt/torch/export/plugins/mcore_nemotron.py +90 -0
- modelopt/torch/export/plugins/mcore_qwen.py +99 -0
- modelopt/torch/export/plugins/megatron_importer.py +647 -0
- modelopt/torch/export/postprocess.py +847 -0
- modelopt/torch/export/quant_utils.py +1069 -0
- modelopt/torch/export/tensorrt_llm_type.py +42 -0
- modelopt/torch/export/tensorrt_llm_utils.py +405 -0
- modelopt/torch/export/transformer_engine.py +94 -0
- modelopt/torch/export/unified_export_hf.py +537 -0
- modelopt/torch/export/unified_export_megatron.py +1164 -0
- modelopt/torch/nas/__init__.py +27 -0
- modelopt/torch/nas/algorithms.py +856 -0
- modelopt/torch/nas/autonas.py +808 -0
- modelopt/torch/nas/conversion.py +119 -0
- modelopt/torch/nas/hparams/__init__.py +19 -0
- modelopt/torch/nas/hparams/concat.py +319 -0
- modelopt/torch/nas/hparams/container.py +48 -0
- modelopt/torch/nas/modules/__init__.py +21 -0
- modelopt/torch/nas/modules/container.py +99 -0
- modelopt/torch/nas/modules/conv.py +254 -0
- modelopt/torch/nas/modules/linear.py +76 -0
- modelopt/torch/nas/modules/norm.py +193 -0
- modelopt/torch/nas/modules/utils.py +61 -0
- modelopt/torch/nas/patch.py +261 -0
- modelopt/torch/nas/plugins/__init__.py +29 -0
- modelopt/torch/nas/plugins/megatron.py +1497 -0
- modelopt/torch/nas/plugins/torch.py +71 -0
- modelopt/torch/nas/plugins/transformer_engine.py +42 -0
- modelopt/torch/nas/plugins/transformers.py +210 -0
- modelopt/torch/nas/registry.py +23 -0
- modelopt/torch/nas/search_space.py +260 -0
- modelopt/torch/nas/traced_hp.py +149 -0
- modelopt/torch/nas/utils.py +408 -0
- modelopt/torch/opt/__init__.py +41 -0
- modelopt/torch/opt/_hooks.py +98 -0
- modelopt/torch/opt/config.py +383 -0
- modelopt/torch/opt/conversion.py +620 -0
- modelopt/torch/opt/dynamic.py +1367 -0
- modelopt/torch/opt/hparam.py +275 -0
- modelopt/torch/opt/mode.py +353 -0
- modelopt/torch/opt/plugins/__init__.py +38 -0
- modelopt/torch/opt/plugins/diffusers.py +40 -0
- modelopt/torch/opt/plugins/huggingface.py +162 -0
- modelopt/torch/opt/plugins/mcore_dist_checkpointing.py +211 -0
- modelopt/torch/opt/plugins/megatron.py +142 -0
- modelopt/torch/opt/plugins/peft.py +108 -0
- modelopt/torch/opt/plugins/transformers.py +160 -0
- modelopt/torch/opt/searcher.py +363 -0
- modelopt/torch/opt/utils.py +125 -0
- modelopt/torch/prune/__init__.py +26 -0
- modelopt/torch/prune/fastnas.py +376 -0
- modelopt/torch/prune/gradnas.py +349 -0
- modelopt/torch/prune/plugins/__init__.py +24 -0
- modelopt/torch/prune/plugins/mcore_minitron.py +263 -0
- modelopt/torch/prune/plugins/transformers.py +41 -0
- modelopt/torch/prune/pruning.py +211 -0
- modelopt/torch/quantization/__init__.py +26 -0
- modelopt/torch/quantization/algorithms.py +671 -0
- modelopt/torch/quantization/backends/__init__.py +20 -0
- modelopt/torch/quantization/backends/fp8_per_tensor_gemm.py +204 -0
- modelopt/torch/quantization/backends/gemm_registry.py +156 -0
- modelopt/torch/quantization/backends/nvfp4_gemm.py +201 -0
- modelopt/torch/quantization/backends/utils.py +28 -0
- modelopt/torch/quantization/calib/__init__.py +25 -0
- modelopt/torch/quantization/calib/bias.py +172 -0
- modelopt/torch/quantization/calib/calibrator.py +63 -0
- modelopt/torch/quantization/calib/histogram.py +434 -0
- modelopt/torch/quantization/calib/max.py +110 -0
- modelopt/torch/quantization/compress.py +227 -0
- modelopt/torch/quantization/config.py +1180 -0
- modelopt/torch/quantization/conversion.py +389 -0
- modelopt/torch/quantization/export_onnx.py +639 -0
- modelopt/torch/quantization/extensions.py +89 -0
- modelopt/torch/quantization/mode.py +428 -0
- modelopt/torch/quantization/model_calib.py +949 -0
- modelopt/torch/quantization/model_quant.py +477 -0
- modelopt/torch/quantization/nn/__init__.py +26 -0
- modelopt/torch/quantization/nn/functional.py +109 -0
- modelopt/torch/quantization/nn/modules/__init__.py +16 -0
- modelopt/torch/quantization/nn/modules/quant_activations.py +22 -0
- modelopt/torch/quantization/nn/modules/quant_batchnorm.py +24 -0
- modelopt/torch/quantization/nn/modules/quant_conv.py +123 -0
- modelopt/torch/quantization/nn/modules/quant_instancenorm.py +39 -0
- modelopt/torch/quantization/nn/modules/quant_linear.py +258 -0
- modelopt/torch/quantization/nn/modules/quant_module.py +211 -0
- modelopt/torch/quantization/nn/modules/quant_pooling.py +99 -0
- modelopt/torch/quantization/nn/modules/quant_rnn.py +527 -0
- modelopt/torch/quantization/nn/modules/tensor_quantizer.py +1293 -0
- modelopt/torch/quantization/plugins/__init__.py +73 -0
- modelopt/torch/quantization/plugins/accelerate.py +214 -0
- modelopt/torch/quantization/plugins/apex.py +52 -0
- modelopt/torch/quantization/plugins/attention.py +312 -0
- modelopt/torch/quantization/plugins/custom.py +192 -0
- modelopt/torch/quantization/plugins/diffusers.py +237 -0
- modelopt/torch/quantization/plugins/fairscale.py +45 -0
- modelopt/torch/quantization/plugins/huggingface.py +736 -0
- modelopt/torch/quantization/plugins/megatron.py +462 -0
- modelopt/torch/quantization/plugins/peft.py +148 -0
- modelopt/torch/quantization/plugins/transformer_engine.py +60 -0
- modelopt/torch/quantization/plugins/transformers.py +52 -0
- modelopt/torch/quantization/plugins/transformers_trainer.py +426 -0
- modelopt/torch/quantization/plugins/trl.py +27 -0
- modelopt/torch/quantization/plugins/vllm.py +199 -0
- modelopt/torch/quantization/qtensor/__init__.py +24 -0
- modelopt/torch/quantization/qtensor/base_qtensor.py +370 -0
- modelopt/torch/quantization/qtensor/fp8_tensor.py +151 -0
- modelopt/torch/quantization/qtensor/int4_tensor.py +130 -0
- modelopt/torch/quantization/qtensor/int8_tensor.py +124 -0
- modelopt/torch/quantization/qtensor/mxfp4_tensor.py +144 -0
- modelopt/torch/quantization/qtensor/nf4_tensor.py +199 -0
- modelopt/torch/quantization/qtensor/nvfp4_tensor.py +295 -0
- modelopt/torch/quantization/src/tensor_quant.cpp +77 -0
- modelopt/torch/quantization/src/tensor_quant.h +69 -0
- modelopt/torch/quantization/src/tensor_quant_fp8.cpp +48 -0
- modelopt/torch/quantization/src/tensor_quant_gpu.cu +361 -0
- modelopt/torch/quantization/src/tensor_quant_gpu_fp8.cu +122 -0
- modelopt/torch/quantization/src/tensor_quant_mx.cu +411 -0
- modelopt/torch/quantization/src/tensor_quant_mx.h +247 -0
- modelopt/torch/quantization/tensor_quant.py +816 -0
- modelopt/torch/quantization/triton/__init__.py +36 -0
- modelopt/torch/quantization/triton/fp4_kernel.py +303 -0
- modelopt/torch/quantization/utils.py +443 -0
- modelopt/torch/sparsity/__init__.py +19 -0
- modelopt/torch/sparsity/config.py +51 -0
- modelopt/torch/sparsity/magnitude.py +148 -0
- modelopt/torch/sparsity/mode.py +203 -0
- modelopt/torch/sparsity/module.py +87 -0
- modelopt/torch/sparsity/plugins/__init__.py +27 -0
- modelopt/torch/sparsity/plugins/megatron.py +93 -0
- modelopt/torch/sparsity/searcher.py +84 -0
- modelopt/torch/sparsity/sparsegpt.py +276 -0
- modelopt/torch/sparsity/sparsification.py +123 -0
- modelopt/torch/speculative/__init__.py +20 -0
- modelopt/torch/speculative/config.py +100 -0
- modelopt/torch/speculative/eagle/__init__.py +20 -0
- modelopt/torch/speculative/eagle/conversion.py +67 -0
- modelopt/torch/speculative/eagle/default_config.py +50 -0
- modelopt/torch/speculative/eagle/eagle_model.py +51 -0
- modelopt/torch/speculative/eagle/utils.py +91 -0
- modelopt/torch/speculative/medusa/__init__.py +19 -0
- modelopt/torch/speculative/medusa/conversion.py +59 -0
- modelopt/torch/speculative/medusa/medusa_model.py +32 -0
- modelopt/torch/speculative/mode.py +86 -0
- modelopt/torch/speculative/plugins/__init__.py +33 -0
- modelopt/torch/speculative/plugins/megatron_eagle.py +2119 -0
- modelopt/torch/speculative/plugins/megatron_medusa.py +312 -0
- modelopt/torch/speculative/plugins/transformers.py +1138 -0
- modelopt/torch/speculative/speculative_decoding.py +59 -0
- modelopt/torch/speculative/utils.py +364 -0
- modelopt/torch/trace/__init__.py +25 -0
- modelopt/torch/trace/analyzer.py +1368 -0
- modelopt/torch/trace/modules/__init__.py +19 -0
- modelopt/torch/trace/modules/concat.py +384 -0
- modelopt/torch/trace/modules/nn.py +153 -0
- modelopt/torch/trace/plugins/__init__.py +34 -0
- modelopt/torch/trace/plugins/megatron.py +36 -0
- modelopt/torch/trace/plugins/transformers.py +58 -0
- modelopt/torch/trace/symbols.py +545 -0
- modelopt/torch/trace/tracer.py +331 -0
- modelopt/torch/utils/__init__.py +28 -0
- modelopt/torch/utils/_pytree.py +133 -0
- modelopt/torch/utils/cpp_extension.py +91 -0
- modelopt/torch/utils/dataset_utils.py +484 -0
- modelopt/torch/utils/distributed.py +311 -0
- modelopt/torch/utils/graph.py +123 -0
- modelopt/torch/utils/image_processor.py +112 -0
- modelopt/torch/utils/import_utils.py +35 -0
- modelopt/torch/utils/list.py +54 -0
- modelopt/torch/utils/logging.py +127 -0
- modelopt/torch/utils/memory_monitor.py +146 -0
- modelopt/torch/utils/network.py +658 -0
- modelopt/torch/utils/perf.py +174 -0
- modelopt/torch/utils/plugins/__init__.py +27 -0
- modelopt/torch/utils/plugins/megatron_generate.py +299 -0
- modelopt/torch/utils/plugins/megatron_mmlu.py +152 -0
- modelopt/torch/utils/plugins/megatron_preprocess_data.py +200 -0
- modelopt/torch/utils/random.py +163 -0
- modelopt/torch/utils/speech_dataset_utils.py +134 -0
- modelopt/torch/utils/tensor.py +87 -0
- modelopt/torch/utils/vlm_dataset_utils.py +110 -0
- nvidia_modelopt-0.35.0.dist-info/METADATA +171 -0
- nvidia_modelopt-0.35.0.dist-info/RECORD +272 -0
- nvidia_modelopt-0.35.0.dist-info/WHEEL +5 -0
- nvidia_modelopt-0.35.0.dist-info/licenses/LICENSE +14 -0
- nvidia_modelopt-0.35.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,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
|
+
}
|