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,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; }