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,411 @@
|
|
|
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 <c10/cuda/CUDAStream.h>
|
|
20
|
+
#include <cuda.h>
|
|
21
|
+
#include <cuda/std/bit>
|
|
22
|
+
#include <cuda/std/tuple>
|
|
23
|
+
#include <cuda_fp16.h>
|
|
24
|
+
#include <cuda_runtime.h>
|
|
25
|
+
|
|
26
|
+
#include <torch/extension.h>
|
|
27
|
+
|
|
28
|
+
#include <algorithm>
|
|
29
|
+
#include <cmath>
|
|
30
|
+
#include <cub/cub.cuh>
|
|
31
|
+
|
|
32
|
+
#include "tensor_quant_mx.h"
|
|
33
|
+
|
|
34
|
+
namespace {
|
|
35
|
+
|
|
36
|
+
static __device__ __host__ __inline__ float quantize(const float x, const float scale,
|
|
37
|
+
const float unscale, const Types format) {
|
|
38
|
+
// Get the sign.
|
|
39
|
+
int sign;
|
|
40
|
+
if (x < 0.0)
|
|
41
|
+
sign = -1;
|
|
42
|
+
if (x > 0.0)
|
|
43
|
+
sign = 1;
|
|
44
|
+
// Absolute value of x.
|
|
45
|
+
float xabs = fabsf(x);
|
|
46
|
+
// Scale.
|
|
47
|
+
xabs = xabs * scale;
|
|
48
|
+
// Quantize.
|
|
49
|
+
xabs = convert_to_types(xabs, format);
|
|
50
|
+
// Unscale.
|
|
51
|
+
xabs = xabs * unscale;
|
|
52
|
+
|
|
53
|
+
// Apply sign.
|
|
54
|
+
return sign * xabs;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
* Get the maximum for a format for quantization purposes.
|
|
59
|
+
*
|
|
60
|
+
* Note: we split out e8mY formats as a) they don't need scaling for
|
|
61
|
+
* dynamic range, and if we _do_ scale, we can easily get numerical
|
|
62
|
+
* weirdnesses - 1/scale has a habit of flushing -> 0 and causing
|
|
63
|
+
* NaN in answers. For this reason, effectively disable scaling
|
|
64
|
+
* for these formats (scale=unscale=1)
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
// Algorithms for E8M0 scaling factor computation: OCP and NV
|
|
68
|
+
// Both implementations require or assume the following:
|
|
69
|
+
// * amax is the maximum magnitude input value,
|
|
70
|
+
// * dmax is the maximum magnitude representable by config,
|
|
71
|
+
// * the range of config is symmetric.
|
|
72
|
+
|
|
73
|
+
// OCP algorithm:
|
|
74
|
+
// scale = 2 ** clamp(floor(log2(amax)) - floor(log2(dmax)), -127, 127),
|
|
75
|
+
__device__ __host__ cuda::std::tuple<float, float> compute_scale_e8m0_OCP(float amax,
|
|
76
|
+
Types format) {
|
|
77
|
+
// lg2_dmax = log2(maximum power-of-two representable by config)
|
|
78
|
+
int32_t lg2_dmax = get_format_lg2_max(format);
|
|
79
|
+
|
|
80
|
+
// lg2_amax = floor(log2(amax))
|
|
81
|
+
// The following code assumes amax is a positive, finite FP32 value.
|
|
82
|
+
union {
|
|
83
|
+
float f32;
|
|
84
|
+
uint32_t u32;
|
|
85
|
+
} amax_bits;
|
|
86
|
+
|
|
87
|
+
amax_bits.f32 = amax;
|
|
88
|
+
|
|
89
|
+
uint32_t amax_exponent_field = (amax_bits.u32 >> 23) & 0xff;
|
|
90
|
+
uint32_t amax_significand_field = amax_bits.u32 & 0x7fffff;
|
|
91
|
+
int32_t lg2_amax = amax_exponent_field == 0
|
|
92
|
+
? static_cast<int32_t>(cuda::std::bit_width(amax_significand_field)) - 150
|
|
93
|
+
: static_cast<int32_t>(amax_exponent_field) - 127;
|
|
94
|
+
|
|
95
|
+
int unscale_exponent = std::clamp(lg2_amax - lg2_dmax, -127, 127);
|
|
96
|
+
|
|
97
|
+
float scale = ldexpf(1.f, -unscale_exponent);
|
|
98
|
+
float unscale = ldexpf(1.f, unscale_exponent);
|
|
99
|
+
|
|
100
|
+
return cuda::std::make_tuple(scale, unscale);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// NVIDIA algorithm:
|
|
104
|
+
// unscale = 2 ** clamp (ceil(log2(amax/dmax)), -127, 127)
|
|
105
|
+
__device__ __host__ cuda::std::tuple<float, float> compute_scale_e8m0_NV(float amax, Types format) {
|
|
106
|
+
// TODO: currently this FP32 division uses RNE. When the exact result
|
|
107
|
+
// is just above a binade boundary, it will be rounded down, in which
|
|
108
|
+
// case this routine may return the floor(), not the ceil()!
|
|
109
|
+
//
|
|
110
|
+
// We can fix this by performing the fdiv using RU. On __device__,
|
|
111
|
+
// this can be accomplished by __fdiv_ru intrinsic. On __host__,
|
|
112
|
+
// we may have to use <fenv>.
|
|
113
|
+
|
|
114
|
+
float ratio = amax / get_format_max(format);
|
|
115
|
+
|
|
116
|
+
// scale_exponent = clamp(ceil(log2(ratio)), -127, 127)
|
|
117
|
+
// The following code assumes ratio is a positive, finite FP32 value.
|
|
118
|
+
union {
|
|
119
|
+
float f32;
|
|
120
|
+
uint32_t u32;
|
|
121
|
+
} ratio_bits;
|
|
122
|
+
|
|
123
|
+
ratio_bits.f32 = ratio;
|
|
124
|
+
|
|
125
|
+
uint32_t ratio_exponent_field = (ratio_bits.u32 >> 23) & 0xff;
|
|
126
|
+
uint32_t ratio_significand_field = ratio_bits.u32 & 0x7fffff;
|
|
127
|
+
int32_t unscale_exponent =
|
|
128
|
+
ratio_significand_field > 0 && ratio_exponent_field != 0xfe &&
|
|
129
|
+
!(ratio_exponent_field == 0 && ratio_significand_field <= 0x400000)
|
|
130
|
+
? static_cast<int32_t>(ratio_exponent_field) - 126
|
|
131
|
+
: static_cast<int32_t>(ratio_exponent_field) - 127;
|
|
132
|
+
|
|
133
|
+
float scale = ldexpf(1.f, -unscale_exponent);
|
|
134
|
+
float unscale = ldexpf(1.f, unscale_exponent);
|
|
135
|
+
|
|
136
|
+
return cuda::std::make_tuple(scale, unscale);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Compute scaling factor.
|
|
140
|
+
__device__ __host__ __inline__ cuda::std::tuple<float, float>
|
|
141
|
+
compute_scale(const float amax, const Types format, const Types scale_format) {
|
|
142
|
+
if (amax == 0 || isinf(amax) || isnan(amax)) {
|
|
143
|
+
return cuda::std::make_tuple(1.f, 1.f);
|
|
144
|
+
} else {
|
|
145
|
+
// intercept e8m0 specifically
|
|
146
|
+
if (scale_format == Types::E8M0) {
|
|
147
|
+
return compute_scale_e8m0_NV(amax, format);
|
|
148
|
+
}
|
|
149
|
+
// otherwise take the general path
|
|
150
|
+
const float emax = get_format_max(format);
|
|
151
|
+
double scale = emax / amax;
|
|
152
|
+
double inv_scale = convert_to_types(1. / scale, scale_format);
|
|
153
|
+
scale = 1. / inv_scale;
|
|
154
|
+
return cuda::std::make_tuple(scale, inv_scale);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
__device__ __host__ __inline__ cuda::std::tuple<float, float>
|
|
159
|
+
compute_scale_with_global(const float global_amax, const float local_amax, const Types format,
|
|
160
|
+
const Types scale_format) {
|
|
161
|
+
bool local_amax_invalid = local_amax == 0 || isinf(local_amax) || isnan(local_amax);
|
|
162
|
+
bool global_amax_invalid = global_amax == 0 || isinf(global_amax) || isnan(global_amax);
|
|
163
|
+
if (local_amax_invalid || global_amax_invalid) {
|
|
164
|
+
return cuda::std::make_tuple(1.f, 1.f);
|
|
165
|
+
} else {
|
|
166
|
+
const float elem_format_max = get_format_max(format);
|
|
167
|
+
const float scale_format_max = get_format_max(scale_format);
|
|
168
|
+
|
|
169
|
+
const float local_unscale = local_amax / elem_format_max;
|
|
170
|
+
// Note: if elem_format_max / global_amax > 1 and scale_format_max
|
|
171
|
+
// is close to FLT_MAX, we can overflow here
|
|
172
|
+
// WAR is to just do these few calculations in double.
|
|
173
|
+
const double two_level_scale =
|
|
174
|
+
static_cast<double>(scale_format_max) * (elem_format_max / global_amax);
|
|
175
|
+
|
|
176
|
+
const double local_unscale_q =
|
|
177
|
+
convert_to_types(static_cast<float>(local_unscale * two_level_scale), scale_format) /
|
|
178
|
+
two_level_scale;
|
|
179
|
+
const float scale = 1. / local_unscale_q;
|
|
180
|
+
|
|
181
|
+
return cuda::std::make_tuple(scale, static_cast<float>(local_unscale_q));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
}; // anonymous namespace
|
|
186
|
+
|
|
187
|
+
namespace {
|
|
188
|
+
|
|
189
|
+
template <int THREAD_X, int THREAD_Y = 4>
|
|
190
|
+
__device__ float compute_max_block(const float x, const int block_size,
|
|
191
|
+
const float clamp = FLT_MAX) {
|
|
192
|
+
float xabs = fabsf(x);
|
|
193
|
+
xabs = (xabs > clamp) ? clamp : xabs;
|
|
194
|
+
|
|
195
|
+
typedef cub::BlockReduce<float, THREAD_X> BlockReduce;
|
|
196
|
+
|
|
197
|
+
__shared__ typename BlockReduce::TempStorage temp_storage[THREAD_Y];
|
|
198
|
+
|
|
199
|
+
float amax = BlockReduce(temp_storage[threadIdx.y]).Reduce(xabs, [](float a, float b) {
|
|
200
|
+
return fmaxf(a, b);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
__shared__ float amax_smem[THREAD_Y];
|
|
204
|
+
if (threadIdx.x == 0)
|
|
205
|
+
amax_smem[threadIdx.y] = amax;
|
|
206
|
+
|
|
207
|
+
__syncthreads();
|
|
208
|
+
|
|
209
|
+
return amax_smem[threadIdx.y];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
template <int THREAD_Y>
|
|
213
|
+
__device__ float compute_max_warp(const float x, const int block_size,
|
|
214
|
+
const float clamp = FLT_MAX) {
|
|
215
|
+
float xabs = fabsf(x);
|
|
216
|
+
xabs = (xabs > clamp) ? clamp : xabs;
|
|
217
|
+
|
|
218
|
+
typedef cub::WarpReduce<float> WarpReduce;
|
|
219
|
+
__shared__ typename WarpReduce::TempStorage temp_storage[THREAD_Y];
|
|
220
|
+
|
|
221
|
+
float amax = WarpReduce(temp_storage[threadIdx.y]).Reduce(xabs, [](float a, float b) {
|
|
222
|
+
return fmaxf(a, b);
|
|
223
|
+
});
|
|
224
|
+
amax = __shfl_sync(0xffffffff, amax, 0);
|
|
225
|
+
return amax;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
template <int THREAD_X, int THREAD_Y>
|
|
229
|
+
__device__ float compute_max(const float x, const int block_size, const float clamp = FLT_MAX) {
|
|
230
|
+
if (THREAD_X == 32) {
|
|
231
|
+
return compute_max_warp<THREAD_Y>(x, block_size, clamp);
|
|
232
|
+
} else {
|
|
233
|
+
return compute_max_block<THREAD_X, THREAD_Y>(x, block_size, clamp);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
}; // namespace
|
|
238
|
+
|
|
239
|
+
template <typename T, typename T_y, int THREAD_X, int THREAD_Y>
|
|
240
|
+
__global__ void amax_and_convert_kernel(const T *x, T_y *y, const int64_t n, const int blocksize,
|
|
241
|
+
const int actual_cols, const int padded_cols, Types format,
|
|
242
|
+
Types scale_format, const float *global_amax = nullptr,
|
|
243
|
+
const bool per_channel_scaling = false,
|
|
244
|
+
const int ncols = -1) {
|
|
245
|
+
// map thread -> element
|
|
246
|
+
const uint64_t block_idx = blockIdx.x * blockDim.y + threadIdx.y;
|
|
247
|
+
const int thread_id = threadIdx.x;
|
|
248
|
+
const int warp_id = threadIdx.y;
|
|
249
|
+
|
|
250
|
+
// Unique id in the padded matrix
|
|
251
|
+
const int64_t idx = block_idx * blocksize + thread_id;
|
|
252
|
+
|
|
253
|
+
const int blocks_per_row = padded_cols / blocksize;
|
|
254
|
+
|
|
255
|
+
if (idx >= n)
|
|
256
|
+
return;
|
|
257
|
+
|
|
258
|
+
// bool output_scaled = (block_unscale_ptr != nullptr);
|
|
259
|
+
|
|
260
|
+
float scale = 1.f, unscale = 1.f;
|
|
261
|
+
|
|
262
|
+
// row and col are in terms of the "padded" size that we launched based off
|
|
263
|
+
const int row = block_idx / blocks_per_row;
|
|
264
|
+
const int block_in_row = block_idx % blocks_per_row;
|
|
265
|
+
const int col = block_in_row * blocksize + thread_id;
|
|
266
|
+
// Differentiate between real and padded elements
|
|
267
|
+
const bool in_padding = col >= actual_cols;
|
|
268
|
+
|
|
269
|
+
// map threads to the actual memory locations
|
|
270
|
+
// Example: x = [2, 17], bs=16
|
|
271
|
+
// thread @ 0, 0 = 0
|
|
272
|
+
// thread @ 0, 15 = 15
|
|
273
|
+
// thread @ 1, 0 = 17
|
|
274
|
+
const size_t real_idx = row * actual_cols + col;
|
|
275
|
+
|
|
276
|
+
// read either real or padded (zero) value
|
|
277
|
+
float thread_val = (in_padding) ? 0.f : static_cast<float>(x[real_idx]);
|
|
278
|
+
float block_amax = compute_max<THREAD_X, THREAD_Y>(thread_val, blocksize);
|
|
279
|
+
|
|
280
|
+
if (global_amax) {
|
|
281
|
+
int global_idx = (per_channel_scaling) ? idx / ncols : 0;
|
|
282
|
+
float global_amax_val = global_amax[global_idx];
|
|
283
|
+
cuda::std::tie(scale, unscale) =
|
|
284
|
+
compute_scale_with_global(global_amax_val, block_amax, format, scale_format);
|
|
285
|
+
} else {
|
|
286
|
+
cuda::std::tie(scale, unscale) = compute_scale(block_amax, format, scale_format);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// if thread isn't handling a real value, nothing to output.
|
|
290
|
+
if (in_padding)
|
|
291
|
+
return;
|
|
292
|
+
|
|
293
|
+
y[real_idx] = quantize(thread_val, scale, unscale, format);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
std::tuple<float *, bool> get_global_scaling(at::Tensor x, std::optional<at::Tensor> global_amax) {
|
|
297
|
+
float *global_amax_ptr =
|
|
298
|
+
global_amax.has_value() ? global_amax.value().data_ptr<float>() : nullptr;
|
|
299
|
+
|
|
300
|
+
// if we need per-channel scaling, following must be true:
|
|
301
|
+
// 1) 2d input tensor
|
|
302
|
+
// 2) 1d blocksize
|
|
303
|
+
// 3) # global_amax elements == # rows of collapsed matrix
|
|
304
|
+
bool per_channel_scaling = false;
|
|
305
|
+
int cols = x.size(-1);
|
|
306
|
+
if (global_amax_ptr) {
|
|
307
|
+
per_channel_scaling = (x.dim() == 2) && (global_amax.value().numel() == x.size(0));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return std::make_tuple(global_amax_ptr, per_channel_scaling);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
using output_t = std::tuple<at::Tensor, std::optional<at::Tensor>>;
|
|
314
|
+
|
|
315
|
+
#define DISPATCH_FUSED_AMAX_KERNEL(T, TX, TY) \
|
|
316
|
+
amax_and_convert_kernel<scalar_t, T, TX, TY> \
|
|
317
|
+
<<<blocks, block, 0, c10::cuda::getCurrentCUDAStream()>>>( \
|
|
318
|
+
x.data_ptr<scalar_t>(), y.data_ptr<T>(), n, blocksize, actual_cols, padded_cols, format, \
|
|
319
|
+
scale_format, global_amax_ptr, per_channel_scaling, x.size(-1))
|
|
320
|
+
|
|
321
|
+
#define DISPATCH_SINGLE_TYPE(T) \
|
|
322
|
+
if (blocksize == 8) { \
|
|
323
|
+
DISPATCH_FUSED_AMAX_KERNEL(T, 8, blocks_per_cta); \
|
|
324
|
+
} else if (blocksize == 16) { \
|
|
325
|
+
DISPATCH_FUSED_AMAX_KERNEL(T, 16, blocks_per_cta); \
|
|
326
|
+
} else if (blocksize == 32) { \
|
|
327
|
+
DISPATCH_FUSED_AMAX_KERNEL(T, 32, blocks_per_cta); \
|
|
328
|
+
} else { \
|
|
329
|
+
throw std::invalid_argument("Blocksize for fused call must be one of {8, 16, 32}"); \
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
#define DISPATCH_FLOAT_AND_HALF_AND_BFLOAT(TYPE, NAME, ...) \
|
|
333
|
+
switch (TYPE) { \
|
|
334
|
+
case at::ScalarType::Float: { \
|
|
335
|
+
using scalar_t = float; \
|
|
336
|
+
__VA_ARGS__; \
|
|
337
|
+
break; \
|
|
338
|
+
} \
|
|
339
|
+
case at::ScalarType::Half: { \
|
|
340
|
+
using scalar_t = at::Half; \
|
|
341
|
+
__VA_ARGS__; \
|
|
342
|
+
break; \
|
|
343
|
+
} \
|
|
344
|
+
case at::ScalarType::BFloat16: { \
|
|
345
|
+
using scalar_t = at::BFloat16; \
|
|
346
|
+
__VA_ARGS__; \
|
|
347
|
+
break; \
|
|
348
|
+
} \
|
|
349
|
+
default: \
|
|
350
|
+
AT_ERROR(#NAME, " not implemented for '", toString(TYPE), "'"); \
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
int pad_dim_to_blocksize(const int dim, const int bs) { return dim + (bs - (dim % bs)); }
|
|
354
|
+
|
|
355
|
+
at::Tensor fused_amax_convert(at::Tensor x, const int blocksize, Types format, Types scale_format,
|
|
356
|
+
std::optional<at::Tensor> global_amax) {
|
|
357
|
+
std::optional<at::Tensor> global_amax_float = std::nullopt;
|
|
358
|
+
|
|
359
|
+
if (global_amax.has_value()) {
|
|
360
|
+
const at::Tensor &_global_amax = *global_amax;
|
|
361
|
+
global_amax_float = at::_cast_Float(_global_amax);
|
|
362
|
+
}
|
|
363
|
+
// const bool native_mode = is_native(output_mode);
|
|
364
|
+
auto y_options = x.options();
|
|
365
|
+
|
|
366
|
+
at::Tensor y = at::empty_like(x, y_options);
|
|
367
|
+
|
|
368
|
+
size_t n = x.numel();
|
|
369
|
+
int ndim = x.dim();
|
|
370
|
+
// Handle partial blocks by fake-padding to full blocks
|
|
371
|
+
const int actual_cols = x.size(-1);
|
|
372
|
+
const int padded_cols = pad_dim_to_blocksize(actual_cols, blocksize);
|
|
373
|
+
// pad the total size, replace the final dimension with padded one
|
|
374
|
+
n = n / actual_cols * padded_cols;
|
|
375
|
+
|
|
376
|
+
const int blocks_per_cta = 4;
|
|
377
|
+
|
|
378
|
+
const dim3 block(blocksize, blocks_per_cta);
|
|
379
|
+
const int blocks = ceil_div(n, blocksize * blocks_per_cta);
|
|
380
|
+
|
|
381
|
+
auto [global_amax_ptr, per_channel_scaling] = get_global_scaling(x, global_amax_float);
|
|
382
|
+
|
|
383
|
+
DISPATCH_FLOAT_AND_HALF_AND_BFLOAT(x.scalar_type(), "fused_amax_convert_kernel",
|
|
384
|
+
{ DISPATCH_SINGLE_TYPE(scalar_t); });
|
|
385
|
+
|
|
386
|
+
return y;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
#undef DISPATCH_FUSED_AMAX_KERNEL
|
|
390
|
+
#undef DISPATCH_SINGLE_TYPE
|
|
391
|
+
#undef DISPATCH_FLOAT_AND_HALF_AND_BFLOAT
|
|
392
|
+
|
|
393
|
+
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|
394
|
+
m.def("fused_amax_convert", &fused_amax_convert,
|
|
395
|
+
"Compute block amax and quantize the tensor to mx formats", py::arg("inputs"),
|
|
396
|
+
py::arg("block_size"), py::arg("format"), py::arg("scale_format"),
|
|
397
|
+
py::arg("global_amax") = py::none());
|
|
398
|
+
m.def("convert_to_exmy", &convert_to_types, "Convert value to exmy format.", py::arg("x"),
|
|
399
|
+
py::arg("format"));
|
|
400
|
+
py::enum_<Types>(m, "Types")
|
|
401
|
+
.value("E4M3", Types::E4M3)
|
|
402
|
+
.value("E5M2", Types::E5M2)
|
|
403
|
+
.value("INT8", Types::INT8)
|
|
404
|
+
.value("E0M3", Types::E0M3)
|
|
405
|
+
.value("E1M2", Types::E1M2)
|
|
406
|
+
.value("E3M0", Types::E3M0)
|
|
407
|
+
.value("E2M1", Types::E2M1)
|
|
408
|
+
.value("E3M2", Types::E3M2)
|
|
409
|
+
.value("E2M3", Types::E2M3)
|
|
410
|
+
.value("E8M0", Types::E8M0);
|
|
411
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
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
|
+
#pragma once
|
|
19
|
+
|
|
20
|
+
#ifndef CUDA_HOST_DEVICE
|
|
21
|
+
#ifdef __CUDA_ARCH__
|
|
22
|
+
#define CUDA_HOST_DEVICE __host__ __device__ __forceinline__
|
|
23
|
+
#define MODELOPT_FORMAT_FAIL(str) __trap();
|
|
24
|
+
#else
|
|
25
|
+
#define CUDA_HOST_DEVICE inline
|
|
26
|
+
#define MODELOPT_FORMAT_FAIL(str) throw std::runtime_error(str);
|
|
27
|
+
#endif
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#ifdef __CUDA_ARCH__
|
|
31
|
+
#define CONSTANT __constant__
|
|
32
|
+
#else
|
|
33
|
+
#define CONSTANT static
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
#include <cuda_fp8.h>
|
|
37
|
+
#include <float.h>
|
|
38
|
+
|
|
39
|
+
enum class Types { E4M3, E5M2, INT8, E0M3, E1M2, E3M0, E2M1, E3M2, E2M3, E8M0 };
|
|
40
|
+
|
|
41
|
+
// FP4
|
|
42
|
+
CONSTANT float e2m1_table_values[8] = {0, 0.5, 1, 1.5, 2, 3, 4, 6};
|
|
43
|
+
CONSTANT float e2m1_table_bounds[7] = {0.25, 0.75, 1.25, 1.75, 2.5, 3.5, 5};
|
|
44
|
+
|
|
45
|
+
CONSTANT float e1m2_table_values[8] = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5};
|
|
46
|
+
CONSTANT float e1m2_table_bounds[7] = {0.25, 0.75, 1.25, 1.75, 2.25, 2.75, 3.25};
|
|
47
|
+
|
|
48
|
+
CONSTANT float e0m3_table_values[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
|
49
|
+
CONSTANT float e0m3_table_bounds[7] = {0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5};
|
|
50
|
+
|
|
51
|
+
CONSTANT float e3m0_table_values[8] = {0, 0.25, 0.5, 1, 2, 4, 8, 16};
|
|
52
|
+
CONSTANT float e3m0_table_bounds[7] = {0.125, 0.375, 0.75, 1.5, 3, 6, 12};
|
|
53
|
+
|
|
54
|
+
// FP6
|
|
55
|
+
CONSTANT float e3m2_table_values[32] = {0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375,
|
|
56
|
+
0.5, 0.625, 0.75, 0.875, 1, 1.25, 1.5, 1.75,
|
|
57
|
+
2, 2.5, 3, 3.5, 4, 5, 6, 7,
|
|
58
|
+
8, 10, 12, 14, 16, 20, 24, 28};
|
|
59
|
+
CONSTANT float e3m2_table_bounds[31] = {
|
|
60
|
+
0.03125, 0.09375, 0.15625, 0.21875, 0.28125, 0.34375, 0.40625, 0.46875, 0.5625, 0.6875, 0.8125,
|
|
61
|
+
0.9375, 1.125, 1.375, 1.625, 1.875, 2.25, 2.75, 3.25, 3.75, 4.5, 5.5,
|
|
62
|
+
6.5, 7.5, 9, 11, 13, 15, 18, 22, 26};
|
|
63
|
+
|
|
64
|
+
CONSTANT float e2m3_table_values[32] = {
|
|
65
|
+
0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875,
|
|
66
|
+
2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5};
|
|
67
|
+
CONSTANT float e2m3_table_bounds[31] = {
|
|
68
|
+
0.0625, 0.1875, 0.3125, 0.4375, 0.5625, 0.6875, 0.8125, 0.9375, 1.0625, 1.1875, 1.3125,
|
|
69
|
+
1.4375, 1.5625, 1.6875, 1.8125, 1.9375, 2.125, 2.375, 2.625, 2.875, 3.125, 3.375,
|
|
70
|
+
3.625, 3.875, 4.25, 4.75, 5.25, 5.75, 6.25, 6.75, 7.25};
|
|
71
|
+
|
|
72
|
+
CUDA_HOST_DEVICE float convert_to_fp8_e4m3(const float x) {
|
|
73
|
+
return static_cast<float>(static_cast<__nv_fp8_e4m3>(static_cast<float>(x)));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
CUDA_HOST_DEVICE float convert_to_fp8_e5m2(const float x) {
|
|
77
|
+
return static_cast<float>(static_cast<__nv_fp8_e5m2>(static_cast<float>(x)));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
CUDA_HOST_DEVICE float convert_int8_saturating(const float x) {
|
|
81
|
+
// Regular conversion w/rounding
|
|
82
|
+
int converted = std::rint(x);
|
|
83
|
+
|
|
84
|
+
// saturate high & low
|
|
85
|
+
converted = std::clamp(converted, (int)(-INT8_MAX), (int)(INT8_MAX));
|
|
86
|
+
|
|
87
|
+
// do the actual conversion.
|
|
88
|
+
return static_cast<int8_t>(converted);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// // Rounding function. Round to nearest, ties away from zero.
|
|
92
|
+
CUDA_HOST_DEVICE float round_away_from_zero(float x, const float *values, const float *bounds,
|
|
93
|
+
int n) {
|
|
94
|
+
// Within current bounds.
|
|
95
|
+
for (int i = 0; i < n - 1; i++) {
|
|
96
|
+
if (x < bounds[i])
|
|
97
|
+
return values[i];
|
|
98
|
+
}
|
|
99
|
+
// Max bounds.
|
|
100
|
+
return values[n - 1];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Rounding function. Round to nearest, ties to even
|
|
104
|
+
CUDA_HOST_DEVICE float round_to_even(float x, const float *values, const float *bounds, int n) {
|
|
105
|
+
// Within current bounds.
|
|
106
|
+
for (int i = 0; i < n - 1; i++) {
|
|
107
|
+
// If less than tie, round down
|
|
108
|
+
if (x < bounds[i])
|
|
109
|
+
return values[i];
|
|
110
|
+
// If equals to tie, round to representable value that has 0 in lsb of the mantissa
|
|
111
|
+
if (x == bounds[i]) {
|
|
112
|
+
// Since lsb alternates between 0 and 1, we can round down
|
|
113
|
+
// if the index is even, and round up if the index is odd
|
|
114
|
+
if (i % 2 == 0)
|
|
115
|
+
return values[i];
|
|
116
|
+
else
|
|
117
|
+
return values[i + 1];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Max bounds.
|
|
121
|
+
return values[n - 1];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
CUDA_HOST_DEVICE float convert_to_table_types(float x, const int n, const float *values,
|
|
125
|
+
const float *bounds) {
|
|
126
|
+
float sign;
|
|
127
|
+
if (x < 0.f) {
|
|
128
|
+
sign = -1.f;
|
|
129
|
+
x = -x;
|
|
130
|
+
} else {
|
|
131
|
+
sign = 1.f;
|
|
132
|
+
}
|
|
133
|
+
// Saturate infs and nans.
|
|
134
|
+
if (isinf(x) || isnan(x))
|
|
135
|
+
return sign * values[n - 1];
|
|
136
|
+
|
|
137
|
+
// Round.
|
|
138
|
+
float value = round_to_even(x, values, bounds, n);
|
|
139
|
+
|
|
140
|
+
return value * sign;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
CUDA_HOST_DEVICE float convert_to_e3m0(float x, const int n, const float *values,
|
|
144
|
+
const float *bounds) {
|
|
145
|
+
float sign;
|
|
146
|
+
if (x < 0.f) {
|
|
147
|
+
sign = -1.f;
|
|
148
|
+
x = -x;
|
|
149
|
+
} else {
|
|
150
|
+
sign = 1.f;
|
|
151
|
+
}
|
|
152
|
+
// Encoding table for 4-bit formats.
|
|
153
|
+
// Saturate infs and nans.
|
|
154
|
+
if (isinf(x) || isnan(x))
|
|
155
|
+
return sign * values[n - 1];
|
|
156
|
+
|
|
157
|
+
// Round.
|
|
158
|
+
float value = round_away_from_zero(x, values, bounds, n);
|
|
159
|
+
|
|
160
|
+
return value * sign;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
CUDA_HOST_DEVICE float convert_to_types(const float x, const Types format) {
|
|
164
|
+
switch (format) {
|
|
165
|
+
case Types::E4M3:
|
|
166
|
+
return convert_to_fp8_e4m3(x);
|
|
167
|
+
case Types::E5M2:
|
|
168
|
+
return convert_to_fp8_e5m2(x);
|
|
169
|
+
case Types::INT8:
|
|
170
|
+
return convert_int8_saturating(x);
|
|
171
|
+
case Types::E2M1:
|
|
172
|
+
return convert_to_table_types(x, 8, e2m1_table_values, e2m1_table_bounds);
|
|
173
|
+
case Types::E0M3:
|
|
174
|
+
return convert_to_table_types(x, 8, e0m3_table_values, e0m3_table_bounds);
|
|
175
|
+
case Types::E1M2:
|
|
176
|
+
return convert_to_table_types(x, 8, e1m2_table_values, e1m2_table_bounds);
|
|
177
|
+
case Types::E3M0:
|
|
178
|
+
return convert_to_e3m0(x, 8, e3m0_table_values, e3m0_table_bounds);
|
|
179
|
+
case Types::E3M2:
|
|
180
|
+
return convert_to_table_types(x, 32, e3m2_table_values, e3m2_table_bounds);
|
|
181
|
+
case Types::E2M3:
|
|
182
|
+
return convert_to_table_types(x, 32, e2m3_table_values, e2m3_table_bounds);
|
|
183
|
+
default:
|
|
184
|
+
return 0.f;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
CUDA_HOST_DEVICE
|
|
189
|
+
float get_format_max(const Types format) {
|
|
190
|
+
switch (format) {
|
|
191
|
+
case Types::E4M3:
|
|
192
|
+
return 448.f;
|
|
193
|
+
case Types::E5M2:
|
|
194
|
+
return 57344.f;
|
|
195
|
+
case Types::INT8:
|
|
196
|
+
return 127.f;
|
|
197
|
+
case Types::E2M1:
|
|
198
|
+
return 6.f;
|
|
199
|
+
case Types::E0M3:
|
|
200
|
+
return 7.f;
|
|
201
|
+
case Types::E3M0:
|
|
202
|
+
return 16.f;
|
|
203
|
+
case Types::E1M2:
|
|
204
|
+
return 3.5f;
|
|
205
|
+
case Types::E3M2:
|
|
206
|
+
return 28.f;
|
|
207
|
+
case Types::E2M3:
|
|
208
|
+
return 7.5f;
|
|
209
|
+
default:
|
|
210
|
+
// error
|
|
211
|
+
return 0.f;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Returns the exponent of the maximum power-of-two representable in the given format.
|
|
216
|
+
__host__ __device__ __inline__ int get_format_lg2_max(Types format) {
|
|
217
|
+
switch (format) {
|
|
218
|
+
case Types::E5M2:
|
|
219
|
+
return 15;
|
|
220
|
+
case Types::E4M3:
|
|
221
|
+
return 8;
|
|
222
|
+
case Types::E3M2:
|
|
223
|
+
case Types::E3M0:
|
|
224
|
+
return 4;
|
|
225
|
+
case Types::E2M3:
|
|
226
|
+
case Types::E2M1:
|
|
227
|
+
return 2;
|
|
228
|
+
case Types::E1M2:
|
|
229
|
+
return 1;
|
|
230
|
+
case Types::E0M3:
|
|
231
|
+
return 2;
|
|
232
|
+
case Types::INT8:
|
|
233
|
+
// This follows the psx-encodings definition of "INT8",
|
|
234
|
+
// which are the 8-bit two's complement integers, symmetrized
|
|
235
|
+
// by removing -128.
|
|
236
|
+
//
|
|
237
|
+
// In the context of OCP MX-formats, "INT8" refers to a
|
|
238
|
+
// symmetrized Q1.6 type. In that case, this function
|
|
239
|
+
// should return 0.
|
|
240
|
+
return 6;
|
|
241
|
+
default:
|
|
242
|
+
MODELOPT_FORMAT_FAIL("Unsupported format for E8M0 scaling");
|
|
243
|
+
}
|
|
244
|
+
return -1;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
inline int ceil_div(const int a, const int b) { return (a + b - 1) / b; }
|