nvmath-python 0.5.0__cp313-cp313-win_amd64.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 (174) hide show
  1. nvmath/__init__.pxd +0 -0
  2. nvmath/__init__.py +37 -0
  3. nvmath/_internal/__init__.py +0 -0
  4. nvmath/_internal/layout.py +58 -0
  5. nvmath/_utils.py +363 -0
  6. nvmath/bindings/__init__.pxd +0 -0
  7. nvmath/bindings/__init__.py +44 -0
  8. nvmath/bindings/_internal/__init__.pxd +0 -0
  9. nvmath/bindings/_internal/__init__.py +0 -0
  10. nvmath/bindings/_internal/cublas.cp313-win_amd64.pyd +0 -0
  11. nvmath/bindings/_internal/cublas.pxd +518 -0
  12. nvmath/bindings/_internal/cublasLt.cp313-win_amd64.pyd +0 -0
  13. nvmath/bindings/_internal/cublasLt.pxd +54 -0
  14. nvmath/bindings/_internal/cudss.cp313-win_amd64.pyd +0 -0
  15. nvmath/bindings/_internal/cudss.pxd +44 -0
  16. nvmath/bindings/_internal/cufft.cp313-win_amd64.pyd +0 -0
  17. nvmath/bindings/_internal/cufft.pxd +69 -0
  18. nvmath/bindings/_internal/cufftMp.pxd +77 -0
  19. nvmath/bindings/_internal/curand.cp313-win_amd64.pyd +0 -0
  20. nvmath/bindings/_internal/curand.pxd +42 -0
  21. nvmath/bindings/_internal/cusolver.cp313-win_amd64.pyd +0 -0
  22. nvmath/bindings/_internal/cusolver.pxd +15 -0
  23. nvmath/bindings/_internal/cusolverDn.cp313-win_amd64.pyd +0 -0
  24. nvmath/bindings/_internal/cusolverDn.pxd +386 -0
  25. nvmath/bindings/_internal/cusparse.cp313-win_amd64.pyd +0 -0
  26. nvmath/bindings/_internal/cusparse.pxd +270 -0
  27. nvmath/bindings/_internal/mathdx.cp313-win_amd64.pyd +0 -0
  28. nvmath/bindings/_internal/mathdx.pxd +79 -0
  29. nvmath/bindings/_internal/nvshmem.pxd +29 -0
  30. nvmath/bindings/_internal/utils.cp313-win_amd64.pyd +0 -0
  31. nvmath/bindings/_internal/utils.pxd +186 -0
  32. nvmath/bindings/cublas.cp313-win_amd64.pyd +0 -0
  33. nvmath/bindings/cublas.pxd +545 -0
  34. nvmath/bindings/cublas.pyi +18 -0
  35. nvmath/bindings/cublasLt.cp313-win_amd64.pyd +0 -0
  36. nvmath/bindings/cublasLt.pxd +99 -0
  37. nvmath/bindings/cudss.cp313-win_amd64.pyd +0 -0
  38. nvmath/bindings/cudss.pxd +83 -0
  39. nvmath/bindings/cudss.pyi +249 -0
  40. nvmath/bindings/cufft.cp313-win_amd64.pyd +0 -0
  41. nvmath/bindings/cufft.pxd +114 -0
  42. nvmath/bindings/cufftMp.pxd +124 -0
  43. nvmath/bindings/curand.cp313-win_amd64.pyd +0 -0
  44. nvmath/bindings/curand.pxd +71 -0
  45. nvmath/bindings/cusolver.cp313-win_amd64.pyd +0 -0
  46. nvmath/bindings/cusolver.pxd +60 -0
  47. nvmath/bindings/cusolverDn.cp313-win_amd64.pyd +0 -0
  48. nvmath/bindings/cusolverDn.pxd +410 -0
  49. nvmath/bindings/cusparse.cp313-win_amd64.pyd +0 -0
  50. nvmath/bindings/cusparse.pxd +329 -0
  51. nvmath/bindings/cycublas.cp313-win_amd64.pyd +0 -0
  52. nvmath/bindings/cycublas.pxd +657 -0
  53. nvmath/bindings/cycublasLt.cp313-win_amd64.pyd +0 -0
  54. nvmath/bindings/cycublasLt.pxd +1010 -0
  55. nvmath/bindings/cycudss.cp313-win_amd64.pyd +0 -0
  56. nvmath/bindings/cycudss.pxd +191 -0
  57. nvmath/bindings/cycufft.cp313-win_amd64.pyd +0 -0
  58. nvmath/bindings/cycufft.pxd +320 -0
  59. nvmath/bindings/cycufftMp.pxd +333 -0
  60. nvmath/bindings/cycurand.cp313-win_amd64.pyd +0 -0
  61. nvmath/bindings/cycurand.pxd +146 -0
  62. nvmath/bindings/cycusolver.cp313-win_amd64.pyd +0 -0
  63. nvmath/bindings/cycusolver.pxd +143 -0
  64. nvmath/bindings/cycusolverDn.cp313-win_amd64.pyd +0 -0
  65. nvmath/bindings/cycusolverDn.pxd +414 -0
  66. nvmath/bindings/cycusparse.cp313-win_amd64.pyd +0 -0
  67. nvmath/bindings/cycusparse.pxd +476 -0
  68. nvmath/bindings/cymathdx.cp313-win_amd64.pyd +0 -0
  69. nvmath/bindings/cymathdx.pxd +363 -0
  70. nvmath/bindings/cynvshmem.pxd +126 -0
  71. nvmath/bindings/mathdx.cp313-win_amd64.pyd +0 -0
  72. nvmath/bindings/mathdx.pxd +131 -0
  73. nvmath/bindings/mathdx.pyi +686 -0
  74. nvmath/bindings/nvpl/__init__.pxd +0 -0
  75. nvmath/bindings/nvpl/__init__.py +11 -0
  76. nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
  77. nvmath/bindings/nvpl/_internal/__init__.py +0 -0
  78. nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
  79. nvmath/bindings/nvpl/cyfft.pxd +87 -0
  80. nvmath/bindings/nvpl/fft.pxd +100 -0
  81. nvmath/bindings/nvshmem.pxd +54 -0
  82. nvmath/device/__init__.py +23 -0
  83. nvmath/device/_deprecated.py +33 -0
  84. nvmath/device/caching.py +51 -0
  85. nvmath/device/common.py +131 -0
  86. nvmath/device/common_backend.py +125 -0
  87. nvmath/device/common_cuda.py +156 -0
  88. nvmath/device/common_mathdx.py +97 -0
  89. nvmath/device/common_numba.py +159 -0
  90. nvmath/device/common_opaque_tensor.py +128 -0
  91. nvmath/device/cublasdx.py +1085 -0
  92. nvmath/device/cublasdx_backend.py +552 -0
  93. nvmath/device/cublasdx_numba.py +528 -0
  94. nvmath/device/cufftdx.py +551 -0
  95. nvmath/device/cufftdx_backend.py +194 -0
  96. nvmath/device/cufftdx_numba.py +123 -0
  97. nvmath/device/curand_kernel.py +9147 -0
  98. nvmath/device/nvrtc.py +95 -0
  99. nvmath/device/patch.py +35 -0
  100. nvmath/device/random.py +417 -0
  101. nvmath/device/random_helpers.py +23 -0
  102. nvmath/device/random_states.py +189 -0
  103. nvmath/device/types.py +11 -0
  104. nvmath/device/vector_types_numba.py +203 -0
  105. nvmath/distributed/__init__.py +117 -0
  106. nvmath/distributed/_internal/__init__.py +0 -0
  107. nvmath/distributed/_internal/nvshmem.py +243 -0
  108. nvmath/distributed/_internal/tensor_ifc_cupy.py +111 -0
  109. nvmath/distributed/_internal/tensor_ifc_numpy.py +53 -0
  110. nvmath/distributed/_internal/tensor_ifc_torch.py +108 -0
  111. nvmath/distributed/_internal/tensor_wrapper.py +59 -0
  112. nvmath/distributed/_utils.py +152 -0
  113. nvmath/distributed/fft/__init__.py +6 -0
  114. nvmath/distributed/fft/_configuration.py +86 -0
  115. nvmath/distributed/fft/fft.py +1737 -0
  116. nvmath/distributed/reshape/__init__.py +6 -0
  117. nvmath/distributed/reshape/_configuration.py +39 -0
  118. nvmath/distributed/reshape/reshape.py +1249 -0
  119. nvmath/fft/__init__.py +7 -0
  120. nvmath/fft/_configuration.py +208 -0
  121. nvmath/fft/_exec_utils.py +116 -0
  122. nvmath/fft/_helpers.py +260 -0
  123. nvmath/fft/fft.py +2346 -0
  124. nvmath/internal/__init__.py +5 -0
  125. nvmath/internal/enum_utils.py +142 -0
  126. nvmath/internal/formatters.py +87 -0
  127. nvmath/internal/mem_limit.py +51 -0
  128. nvmath/internal/package_ifc.py +119 -0
  129. nvmath/internal/package_ifc_cuda.py +43 -0
  130. nvmath/internal/package_ifc_cupy.py +49 -0
  131. nvmath/internal/package_ifc_torch.py +31 -0
  132. nvmath/internal/package_wrapper.py +14 -0
  133. nvmath/internal/tensor_ifc.py +143 -0
  134. nvmath/internal/tensor_ifc_cupy.py +185 -0
  135. nvmath/internal/tensor_ifc_numpy.py +157 -0
  136. nvmath/internal/tensor_ifc_torch.py +115 -0
  137. nvmath/internal/tensor_wrapper.py +160 -0
  138. nvmath/internal/typemaps.py +154 -0
  139. nvmath/internal/utils.py +634 -0
  140. nvmath/linalg/__init__.py +11 -0
  141. nvmath/linalg/_internal/__init__.py +3 -0
  142. nvmath/linalg/_internal/algo_cap_ifc.py +86 -0
  143. nvmath/linalg/_internal/algo_config_ifc.py +87 -0
  144. nvmath/linalg/_internal/enum_to_tuples.py +64 -0
  145. nvmath/linalg/_internal/epilog_protocol.py +738 -0
  146. nvmath/linalg/_internal/matmul_desc_ifc.py +72 -0
  147. nvmath/linalg/_internal/matmul_pref_ifc.py +65 -0
  148. nvmath/linalg/_internal/matrix_layout_ifc.py +59 -0
  149. nvmath/linalg/_internal/typemaps.py +135 -0
  150. nvmath/linalg/_internal/utils.py +96 -0
  151. nvmath/linalg/advanced/__init__.py +8 -0
  152. nvmath/linalg/advanced/_algorithmmod.py +142 -0
  153. nvmath/linalg/advanced/_configuration.py +320 -0
  154. nvmath/linalg/advanced/helpers/__init__.py +5 -0
  155. nvmath/linalg/advanced/helpers/matmul.py +173 -0
  156. nvmath/linalg/advanced/matmulmod.py +2855 -0
  157. nvmath/memory.py +266 -0
  158. nvmath/sparse/__init__.py +18 -0
  159. nvmath/sparse/_internal/__init__.py +21 -0
  160. nvmath/sparse/_internal/common_utils.py +81 -0
  161. nvmath/sparse/_internal/cudss_config_ifc.py +584 -0
  162. nvmath/sparse/_internal/cudss_data_ifc.py +291 -0
  163. nvmath/sparse/_internal/cudss_utils.py +398 -0
  164. nvmath/sparse/_internal/sparse_csr_ifc.py +154 -0
  165. nvmath/sparse/_internal/sparse_format_helpers.py +88 -0
  166. nvmath/sparse/_internal/sparse_tensor_ifc.py +80 -0
  167. nvmath/sparse/advanced/__init__.py +7 -0
  168. nvmath/sparse/advanced/_configuration.py +150 -0
  169. nvmath/sparse/advanced/direct_solver.py +1705 -0
  170. nvmath_python-0.5.0.dist-info/METADATA +122 -0
  171. nvmath_python-0.5.0.dist-info/RECORD +174 -0
  172. nvmath_python-0.5.0.dist-info/WHEEL +5 -0
  173. nvmath_python-0.5.0.dist-info/licenses/LICENSE +177 -0
  174. nvmath_python-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,738 @@
1
+ # Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ """Internal interface for epilog input handling."""
6
+
7
+ __all__ = [
8
+ "EPILOG_INPUT_HANDLERS_MAP",
9
+ "EPILOG_OUTPUT_HANDLERS_MAP",
10
+ "BiasHandler",
11
+ "BgradHandler",
12
+ "ReluAuxHandler",
13
+ "DReluAuxHandler",
14
+ "GeluAuxHandler",
15
+ "DGeluAuxHandler",
16
+ "EpilogInputHandler",
17
+ "EpilogOutputHandler",
18
+ ]
19
+
20
+ from abc import abstractmethod
21
+ import math
22
+ from typing import Protocol, runtime_checkable
23
+
24
+ from nvmath.bindings import cublasLt as cublaslt
25
+ from nvmath.internal import typemaps
26
+ from nvmath.linalg._internal.utils import axis_order_in_memory, calculate_strides, check_batch_tileable
27
+
28
+ Epilog = cublaslt.Epilogue
29
+
30
+
31
+ @runtime_checkable
32
+ class EpilogInputHandler(Protocol):
33
+ """
34
+ Protocol for epilog handler input validation and setting the appropriate MM descriptor
35
+ attributes.
36
+ """
37
+
38
+ @abstractmethod
39
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
40
+ raise NotImplementedError
41
+
42
+ @property
43
+ @abstractmethod
44
+ def name(self):
45
+ """
46
+ The name of the epilog input that is handled (bias, ...).
47
+ """
48
+ raise NotImplementedError
49
+
50
+ @property
51
+ @abstractmethod
52
+ def order(self):
53
+ """
54
+ The result order that is needed by this epilog (cublaslt.Order or None, if no
55
+ restriction on order).
56
+ """
57
+ raise NotImplementedError
58
+
59
+ @abstractmethod
60
+ def validate(self, epilog_input):
61
+ """
62
+ Validate the provided epilog input.
63
+
64
+ Args:
65
+ epilog_input: The epilog input to validate.
66
+
67
+ """
68
+ raise NotImplementedError
69
+
70
+ @abstractmethod
71
+ def update(self, mm_desc_ifc, epilog_input):
72
+ """
73
+ Update the provided epilog input.
74
+
75
+ Args:
76
+ mm_desc_ifc: The MM descriptor to update, provided as a MatmulDescInterface
77
+ object. epilog_input: The epilog input to validate.
78
+
79
+ """
80
+ raise NotImplementedError
81
+
82
+
83
+ @runtime_checkable
84
+ class EpilogOutputHandler(Protocol):
85
+ """
86
+ Protocol for epilog handler output validation and setting the appropriate MM descriptor
87
+ attributes.
88
+ """
89
+
90
+ @abstractmethod
91
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
92
+ raise NotImplementedError
93
+
94
+ @property
95
+ @abstractmethod
96
+ def name(self):
97
+ """
98
+ The name of the epilog output that is handled (relu_aux, gelu_aux, bgrad, bragda,
99
+ bgradb, ...).
100
+ """
101
+ raise NotImplementedError
102
+
103
+ @property
104
+ @abstractmethod
105
+ def order(self):
106
+ """
107
+ The result order that is needed by this epilog (cublaslt.Order or None, if no
108
+ restriction on order).
109
+ """
110
+ raise NotImplementedError
111
+
112
+ @abstractmethod
113
+ def attributes(self):
114
+ """
115
+ The shape, stride, and dtype name of the output tensor.
116
+ """
117
+ raise NotImplementedError
118
+
119
+ @abstractmethod
120
+ def update(self, mm_desc_ifc):
121
+ """
122
+ Update all the attributes for this epilog, except the pointer.
123
+
124
+ Args:
125
+ mm_desc_ifc: The MM descriptor to update, provided as a MatmulDescInterface
126
+ object.
127
+ """
128
+ raise NotImplementedError
129
+
130
+ @abstractmethod
131
+ def update_ptr(self, mm_desc_ifc, ptr):
132
+ """
133
+ Set the pointer for this epilog.
134
+
135
+ Args:
136
+ mm_desc_ifc: The MM descriptor to update, provided as a MatmulDescInterface
137
+ object.
138
+
139
+ ptr: The pointer to set.
140
+
141
+ """
142
+ raise NotImplementedError
143
+
144
+
145
+ class BiasHandler(EpilogInputHandler):
146
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
147
+ self.logger = logger
148
+ self.mm_traits = mm_traits
149
+
150
+ assert enumerator in [
151
+ Epilog.BIAS,
152
+ Epilog.RELU_BIAS,
153
+ Epilog.RELU_AUX_BIAS,
154
+ Epilog.GELU_BIAS,
155
+ Epilog.GELU_AUX_BIAS,
156
+ ], "Internal error."
157
+ self.enumerator = enumerator
158
+
159
+ self.d_dtype_name = d_dtype_name
160
+
161
+ self.batch_offset = None
162
+
163
+ self._name = "bias"
164
+
165
+ self.version = cublaslt.get_version()
166
+
167
+ @property
168
+ def name(self):
169
+ return self._name
170
+
171
+ @property
172
+ def order(self):
173
+ return cublaslt.Order.COL
174
+
175
+ def validate(self, bias_tensor):
176
+ # The bias_tensor must be of rank 1, or rank 2 with (M, 1) or batched versions of
177
+ # the latter (..., M, 1) consistent with the C operand.
178
+
179
+ bias_shape = list(bias_tensor.shape)
180
+ bias_strides = list(bias_tensor.strides)
181
+
182
+ mm_traits = self.mm_traits
183
+
184
+ # Determine the rank of bias_tensor input.
185
+ bias_batch_shape, bias_mm_shape = bias_shape[:-2], bias_shape[-2:]
186
+ bias_batch_strides, bias_mm_strides = bias_strides[:-2], bias_strides[-2:]
187
+ if len(bias_mm_shape) == 1:
188
+ s, d = bias_mm_shape[0], bias_mm_strides[0]
189
+ bias_mm_shape += [1]
190
+ bias_mm_strides += [s * d]
191
+ self.logger.debug(f"The MM shape for the bias is {bias_mm_shape} with strides {bias_mm_strides}.")
192
+
193
+ Mb, Nb = bias_mm_shape
194
+ if Mb != mm_traits.M:
195
+ raise ValueError(f"The M dimension of the bias vector ({Mb}) must match the M dimension of A.")
196
+
197
+ if Nb != 1:
198
+ raise ValueError(f"The N dimension of the bias vector ({Nb}) must be equal to 1.")
199
+
200
+ # Check if the bias_tensor batch shape and axis order match that of the MM, and it's
201
+ # tileable.
202
+ if len(bias_batch_shape) > 0 and bias_batch_shape != mm_traits.batch_shape:
203
+ raise ValueError(
204
+ f"The batch dimensions of the bias {bias_batch_shape} must match with that of the matrix multiplication "
205
+ f"definition {mm_traits.batch_shape}."
206
+ )
207
+
208
+ if self.version < 110902 and len(bias_batch_shape) == 0 and len(mm_traits.batch_shape) > 0:
209
+ raise ValueError(
210
+ f"Bias broadcasting is not supported in cuBLASLt version < 110902 (you have version {self.version})."
211
+ )
212
+
213
+ if len(bias_batch_shape) > 0:
214
+ if self.version < 11703:
215
+ raise ValueError(
216
+ f"Batch dimensions are not supported for the bias tensor in cuBLASLt version < 11703 "
217
+ f"(you have version {self.version})."
218
+ )
219
+
220
+ bias_batch_axis_order = axis_order_in_memory(bias_batch_strides)
221
+ if bias_batch_axis_order != mm_traits.batch_axis_order:
222
+ raise ValueError(
223
+ f"The batch axis order of the bias {bias_batch_axis_order} must match with that "
224
+ f"of the other operands {mm_traits.batch_axis_order}."
225
+ )
226
+
227
+ if not check_batch_tileable(bias_batch_shape, bias_batch_strides):
228
+ message = (
229
+ f"The batch layout for bias corresponding to shape = {bias_batch_shape} "
230
+ f"and strides = {bias_batch_strides} is currently not supported because it is not tileable."
231
+ )
232
+ raise ValueError(message)
233
+
234
+ if bias_mm_strides[0] != 1:
235
+ raise ValueError(
236
+ f"The stride of the bias {bias_strides} must be 1 along the dimension {len(bias_strides) - 2}, "
237
+ f"which corresponds to the M dimension."
238
+ )
239
+
240
+ self.batch_offset = min(bias_batch_strides) if bias_batch_strides else 0 # bias broadcast
241
+
242
+ def update(self, mm_desc_ifc, bias_tensor):
243
+ # Set the bias pointer.
244
+ mm_desc_ifc.bias_pointer = bias_tensor.data_ptr
245
+ # Set the bias batch offset.
246
+ mm_desc_ifc.bias_batch_stride = self.batch_offset
247
+ # Set the bias data type.
248
+ if bias_tensor.dtype != self.d_dtype_name:
249
+ if self.version < 111103:
250
+ raise ValueError(
251
+ f"The bias tensor dtype '{bias_tensor.dtype}' must be the same as the result dtype "
252
+ f"'{self.d_dtype_name}' in cuBLASLt version < 111103 (you have {self.version})."
253
+ )
254
+ mm_desc_ifc.bias_data_type = typemaps.NAME_TO_DATA_TYPE[bias_tensor.dtype]
255
+
256
+
257
+ def round_up(m, base):
258
+ return m + (base - m) % base
259
+
260
+
261
+ def relu_aux_mm_shape(m, n):
262
+ """
263
+ Return the RELU auxiliary bitmask matrix shape when stored as uint8 and M is padded to
264
+ 128-bit/16-byte multiples.
265
+ """
266
+ # Store bitflag mask using int8 dtype, padded to (128//8 ==) 16 bytes.
267
+ m = round_up(math.ceil(m / 8), base=16)
268
+ return m, n
269
+
270
+
271
+ def gelu_aux_mm_shape(m, n):
272
+ """
273
+ Return the GELU auxiliary matrix shape when M is padded to 8-byte multiples.
274
+ """
275
+ m = round_up(m, base=8)
276
+ return m, n
277
+
278
+
279
+ class ReluAuxHandler(EpilogOutputHandler):
280
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
281
+ self.logger = logger
282
+ self.mm_traits = mm_traits
283
+
284
+ assert enumerator in [Epilog.RELU_AUX, Epilog.RELU_AUX_BIAS], "Internal error."
285
+ self.enumerator = enumerator
286
+
287
+ self._name = "relu_aux"
288
+
289
+ m, n = relu_aux_mm_shape(mm_traits.M, mm_traits.N)
290
+ batch_len = len(mm_traits.batch_axis_order)
291
+
292
+ self.aux_shape = mm_traits.batch_shape + [m, n]
293
+ aux_axis_order = [batch_len, batch_len + 1] + list(mm_traits.batch_axis_order) # Column order for the bitmask.
294
+ self.aux_strides = calculate_strides(self.aux_shape, aux_axis_order)
295
+ if aux_dtype_name is not None:
296
+ raise ValueError("Custom type for auxiliary outputs is not supported for RELU epilogs.")
297
+ self.aux_dtype_name = "uint8"
298
+
299
+ # We store bitmask using int8 dtype but the values below are in number of elements.
300
+ self.aux_ld = m * 8 # should be consistent with order (currently COL).
301
+ self.aux_batch_offset = m * 8 * n
302
+
303
+ @property
304
+ def name(self):
305
+ return self._name
306
+
307
+ @property
308
+ def order(self):
309
+ return cublaslt.Order.COL
310
+
311
+ def attributes(self):
312
+ return self.aux_shape, self.aux_strides, self.aux_dtype_name
313
+
314
+ def update(self, mm_desc_ifc):
315
+ # Set the aux LD.
316
+ mm_desc_ifc.epilogue_aux_ld = self.aux_ld
317
+ # Set the aux batch offset.
318
+ mm_desc_ifc.epilogue_aux_batch_stride = self.aux_batch_offset
319
+ # The aux data type is bitmask, don't set.
320
+
321
+ def update_ptr(self, mm_desc_ifc, ptr):
322
+ # Set the aux pointer.
323
+ mm_desc_ifc.epilogue_aux_pointer = ptr
324
+
325
+
326
+ class GeluAuxHandler(EpilogOutputHandler):
327
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
328
+ self.logger = logger
329
+ self.mm_traits = mm_traits
330
+
331
+ assert enumerator in [Epilog.GELU_AUX, Epilog.GELU_AUX_BIAS], "Internal error."
332
+ self.enumerator = enumerator
333
+
334
+ self.d_dtype_name = d_dtype_name
335
+
336
+ self._name = "gelu_aux"
337
+
338
+ m, n = gelu_aux_mm_shape(mm_traits.M, mm_traits.N)
339
+ batch_len = len(mm_traits.batch_axis_order)
340
+
341
+ self.aux_shape = mm_traits.batch_shape + [m, n]
342
+ aux_axis_order = [batch_len, batch_len + 1] + list(mm_traits.batch_axis_order) # Column order for the GELU inputs.
343
+ self.aux_strides = calculate_strides(self.aux_shape, aux_axis_order)
344
+
345
+ self.version = cublaslt.get_version()
346
+
347
+ if aux_dtype_name:
348
+ if self.version < 120800:
349
+ raise ValueError("Specifying custom AUX data type is not supported for cuBLAS < 12.8.")
350
+ self.aux_dtype_name = aux_dtype_name
351
+ else:
352
+ self.aux_dtype_name = c_dtype_name if "float8" in d_dtype_name else d_dtype_name
353
+
354
+ self.aux_ld = m # should be consistent with order (currently COL).
355
+ self.aux_batch_offset = m * n
356
+
357
+ @property
358
+ def name(self):
359
+ return self._name
360
+
361
+ @property
362
+ def order(self):
363
+ return cublaslt.Order.COL
364
+
365
+ def attributes(self):
366
+ return self.aux_shape, self.aux_strides, self.aux_dtype_name
367
+
368
+ def update(self, mm_desc_ifc):
369
+ # Set the aux LD.
370
+ mm_desc_ifc.epilogue_aux_ld = self.aux_ld
371
+ # Set the aux batch offset.
372
+ mm_desc_ifc.epilogue_aux_batch_stride = self.aux_batch_offset
373
+ # Set the pointer to 0x1 to bypass the cuBLAS check.
374
+ mm_desc_ifc.epilogue_aux_pointer = 0x1
375
+ if self.aux_dtype_name is not None and self.version >= 120800:
376
+ mm_desc_ifc.epilogue_aux_data_type = typemaps.NAME_TO_DATA_TYPE[self.aux_dtype_name]
377
+
378
+ def update_ptr(self, mm_desc_ifc, ptr):
379
+ # Set the aux pointer.
380
+ mm_desc_ifc.epilogue_aux_pointer = ptr
381
+
382
+
383
+ class BgradHandler(EpilogOutputHandler):
384
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
385
+ self.logger = logger
386
+ self.mm_traits = mm_traits
387
+
388
+ assert enumerator in [Epilog.DRELU_BGRAD, Epilog.DGELU_BGRAD, Epilog.BGRADA, Epilog.BGRADB], "Internal error."
389
+ self.enumerator = enumerator
390
+
391
+ version = cublaslt.get_version()
392
+ if mm_traits.K == 1 and enumerator in [Epilog.BGRADA, Epilog.BGRADB] and version < 120304:
393
+ raise ValueError(
394
+ f"K=1 is not supported for {enumerator.name} epilog in cuBLASLt version < 120304 (you have version {version})."
395
+ )
396
+
397
+ self._name = enumerator.name.lower()
398
+
399
+ if aux_dtype_name is not None:
400
+ raise ValueError("Custom type for auxiliary outputs is not supported for RELU epilogs.")
401
+
402
+ m = mm_traits.N if enumerator == Epilog.BGRADB else mm_traits.M
403
+ batch_len = len(mm_traits.batch_axis_order)
404
+
405
+ self.bgrad_shape = shape = [m]
406
+ if mm_traits.batch_shape:
407
+ shape = shape + [1]
408
+ self.bgrad_shape = mm_traits.batch_shape + self.bgrad_shape + [1]
409
+
410
+ bgrad_axis_order = [batch_len + a for a in range(len(shape))] + list(mm_traits.batch_axis_order) # Column order.
411
+ self.bgrad_strides = calculate_strides(self.bgrad_shape, bgrad_axis_order)
412
+
413
+ self.d_dtype_name = d_dtype_name
414
+ self.bgrad_dtype_name = d_dtype_name
415
+ self.bgrad_batch_offset = m
416
+
417
+ @property
418
+ def name(self):
419
+ return self._name
420
+
421
+ @property
422
+ def order(self):
423
+ """
424
+ For BGRADA or BGRADB, there is no layout constraint but DRELU_BGRAD and DGELU_BGRAD
425
+ require COL. However currently use COL for BGRADB as well to workaround a library
426
+ issue.
427
+ """
428
+ if self.enumerator in [Epilog.DRELU_BGRAD, Epilog.DGELU_BGRAD, Epilog.BGRADB]:
429
+ return cublaslt.Order.COL
430
+ return None
431
+
432
+ def attributes(self):
433
+ return self.bgrad_shape, self.bgrad_strides, self.bgrad_dtype_name
434
+
435
+ def update(self, mm_desc_ifc):
436
+ # Set the bgrad batch offset.
437
+ mm_desc_ifc.bias_batch_stride = self.bgrad_batch_offset
438
+ # The bgrad data type is by default the data type of the result for all the cases we
439
+ # support.
440
+ assert self.bgrad_dtype_name == self.d_dtype_name, "Internal error."
441
+
442
+ def update_ptr(self, mm_desc_ifc, ptr):
443
+ # Set the bgrad pointer.
444
+ mm_desc_ifc.bias_pointer = ptr
445
+
446
+
447
+ class DReluAuxHandler(EpilogInputHandler):
448
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
449
+ self.logger = logger
450
+ self.mm_traits = mm_traits
451
+
452
+ assert enumerator in [Epilog.DRELU, Epilog.DRELU_BGRAD], "Internal error."
453
+ self.enumerator = enumerator
454
+
455
+ self.batch_offset = None
456
+
457
+ self._name = "relu_aux"
458
+
459
+ # The bitmask int8 matrix shape, including padding.
460
+ self.mm_m, self.mm_n = relu_aux_mm_shape(mm_traits.M, mm_traits.N)
461
+
462
+ # We store bitmask using int8 dtype but the values below are in number of elements.
463
+ self.aux_ld = self.mm_m * 8 # should be consistent with order (currently COL).
464
+
465
+ # K=1 is not supported by cuBLAS
466
+ if mm_traits.K == 1:
467
+ raise ValueError("K=1 is not supported for DRELU epilogs")
468
+
469
+ @property
470
+ def name(self):
471
+ return self._name
472
+
473
+ @property
474
+ def order(self):
475
+ return cublaslt.Order.COL
476
+
477
+ def validate(self, relu_aux_tensor):
478
+ # The relu_aux_tensor must be of rank 2 or its batched version of the latter (...,
479
+ # M, N).
480
+ relu_aux_shape = list(relu_aux_tensor.shape)
481
+ relu_aux_strides = list(relu_aux_tensor.strides)
482
+
483
+ # The dtype must be uint8.
484
+ if relu_aux_tensor.dtype != "uint8":
485
+ raise ValueError(
486
+ f"The dtype of the RELU auxiliary input for epilog {self.enumerator.name} must be 'uint8'. "
487
+ f"The epilog input's dtype is '{relu_aux_tensor.dtype}'."
488
+ )
489
+
490
+ mm_traits = self.mm_traits
491
+
492
+ # Determine the rank of relu_aux_tensor input.
493
+ relu_aux_batch_shape, relu_aux_mm_shape = relu_aux_shape[:-2], relu_aux_shape[-2:]
494
+ relu_aux_batch_strides, relu_aux_mm_strides = relu_aux_strides[:-2], relu_aux_strides[-2:]
495
+
496
+ # The MM shape must match, the MM must be in col order, and the batch order must
497
+ # match.
498
+ Ma, Na = relu_aux_mm_shape
499
+ if Ma != self.mm_m or Na != self.mm_n:
500
+ raise ValueError(
501
+ f"The auxiliary epilog input for epilog {self.enumerator.name} must have the MM shape "
502
+ f"(..., {self.mm_m}, {self.mm_n}). The epilog input's MM shape is (..., {Ma}, {Na})."
503
+ )
504
+
505
+ # Check if the relu_aux_tensor batch shape and axis order match that of the MM, and
506
+ # it's tileable.
507
+ if len(relu_aux_batch_shape) > 0:
508
+ if relu_aux_batch_shape != mm_traits.batch_shape:
509
+ raise ValueError(
510
+ f"The batch dimensions of the RELU auxiliary input {relu_aux_batch_shape} must match with that "
511
+ f"of the matrix multiplication definition {mm_traits.batch_shape}."
512
+ )
513
+
514
+ if (relu_aux_batch_axis_order := axis_order_in_memory(relu_aux_batch_strides)) != mm_traits.batch_axis_order:
515
+ raise ValueError(
516
+ f"The batch axis order of the RELU auxiliary input {relu_aux_batch_axis_order} must match with that "
517
+ f"of the other operands {mm_traits.batch_axis_order}."
518
+ )
519
+
520
+ if not check_batch_tileable(relu_aux_batch_shape, relu_aux_batch_strides):
521
+ message = (
522
+ f"The batch layout for RELU auxiliary input corresponding to shape = {relu_aux_batch_shape} "
523
+ f"and strides = {relu_aux_batch_strides} is currently not supported because it is not tileable."
524
+ )
525
+ raise ValueError(message)
526
+
527
+ if relu_aux_mm_strides[0] != 1:
528
+ raise ValueError(
529
+ f"The stride of the RELU auxiliary input {relu_aux_strides} must be 1 "
530
+ f"along the dimension {len(relu_aux_strides) - 2}, which corresponds to the M dimension."
531
+ )
532
+
533
+ # Convert from bits to elements.
534
+ self.batch_offset = min(relu_aux_batch_strides) * 8 if relu_aux_batch_strides else 0 # relu_aux broadcast
535
+
536
+ if self.batch_offset > 0:
537
+ assert self.batch_offset > 0 and self.batch_offset >= self.mm_m * 8 * self.mm_n, "Tensor data must not overlap."
538
+
539
+ def update(self, mm_desc_ifc, relu_aux_tensor):
540
+ # Set the epilog aux pointer.
541
+ mm_desc_ifc.epilogue_aux_pointer = relu_aux_tensor.data_ptr
542
+ # Set the relu_aux batch offset.
543
+ mm_desc_ifc.epilogue_aux_batch_stride = self.batch_offset
544
+ # Set the aux LD.
545
+ mm_desc_ifc.epilogue_aux_ld = self.aux_ld
546
+ # The relu aux data type is bitmask, don't set.
547
+
548
+
549
+ class DGeluAuxHandler(EpilogInputHandler):
550
+ def __init__(self, logger, mm_traits, enumerator, c_dtype_name, d_dtype_name, aux_dtype_name):
551
+ self.logger = logger
552
+ self.mm_traits = mm_traits
553
+
554
+ assert enumerator in [Epilog.DGELU, Epilog.DGELU_BGRAD], "Internal error."
555
+ self.enumerator = enumerator
556
+
557
+ self.d_dtype_name = d_dtype_name
558
+
559
+ self.batch_offset = None
560
+
561
+ self._name = "gelu_aux"
562
+
563
+ # The GELU aux matrix shape, including padding.
564
+ self.mm_m, self.mm_n = gelu_aux_mm_shape(mm_traits.M, mm_traits.N)
565
+
566
+ self.aux_ld = self.mm_m # should be consistent with order (currently COL).
567
+
568
+ # K=1 is not supported by cuBLAS
569
+ if mm_traits.K == 1:
570
+ raise ValueError("K=1 is not supported for DGELU epilogs")
571
+
572
+ @property
573
+ def name(self):
574
+ return self._name
575
+
576
+ @property
577
+ def order(self):
578
+ return cublaslt.Order.COL
579
+
580
+ def validate(self, gelu_aux_tensor):
581
+ # The gelu_aux_tensor must be of rank 2 or its batched version of the latter (...,
582
+ # M, N).
583
+ gelu_aux_shape = list(gelu_aux_tensor.shape)
584
+ gelu_aux_strides = list(gelu_aux_tensor.strides)
585
+
586
+ # The dtype must be the same as that of D.
587
+ if gelu_aux_tensor.dtype != self.d_dtype_name:
588
+ raise ValueError(
589
+ f"The dtype of the GELU auxiliary input for epilog {self.enumerator.name} must be '{self.d_dtype_name}'. "
590
+ f"The epilog input's dtype is '{gelu_aux_tensor.dtype}'."
591
+ )
592
+
593
+ mm_traits = self.mm_traits
594
+
595
+ # Determine the rank of gelu_aux_tensor input.
596
+ gelu_aux_batch_shape, gelu_aux_mm_shape = gelu_aux_shape[:-2], gelu_aux_shape[-2:]
597
+ gelu_aux_batch_strides, gelu_aux_mm_strides = gelu_aux_strides[:-2], gelu_aux_strides[-2:]
598
+
599
+ # The MM shape must match, the MM must be in col order, and the batch order must
600
+ # match.
601
+ Ma, Na = gelu_aux_mm_shape
602
+ if Ma != self.mm_m or Na != self.mm_n:
603
+ raise ValueError(
604
+ f"The auxiliary epilog input for epilog {self.enumerator.name} must have "
605
+ f"the MM shape (..., {self.mm_m}, {self.mm_n}). The epilog input's MM shape is (..., {Ma}, {Na})."
606
+ )
607
+
608
+ # Check if the gelu_aux_tensor batch shape and axis order match that of the MM, and
609
+ # it's tileable.
610
+ if len(gelu_aux_batch_shape) > 0:
611
+ if gelu_aux_batch_shape != mm_traits.batch_shape:
612
+ raise ValueError(
613
+ f"The batch dimensions of the GELU auxiliary input {gelu_aux_batch_shape} must match with that "
614
+ f"of the matrix multiplication definition {mm_traits.batch_shape}."
615
+ )
616
+
617
+ if (gelu_aux_batch_axis_order := axis_order_in_memory(gelu_aux_batch_strides)) != mm_traits.batch_axis_order:
618
+ raise ValueError(
619
+ f"The batch axis order of the GELU auxiliary input {gelu_aux_batch_axis_order} "
620
+ f"must match with that of the other operands {mm_traits.batch_axis_order}."
621
+ )
622
+
623
+ if not check_batch_tileable(gelu_aux_batch_shape, gelu_aux_batch_strides):
624
+ message = (
625
+ f"The batch layout for GELU auxiliary input corresponding to shape = {gelu_aux_batch_shape} and "
626
+ f"strides = {gelu_aux_batch_strides} is currently not supported because it is not tileable."
627
+ )
628
+ raise ValueError(message)
629
+
630
+ if gelu_aux_mm_strides[0] != 1:
631
+ raise ValueError(
632
+ f"The stride of the GELU auxiliary input {gelu_aux_strides} must be 1 "
633
+ f"along the dimension {len(gelu_aux_strides) - 2}, which corresponds to the M dimension."
634
+ )
635
+
636
+ self.batch_offset = min(gelu_aux_batch_strides) if gelu_aux_batch_strides else 0 # gelu_aux broadcast
637
+
638
+ if self.batch_offset > 0:
639
+ assert self.batch_offset > 0 and self.batch_offset >= self.mm_m * self.mm_n, "Tensor data must not overlap."
640
+
641
+ def update(self, mm_desc_ifc, gelu_aux_tensor):
642
+ # Set the epilog aux pointer.
643
+ mm_desc_ifc.epilogue_aux_pointer = gelu_aux_tensor.data_ptr
644
+ # Set the gelu_aux batch offset.
645
+ mm_desc_ifc.epilogue_aux_batch_stride = self.batch_offset
646
+ # Set the aux LD.
647
+ mm_desc_ifc.epilogue_aux_ld = self.aux_ld
648
+ # Set the gelu aux data type.
649
+ if gelu_aux_tensor.dtype != self.d_dtype_name:
650
+ if self.version < 111103:
651
+ raise ValueError(
652
+ f"The GELU auxiliary tensor dtype '{gelu_aux_tensor.dtype}' must be the same as "
653
+ f"the result dtype '{self.d_dtype_name}' in cuBLASLt version < 111103 (you have {self.version})."
654
+ )
655
+ mm_desc_ifc.epilogue_aux_data_type = typemaps.NAME_TO_DATA_TYPE[gelu_aux_tensor.dtype]
656
+
657
+
658
+ EPILOG_INPUT_HANDLERS_MAP: dict[cublaslt.Epilogue, list[type[EpilogInputHandler]]] = {
659
+ Epilog.RELU: [],
660
+ Epilog.RELU_AUX: [],
661
+ Epilog.GELU: [],
662
+ Epilog.GELU_AUX: [],
663
+ Epilog.BIAS: [BiasHandler],
664
+ Epilog.RELU_BIAS: [BiasHandler],
665
+ Epilog.RELU_AUX_BIAS: [BiasHandler],
666
+ Epilog.GELU_BIAS: [BiasHandler],
667
+ Epilog.GELU_AUX_BIAS: [BiasHandler],
668
+ Epilog.DRELU: [DReluAuxHandler],
669
+ Epilog.DRELU_BGRAD: [DReluAuxHandler],
670
+ Epilog.DGELU: [DGeluAuxHandler],
671
+ Epilog.DGELU_BGRAD: [DGeluAuxHandler],
672
+ Epilog.BGRADA: [],
673
+ Epilog.BGRADB: [],
674
+ }
675
+
676
+ EPILOG_OUTPUT_HANDLERS_MAP: dict[cublaslt.Epilogue, list[type[EpilogOutputHandler]]] = {
677
+ Epilog.RELU: [],
678
+ Epilog.RELU_AUX: [ReluAuxHandler],
679
+ Epilog.GELU: [],
680
+ Epilog.GELU_AUX: [GeluAuxHandler],
681
+ Epilog.BIAS: [],
682
+ Epilog.RELU_BIAS: [],
683
+ Epilog.RELU_AUX_BIAS: [ReluAuxHandler],
684
+ Epilog.GELU_BIAS: [],
685
+ Epilog.GELU_AUX_BIAS: [GeluAuxHandler],
686
+ Epilog.DRELU: [],
687
+ Epilog.DRELU_BGRAD: [BgradHandler],
688
+ Epilog.DGELU: [],
689
+ Epilog.DGELU_BGRAD: [BgradHandler],
690
+ Epilog.BGRADA: [BgradHandler],
691
+ Epilog.BGRADB: [BgradHandler],
692
+ }
693
+
694
+ EPILOG_MINIMUM_VERSIONS_MAP: dict[cublaslt.Epilogue, dict[str, int | str]] = {
695
+ None: {"cublaslt": 00000, "ctk": ""},
696
+ # RELU was the first implemented epilog
697
+ Epilog.RELU: {"cublaslt": 11000, "ctk": "11.0.1"},
698
+ # 11301, 11.2.0 supports ^
699
+ # 11401, 11.2.2 supports ^
700
+ # 11402, 11.3.0 supports ^
701
+ # Even though some *BIAS epilogs appear in earlier headers, because
702
+ # CUBLASLT_MATMUL_DESC_BIAS_BATCH_STRIDE is not defined we cannot use them.
703
+ Epilog.GELU: {"cublaslt": 11501, "ctk": "11.3.1"},
704
+ Epilog.BIAS: {"cublaslt": 11501, "ctk": "11.3.1"},
705
+ Epilog.RELU_AUX: {"cublaslt": 11501, "ctk": "11.3.1"},
706
+ Epilog.GELU_AUX: {"cublaslt": 11501, "ctk": "11.3.1"},
707
+ Epilog.RELU_BIAS: {"cublaslt": 11501, "ctk": "11.3.1"},
708
+ Epilog.RELU_AUX_BIAS: {"cublaslt": 11501, "ctk": "11.3.1"},
709
+ Epilog.GELU_BIAS: {"cublaslt": 11501, "ctk": "11.3.1"},
710
+ Epilog.GELU_AUX_BIAS: {"cublaslt": 11501, "ctk": "11.3.1"},
711
+ # 11501, 11.3.1 supports ^
712
+ # 11504, 11.4.1 supports ^
713
+ # 11601, 11.4.2 supports ^
714
+ # 11703, 11.5.0 supports ^
715
+ # 11704, 11.5.1 supports ^
716
+ # 11801, 11.6.0 supports ^
717
+ # 11801, 11.6.1 supports ^
718
+ # 110902, 11.6.2 supports ^
719
+ # Even though BGRAD[A,B] and D[R,G]ELU appear in earlier headers, our unit tests mark
720
+ # them as unsupported before 111103 for in order to avoid API changes.
721
+ Epilog.DRELU: {"cublaslt": 111103, "ctk": "11.8.0"},
722
+ Epilog.DGELU: {"cublaslt": 111103, "ctk": "11.8.0"},
723
+ Epilog.BGRADA: {"cublaslt": 111103, "ctk": "11.8.0"},
724
+ Epilog.BGRADB: {"cublaslt": 111103, "ctk": "11.8.0"},
725
+ Epilog.DRELU_BGRAD: {"cublaslt": 111103, "ctk": "11.8.0"},
726
+ Epilog.DGELU_BGRAD: {"cublaslt": 111103, "ctk": "11.8.0"},
727
+ # 111103, 11.8.0 supports ^
728
+ }
729
+
730
+ BATCHED_EPILOG_MINIMUM_VERSIONS_MAP = EPILOG_MINIMUM_VERSIONS_MAP.copy()
731
+ BATCHED_EPILOG_MINIMUM_VERSIONS_MAP.update(
732
+ {
733
+ Epilog.RELU_AUX: {"cublaslt": 11703, "ctk": "11.5"},
734
+ Epilog.GELU_AUX: {"cublaslt": 11703, "ctk": "11.5"},
735
+ Epilog.RELU_AUX_BIAS: {"cublaslt": 11703, "ctk": "11.5"},
736
+ Epilog.GELU_AUX_BIAS: {"cublaslt": 11703, "ctk": "11.5"},
737
+ }
738
+ )