nvmath-python 0.9.0__cp314-cp314-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.
- nvmath/__init__.pxd +0 -0
- nvmath/__init__.py +45 -0
- nvmath/_internal/__init__.py +0 -0
- nvmath/_internal/attribute_ifc_factory.py +330 -0
- nvmath/_internal/layout.py +70 -0
- nvmath/_internal/templates.py +383 -0
- nvmath/_utils.py +150 -0
- nvmath/bindings/__init__.py +51 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +47 -0
- nvmath/bindings/_internal/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +277 -0
- nvmath/bindings/_internal/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +179 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +746 -0
- nvmath/bindings/cublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1337 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +219 -0
- nvmath/bindings/cudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +86 -0
- nvmath/bindings/cudss.pyi +282 -0
- nvmath/bindings/cufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +241 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +260 -0
- nvmath/bindings/curand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +159 -0
- nvmath/bindings/cusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +242 -0
- nvmath/bindings/cusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +416 -0
- nvmath/bindings/cusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +338 -0
- nvmath/bindings/cusparse.pyi +659 -0
- nvmath/bindings/cusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +198 -0
- nvmath/bindings/cutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +294 -0
- nvmath/bindings/cycublas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +684 -0
- nvmath/bindings/cycublasLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1055 -0
- nvmath/bindings/cycublasMp.pxd +183 -0
- nvmath/bindings/cycudss.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +224 -0
- nvmath/bindings/cycufft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +326 -0
- nvmath/bindings/cycufftMp.pxd +334 -0
- nvmath/bindings/cycurand.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +146 -0
- nvmath/bindings/cycusolver.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +154 -0
- nvmath/bindings/cycusolverDn.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +446 -0
- nvmath/bindings/cycusparse.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +470 -0
- nvmath/bindings/cycusparseLt.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +150 -0
- nvmath/bindings/cycutensor.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +192 -0
- nvmath/bindings/cymathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +126 -0
- nvmath/bindings/mathdx.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1244 -0
- nvmath/bindings/nvpl/__init__.pxd +0 -0
- nvmath/bindings/nvpl/__init__.py +13 -0
- nvmath/bindings/nvpl/_internal/__init__.pxd +0 -0
- nvmath/bindings/nvpl/_internal/__init__.py +0 -0
- nvmath/bindings/nvpl/_internal/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +125 -0
- nvmath/bindings/nvpl/_internal/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +85 -0
- nvmath/bindings/nvpl/blas.pyi +122 -0
- nvmath/bindings/nvpl/cyblas.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +166 -0
- nvmath/bindings/nvpl/cyfft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +92 -0
- nvmath/bindings/nvpl/fft.cp314-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +100 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +179 -0
- nvmath/device/__init__.py +21 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +313 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +310 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1805 -0
- nvmath/device/cublasdx_backend.py +807 -0
- nvmath/device/cublasdx_numba.py +1612 -0
- nvmath/device/cufftdx.py +510 -0
- nvmath/device/cufftdx_backend.py +196 -0
- nvmath/device/cufftdx_numba.py +196 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2690 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +1624 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +445 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +147 -0
- nvmath/device/vector_types_numba.py +203 -0
- nvmath/distributed/__init__.py +205 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nvshmem.py +302 -0
- nvmath/distributed/_internal/tensor_ifc.py +67 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +62 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +165 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +41 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +141 -0
- nvmath/distributed/_internal/tensor_wrapper.py +78 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution.py +770 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +79 -0
- nvmath/distributed/fft/fft.py +2801 -0
- nvmath/distributed/linalg/__init__.py +12 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +496 -0
- nvmath/distributed/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/distributed/linalg/advanced/__init__.py +8 -0
- nvmath/distributed/linalg/advanced/_configuration.py +166 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +2908 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/distributed/reshape/__init__.py +6 -0
- nvmath/distributed/reshape/_configuration.py +39 -0
- nvmath/distributed/reshape/reshape.py +1256 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +208 -0
- nvmath/fft/_exec_utils.py +109 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +2903 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +12 -0
- nvmath/internal/_device_utils.py +54 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +10 -0
- nvmath/internal/memory.pyi +46 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +7 -0
- nvmath/internal/ndbuffer/copy_kernel/args.h +34 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/array_view.h +52 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/elementwise.h +68 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/grid_indexer.h +69 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/transposed.h +240 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/type_utils.h +39 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/utils.h +132 -0
- nvmath/internal/ndbuffer/copy_kernel/copy_kernel_impl/vec.h +159 -0
- nvmath/internal/ndbuffer/copy_kernel/elementwise.h +53 -0
- nvmath/internal/ndbuffer/copy_kernel/transposed.h +58 -0
- nvmath/internal/ndbuffer/copy_kernel.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/copy_kernel.pxd +9 -0
- nvmath/internal/ndbuffer/copy_kernel.pyi +9 -0
- nvmath/internal/ndbuffer/data_layout.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/data_layout.pxd +72 -0
- nvmath/internal/ndbuffer/data_layout.pyi +23 -0
- nvmath/internal/ndbuffer/jit.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/jit.pxd +7 -0
- nvmath/internal/ndbuffer/jit.pyi +6 -0
- nvmath/internal/ndbuffer/ndbuffer.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/ndbuffer.pxd +36 -0
- nvmath/internal/ndbuffer/ndbuffer.pyi +41 -0
- nvmath/internal/ndbuffer/package_utils.cp314-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/package_utils.pxd +11 -0
- nvmath/internal/ndbuffer/package_utils.pyi +12 -0
- nvmath/internal/package_ifc.py +147 -0
- nvmath/internal/package_ifc_cuda.py +49 -0
- nvmath/internal/package_ifc_cupy.py +49 -0
- nvmath/internal/package_ifc_torch.py +31 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +194 -0
- nvmath/internal/tensor_ifc_cupy.py +241 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +153 -0
- nvmath/internal/tensor_ifc_numpy.py +183 -0
- nvmath/internal/tensor_ifc_torch.py +176 -0
- nvmath/internal/tensor_wrapper.py +157 -0
- nvmath/internal/typemaps.py +162 -0
- nvmath/internal/utils.py +771 -0
- nvmath/linalg/__init__.py +46 -0
- nvmath/linalg/_internal/__init__.py +3 -0
- nvmath/linalg/_internal/algo_cap_ifc.py +82 -0
- nvmath/linalg/_internal/algo_config_ifc.py +43 -0
- nvmath/linalg/_internal/batch.py +217 -0
- nvmath/linalg/_internal/enum_to_tuples.py +64 -0
- nvmath/linalg/_internal/epilog_protocol.py +766 -0
- nvmath/linalg/_internal/layout.py +624 -0
- nvmath/linalg/_internal/matmul_desc_ifc.py +28 -0
- nvmath/linalg/_internal/matmul_pref_ifc.py +27 -0
- nvmath/linalg/_internal/matrix_layout_ifc.py +26 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +134 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +149 -0
- nvmath/linalg/advanced/_configuration.py +349 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1348 -0
- nvmath/linalg/advanced/matmulmod.py +3937 -0
- nvmath/linalg/generic/__init__.py +43 -0
- nvmath/linalg/generic/_configuration/__init__.py +37 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +609 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +494 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +1060 -0
- nvmath/memory.py +282 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +144 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +741 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +445 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +300 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +254 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +266 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +239 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +121 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +146 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +230 -0
- nvmath/sparse/advanced/direct_solver.py +1884 -0
- nvmath/sparse/generic/__init__.py +7 -0
- nvmath/sparse/generic/_configuration.py +129 -0
- nvmath/sparse/generic/_helpers.py +137 -0
- nvmath/sparse/generic/_thunks.py +21 -0
- nvmath/sparse/generic/matmulmod.py +2426 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +378 -0
- nvmath/sparse/ust/_drawer.py +552 -0
- nvmath/sparse/ust/_emitter.py +553 -0
- nvmath/sparse/ust/_jit.py +212 -0
- nvmath/sparse/ust/_kernel.py +346 -0
- nvmath/sparse/ust/_semiring.py +71 -0
- nvmath/sparse/ust/_utils.py +102 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/semiring_ops.py +71 -0
- nvmath/sparse/ust/tensor.py +1027 -0
- nvmath/sparse/ust/tensor_drawer.py +552 -0
- nvmath/sparse/ust/tensor_emitter.py +558 -0
- nvmath/sparse/ust/tensor_format.py +935 -0
- nvmath/sparse/ust/tensor_jit.py +212 -0
- nvmath/sparse/ust/tensor_kernel.py +348 -0
- nvmath/sparse/ust/tensor_utils.py +380 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +95 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +247 -0
- nvmath/tensor/_internal/cutensor_utils.py +162 -0
- nvmath/tensor/_internal/data.py +43 -0
- nvmath/tensor/_internal/einsum_parser.py +444 -0
- nvmath/tensor/_internal/typemaps.py +96 -0
- nvmath/tensor/contract.py +1861 -0
- nvmath_python-0.9.0.dist-info/METADATA +127 -0
- nvmath_python-0.9.0.dist-info/RECORD +309 -0
- nvmath_python-0.9.0.dist-info/WHEEL +5 -0
- nvmath_python-0.9.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-0.9.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface to seamlessly use Numpy ndarray objects.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["NumpyTensor", "CudaTensor"]
|
|
10
|
+
|
|
11
|
+
from collections.abc import Sequence
|
|
12
|
+
|
|
13
|
+
import numpy
|
|
14
|
+
import numpy.typing as npt
|
|
15
|
+
|
|
16
|
+
from nvmath.internal.tensor_ifc_ndbuffer import NDBufferTensor
|
|
17
|
+
|
|
18
|
+
from . import utils
|
|
19
|
+
from .ndbuffer import ndbuffer, package_utils
|
|
20
|
+
from .package_ifc import StreamHolder
|
|
21
|
+
from .tensor_ifc import TensorHolder
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CudaTensor(NDBufferTensor):
|
|
25
|
+
"""
|
|
26
|
+
Wraps ndbuffer with data residing on the GPU.
|
|
27
|
+
It serves as a CUDA counterpart for NumpyTensor.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
name = "cuda"
|
|
31
|
+
host_tensor_class: type["NumpyTensor"] # set once NumpyTensor is defined
|
|
32
|
+
|
|
33
|
+
def __init__(self, tensor):
|
|
34
|
+
super().__init__(tensor)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def create_from_host(cls, tensor: TensorHolder, device_id: int, stream_holder: StreamHolder):
|
|
38
|
+
with utils.device_ctx(device_id):
|
|
39
|
+
src_ndbuffer = tensor.asndbuffer()
|
|
40
|
+
dst_ndbuffer = ndbuffer.empty_like(src_ndbuffer, device_id=device_id, stream=stream_holder)
|
|
41
|
+
ndbuffer.copy_into(dst_ndbuffer, src_ndbuffer, stream_holder)
|
|
42
|
+
return cls(dst_ndbuffer)
|
|
43
|
+
|
|
44
|
+
def to(self, device_id, stream_holder):
|
|
45
|
+
if device_id == "cpu":
|
|
46
|
+
with utils.device_ctx(self.device_id):
|
|
47
|
+
dst = self.host_tensor_class.create_host_from(self, stream_holder)
|
|
48
|
+
return dst
|
|
49
|
+
elif device_id == self.device_id:
|
|
50
|
+
return self
|
|
51
|
+
elif isinstance(device_id, int):
|
|
52
|
+
raise ValueError(f"Unsupported copy between different devices {self.device_id} and {device_id}.")
|
|
53
|
+
else:
|
|
54
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class NumpyTensor(TensorHolder[npt.NDArray]):
|
|
58
|
+
"""
|
|
59
|
+
TensorHolder for numpy ndarrays.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
name = "numpy"
|
|
63
|
+
module = numpy
|
|
64
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(
|
|
65
|
+
conversion_function=lambda name: numpy.dtype(name), exception_type=TypeError
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
device_tensor_class = CudaTensor
|
|
69
|
+
|
|
70
|
+
def __init__(self, tensor):
|
|
71
|
+
super().__init__(tensor)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def data_ptr(self):
|
|
75
|
+
return self.tensor.ctypes.data
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def device(self):
|
|
79
|
+
return "cpu"
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def device_id(self):
|
|
83
|
+
return "cpu"
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def dtype(self):
|
|
87
|
+
"""Name of the data type"""
|
|
88
|
+
return self.tensor.dtype.name
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def itemsize(self):
|
|
92
|
+
return self.tensor.itemsize
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def empty(cls, shape, device_id="cpu", *, dtype="float32", strides=None, **context):
|
|
96
|
+
"""
|
|
97
|
+
Create an empty tensor of the specified shape and data type.
|
|
98
|
+
"""
|
|
99
|
+
assert device_id == "cpu", "Internal Error: Numpy tensors must be allocated with device_id='cpu'"
|
|
100
|
+
dtype = NumpyTensor.name_to_dtype[dtype]
|
|
101
|
+
# when strides is not None, it should be of unit counts not bytes
|
|
102
|
+
return cls(
|
|
103
|
+
cls.module.ndarray(shape, dtype=dtype, strides=(tuple(s * dtype.itemsize for s in strides) if strides else None))
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def create_host_from(cls, tensor: TensorHolder, stream_holder: StreamHolder):
|
|
108
|
+
src_nd = tensor.asndbuffer()
|
|
109
|
+
wrapped_np = package_utils.empty_numpy_like(src_nd)
|
|
110
|
+
ndbuffer.copy_into(wrapped_np, src_nd, stream_holder)
|
|
111
|
+
return cls(wrapped_np.data)
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def shape(self):
|
|
115
|
+
return tuple(self.tensor.shape)
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def size(self):
|
|
119
|
+
return self.tensor.size
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def strides(self):
|
|
123
|
+
return tuple(stride_in_bytes // self.tensor.itemsize for stride_in_bytes in self.tensor.strides)
|
|
124
|
+
|
|
125
|
+
def asndbuffer(self):
|
|
126
|
+
return package_utils.wrap_numpy_array(self.tensor)
|
|
127
|
+
|
|
128
|
+
def to(self, device_id, stream_holder):
|
|
129
|
+
if device_id == "cpu":
|
|
130
|
+
return self
|
|
131
|
+
elif isinstance(device_id, int):
|
|
132
|
+
dst = self.device_tensor_class.create_from_host(self, device_id, stream_holder)
|
|
133
|
+
return dst
|
|
134
|
+
else:
|
|
135
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
136
|
+
|
|
137
|
+
def copy_(self, src, stream_holder):
|
|
138
|
+
match src.name:
|
|
139
|
+
case "numpy":
|
|
140
|
+
numpy.copyto(self.tensor, src.tensor)
|
|
141
|
+
case _:
|
|
142
|
+
with utils.device_ctx(src.device_id):
|
|
143
|
+
ndbuffer.copy_into(self.asndbuffer(), src._broadcast_to(self.shape).asndbuffer(), stream_holder)
|
|
144
|
+
|
|
145
|
+
def istensor(self):
|
|
146
|
+
"""
|
|
147
|
+
Check if the object is ndarray-like.
|
|
148
|
+
"""
|
|
149
|
+
return isinstance(self.tensor, numpy.ndarray)
|
|
150
|
+
|
|
151
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
152
|
+
if int(numpy.__version__.split(".")[0]) < 2:
|
|
153
|
+
return self.__class__(numpy.reshape(self.tensor, shape))
|
|
154
|
+
else:
|
|
155
|
+
return self.__class__(numpy.reshape(self.tensor, shape, copy=copy))
|
|
156
|
+
|
|
157
|
+
def memory_buffer(self):
|
|
158
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
159
|
+
t = self.tensor
|
|
160
|
+
# TODO: ensure tensor is dense for now, and later support linear
|
|
161
|
+
# memory with constant stride.
|
|
162
|
+
v = NumpyTensor(t.ravel(order="K"))
|
|
163
|
+
assert v.data_ptr == self.data_ptr, "Internal error."
|
|
164
|
+
return v
|
|
165
|
+
|
|
166
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
167
|
+
"""
|
|
168
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
169
|
+
shape and strides.
|
|
170
|
+
"""
|
|
171
|
+
assert len(self.shape) == 1, "Internal error."
|
|
172
|
+
t = self.tensor
|
|
173
|
+
strides = [s * self.itemsize for s in strides]
|
|
174
|
+
v = NumpyTensor(numpy.lib.stride_tricks.as_strided(t, shape=shape, strides=strides))
|
|
175
|
+
assert v.data_ptr == self.data_ptr, "Internal error."
|
|
176
|
+
return v
|
|
177
|
+
|
|
178
|
+
def _broadcast_to(self, shape):
|
|
179
|
+
reshaped_tensor = numpy.broadcast_to(self.tensor, shape)
|
|
180
|
+
return self.__class__(reshaped_tensor)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
CudaTensor.host_tensor_class = NumpyTensor
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Interface to seamlessly use Torch tensor objects.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["TorchTensor"]
|
|
10
|
+
|
|
11
|
+
import contextlib
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
14
|
+
import torch
|
|
15
|
+
|
|
16
|
+
from .package_ifc import StreamHolder
|
|
17
|
+
from .tensor_ifc import TensorHolder
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TorchTensor(TensorHolder[torch.Tensor]):
|
|
21
|
+
"""
|
|
22
|
+
TensorHolder for Torch Tensors.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
name = "torch"
|
|
26
|
+
module = torch
|
|
27
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(
|
|
28
|
+
conversion_function=lambda name: getattr(torch, name), exception_type=AttributeError
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def __init__(self, tensor):
|
|
32
|
+
super().__init__(tensor)
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def data_ptr(self):
|
|
36
|
+
return self.tensor.data_ptr()
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def device(self):
|
|
40
|
+
return str(self.tensor.device).split(":")[0]
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def device_id(self):
|
|
44
|
+
index = self.tensor.device.index
|
|
45
|
+
return "cpu" if index is None else index
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def dtype(self):
|
|
49
|
+
"""Name of the data type"""
|
|
50
|
+
return str(self.tensor.dtype).split(".")[-1]
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def itemsize(self):
|
|
54
|
+
return self.tensor.itemsize
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def shape(self):
|
|
58
|
+
return tuple(self.tensor.shape)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def size(self):
|
|
62
|
+
return self.tensor.nelement()
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def strides(self):
|
|
66
|
+
return self.tensor.stride()
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def empty(
|
|
70
|
+
cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Create an empty tensor of the specified shape and data type on the specified device
|
|
74
|
+
(None, 'cpu', or device id).
|
|
75
|
+
|
|
76
|
+
Note, that the strides, if specified, should correspond to a dense
|
|
77
|
+
(possibly permuted) tensor and MUST NOT overlap.
|
|
78
|
+
Otherwise, the behaviour is not defined.
|
|
79
|
+
"""
|
|
80
|
+
dtype = TorchTensor.name_to_dtype[dtype]
|
|
81
|
+
stream_ctx = contextlib.nullcontext() if stream_holder is None else stream_holder.ctx
|
|
82
|
+
with stream_ctx:
|
|
83
|
+
if strides:
|
|
84
|
+
# note: torch strides is not scaled by bytes
|
|
85
|
+
tensor = torch.empty_strided(shape, strides, dtype=dtype, device=device_id)
|
|
86
|
+
else:
|
|
87
|
+
tensor = torch.empty(shape, dtype=dtype, device=device_id)
|
|
88
|
+
|
|
89
|
+
return cls(tensor)
|
|
90
|
+
|
|
91
|
+
def asndbuffer(self):
|
|
92
|
+
raise RuntimeError("Converting torch tensor to ndbuffer is not supported")
|
|
93
|
+
|
|
94
|
+
def to(self, device_id, stream_holder):
|
|
95
|
+
if not (device_id == "cpu" or isinstance(device_id, int)):
|
|
96
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
97
|
+
|
|
98
|
+
# For h2d the data on the CPU is available and we block on `to()`, so a stream
|
|
99
|
+
# is not needed. It is currently ignored if provided.
|
|
100
|
+
|
|
101
|
+
# For d2h and d2d, we require a stream to ensure that the source data is ready
|
|
102
|
+
# before the copy operation is launched.
|
|
103
|
+
if self.device_id != "cpu" and stream_holder is None:
|
|
104
|
+
raise AssertionError("Internal error: a stream holder should be provided for d2h or d2d copies.")
|
|
105
|
+
|
|
106
|
+
# Always block for h2d and d2h copies to ensure that the copied data is ready
|
|
107
|
+
# for consumption when `to()` return.
|
|
108
|
+
|
|
109
|
+
# For d2d, the `torch.to()` operation is launched on the source device on the
|
|
110
|
+
# specified stream, so this stream must be on the source device. Their
|
|
111
|
+
# implementation ensures correct ordering between the current streams on the
|
|
112
|
+
# source and target devices.
|
|
113
|
+
|
|
114
|
+
blocking = self.device_id == "cpu" or device_id == "cpu"
|
|
115
|
+
|
|
116
|
+
stream_ctx = contextlib.nullcontext() if stream_holder is None else stream_holder.ctx
|
|
117
|
+
with stream_ctx:
|
|
118
|
+
tensor_device = self.tensor.to(device=device_id, non_blocking=not blocking)
|
|
119
|
+
|
|
120
|
+
return TorchTensor(tensor_device)
|
|
121
|
+
|
|
122
|
+
def copy_(self, src, stream_holder):
|
|
123
|
+
"""
|
|
124
|
+
Inplace copy of src (copy the data from src into self).
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
# For d2h and d2d, we require a stream to ensure that the source data is ready
|
|
128
|
+
# before the copy operation is launched.
|
|
129
|
+
if src.device_id != "cpu" and stream_holder is None:
|
|
130
|
+
raise AssertionError("Internal error: a stream holder should be provided for d2h or d2d copies.")
|
|
131
|
+
|
|
132
|
+
stream_ctx = contextlib.nullcontext() if stream_holder is None else stream_holder.ctx
|
|
133
|
+
with stream_ctx:
|
|
134
|
+
self.tensor.copy_(src.tensor)
|
|
135
|
+
|
|
136
|
+
def istensor(self):
|
|
137
|
+
"""
|
|
138
|
+
Check if the object is ndarray-like.
|
|
139
|
+
"""
|
|
140
|
+
return isinstance(self.tensor, torch.Tensor)
|
|
141
|
+
|
|
142
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
143
|
+
if copy:
|
|
144
|
+
raise NotImplementedError("reshape with copy=True not implemented")
|
|
145
|
+
if copy is False:
|
|
146
|
+
return self.__class__(self.tensor.view(shape))
|
|
147
|
+
return self.__class__(self.tensor.reshape(shape))
|
|
148
|
+
|
|
149
|
+
def memory_buffer(self):
|
|
150
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
151
|
+
storage = self.tensor.untyped_storage()
|
|
152
|
+
size = self.size
|
|
153
|
+
v = self.tensor.view(self.shape)
|
|
154
|
+
# TODO: ensure tensor is dense for now, and later support linear
|
|
155
|
+
# memory with constant stride.
|
|
156
|
+
v.set_(storage, self.tensor.storage_offset(), (size,), (1,))
|
|
157
|
+
return TorchTensor(v)
|
|
158
|
+
|
|
159
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
160
|
+
"""
|
|
161
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
162
|
+
shape and strides.
|
|
163
|
+
"""
|
|
164
|
+
assert len(self.shape) == 1, "Internal error."
|
|
165
|
+
storage = self.tensor.untyped_storage()
|
|
166
|
+
t = self.tensor.view(self.shape)
|
|
167
|
+
t.set_(storage, self.tensor.storage_offset(), shape, strides)
|
|
168
|
+
return TorchTensor(t)
|
|
169
|
+
|
|
170
|
+
def _broadcast_to(self, shape):
|
|
171
|
+
reshaped_tensor = torch.broadcast_to(self.tensor, shape)
|
|
172
|
+
return self.__class__(reshaped_tensor)
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def is_conjugate(self) -> bool:
|
|
176
|
+
return self.tensor.is_conj()
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Entry point to using tensors from different libraries seamlessly.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["infer_tensor_package", "wrap_operand", "wrap_operands", "to", "copy_", "TensorHolder", "AnyTensor"]
|
|
10
|
+
|
|
11
|
+
import warnings
|
|
12
|
+
from collections.abc import Sequence
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
from . import formatters
|
|
17
|
+
from .tensor_ifc import AnyTensor, Tensor, TensorHolder
|
|
18
|
+
from .tensor_ifc_numpy import CudaTensor, NumpyTensor
|
|
19
|
+
|
|
20
|
+
_TENSOR_TYPES: dict[str, type[TensorHolder]] = {"numpy": NumpyTensor, "cuda": CudaTensor}
|
|
21
|
+
|
|
22
|
+
_SUPPORTED_PACKAGES = tuple(_TENSOR_TYPES.keys())
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def infer_tensor_package(tensor):
|
|
26
|
+
"""
|
|
27
|
+
Infer the package that defines this tensor.
|
|
28
|
+
"""
|
|
29
|
+
if issubclass(tensor.__class__, np.ndarray):
|
|
30
|
+
return "numpy"
|
|
31
|
+
module = tensor.__class__.__module__
|
|
32
|
+
package = module.split(".")[0]
|
|
33
|
+
maybe_register_package(package)
|
|
34
|
+
return package
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def maybe_register_package(package):
|
|
38
|
+
global _SUPPORTED_PACKAGES
|
|
39
|
+
if package not in _SUPPORTED_PACKAGES:
|
|
40
|
+
global _TENSOR_TYPES
|
|
41
|
+
from .. import memory
|
|
42
|
+
from . import package_wrapper
|
|
43
|
+
|
|
44
|
+
if package == "torch":
|
|
45
|
+
from .package_ifc_torch import TorchPackage
|
|
46
|
+
from .tensor_ifc_torch import TorchTensor
|
|
47
|
+
|
|
48
|
+
_TENSOR_TYPES[package] = TorchTensor
|
|
49
|
+
package_wrapper.PACKAGE[package] = TorchPackage
|
|
50
|
+
memory.lazy_load_torch()
|
|
51
|
+
elif package == "cupy":
|
|
52
|
+
from .package_ifc_cupy import CupyPackage
|
|
53
|
+
from .tensor_ifc_cupy import CupyTensor, HostTensor
|
|
54
|
+
|
|
55
|
+
_TENSOR_TYPES[package] = CupyTensor
|
|
56
|
+
_TENSOR_TYPES["cupy_host"] = HostTensor
|
|
57
|
+
package_wrapper.PACKAGE[package] = CupyPackage
|
|
58
|
+
package_wrapper.PACKAGE["cupy_host"] = CupyPackage
|
|
59
|
+
memory.lazy_load_cupy()
|
|
60
|
+
else:
|
|
61
|
+
message = f"""{package} not supported yet. Currently must be one of ['numpy', 'cupy', 'torch']"""
|
|
62
|
+
raise ValueError(message)
|
|
63
|
+
_SUPPORTED_PACKAGES = tuple(_TENSOR_TYPES.keys())
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def wrap_operand(native_operand: Tensor) -> TensorHolder[Tensor]:
|
|
67
|
+
"""
|
|
68
|
+
Wrap one "native" operand so that package-agnostic API can be used.
|
|
69
|
+
"""
|
|
70
|
+
if isinstance(native_operand, TensorHolder):
|
|
71
|
+
msg = (
|
|
72
|
+
"wrap_operand() is being called unnecessarily because the input is already a TensorHolder. "
|
|
73
|
+
"Only public facing APIs should call wrap_operand(). "
|
|
74
|
+
"Internal APIs should assume the operands are TensorHolder already."
|
|
75
|
+
"Trying to wrap a TensorHolder will become an error in the future."
|
|
76
|
+
)
|
|
77
|
+
warnings.warn(msg, DeprecationWarning)
|
|
78
|
+
return native_operand
|
|
79
|
+
wrapped_operand = _TENSOR_TYPES[infer_tensor_package(native_operand)](native_operand)
|
|
80
|
+
return wrapped_operand
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def check_valid_package(native_operands):
|
|
84
|
+
"""
|
|
85
|
+
Check if the operands belong to one of the supported packages.
|
|
86
|
+
"""
|
|
87
|
+
operands_pkg = [infer_tensor_package(o) for o in native_operands]
|
|
88
|
+
checks = [p in _SUPPORTED_PACKAGES for p in operands_pkg]
|
|
89
|
+
if not all(checks):
|
|
90
|
+
unknown = [f"{location}: {operands_pkg[location]}" for location, predicate in enumerate(checks) if predicate is False]
|
|
91
|
+
unknown = formatters.array2string(unknown)
|
|
92
|
+
message = f"""The operands should be ndarray-like objects from one of {_SUPPORTED_PACKAGES} packages.
|
|
93
|
+
The unsupported operands as a sequence of "position: package" is: \n{unknown}"""
|
|
94
|
+
raise ValueError(message)
|
|
95
|
+
|
|
96
|
+
return operands_pkg
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def check_valid_operand_type(wrapped_operands):
|
|
100
|
+
"""
|
|
101
|
+
Check if the wrapped operands are ndarray-like.
|
|
102
|
+
"""
|
|
103
|
+
istensor = [o.istensor() for o in wrapped_operands]
|
|
104
|
+
if not all(istensor):
|
|
105
|
+
unknown = [
|
|
106
|
+
f"{location}: {type(wrapped_operands[location].tensor)}"
|
|
107
|
+
for location, predicate in enumerate(istensor)
|
|
108
|
+
if predicate is False
|
|
109
|
+
]
|
|
110
|
+
unknown = formatters.array2string(unknown)
|
|
111
|
+
message = f"""The operands should be ndarray-like objects from one of {_SUPPORTED_PACKAGES} packages.
|
|
112
|
+
The unsupported operands as a sequence of "position: type" is: \n{unknown}"""
|
|
113
|
+
raise ValueError(message)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _wrapper_helper(operand: Tensor | TensorHolder, index: int, packages: list[str]) -> TensorHolder[Tensor]:
|
|
117
|
+
if isinstance(operand, TensorHolder):
|
|
118
|
+
msg = (
|
|
119
|
+
"wrap_operands() is being called unnecessarily because at least one input is already a TensorHolder. "
|
|
120
|
+
"Only public facing APIs should call wrap_operands(). "
|
|
121
|
+
"Internal APIs should assume the operands are TensorHolder already."
|
|
122
|
+
"Trying to wrap a TensorHolder will become an error in the future."
|
|
123
|
+
)
|
|
124
|
+
warnings.warn(msg, DeprecationWarning)
|
|
125
|
+
return operand
|
|
126
|
+
return _TENSOR_TYPES[packages[index]](operand)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def wrap_operands(native_operands: Sequence[Tensor]) -> Sequence[TensorHolder[Tensor]]:
|
|
130
|
+
"""
|
|
131
|
+
Wrap the "native" operands so that package-agnostic API can be used.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
operands_pkg = check_valid_package(native_operands)
|
|
135
|
+
|
|
136
|
+
wrapped_operands = tuple(_wrapper_helper(o, i, operands_pkg) for i, o in enumerate(native_operands))
|
|
137
|
+
|
|
138
|
+
check_valid_operand_type(wrapped_operands)
|
|
139
|
+
|
|
140
|
+
return wrapped_operands
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def to(operands: Sequence[TensorHolder], device_id, stream_holder) -> Sequence[TensorHolder]:
|
|
144
|
+
"""
|
|
145
|
+
Copy the wrapped operands to the specified device_id (None or int) and return the
|
|
146
|
+
wrapped operands on the device.
|
|
147
|
+
"""
|
|
148
|
+
assert isinstance(operands, Sequence) and isinstance(operands[0], TensorHolder)
|
|
149
|
+
return tuple(o.to(device_id, stream_holder) for o in operands)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def copy_(src: Sequence[TensorHolder], dest: Sequence[TensorHolder], stream_holder):
|
|
153
|
+
"""
|
|
154
|
+
Copy the wrapped operands in src to the corresponding wrapped operands in dest.
|
|
155
|
+
"""
|
|
156
|
+
for s, d in zip(src, dest, strict=True):
|
|
157
|
+
d.copy_(s, stream_holder=stream_holder)
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Functions to link type names with CUDA data and compute types.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["COMPUTE_TYPE_TO_NAME", "DATA_TYPE_TO_NAME", "NAME_TO_DATA_TYPE", "NAME_TO_COMPUTE_TYPE", "NAME_TO_DATA_WIDTH"]
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
from enum import IntEnum
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ComputeType(IntEnum):
|
|
16
|
+
"""An enumeration of CUDA compute types."""
|
|
17
|
+
|
|
18
|
+
COMPUTE_DEFAULT = 0
|
|
19
|
+
COMPUTE_16F = 1 << 0
|
|
20
|
+
COMPUTE_32F = 1 << 2
|
|
21
|
+
COMPUTE_64F = 1 << 4
|
|
22
|
+
COMPUTE_8U = 1 << 6
|
|
23
|
+
COMPUTE_8I = 1 << 8
|
|
24
|
+
COMPUTE_32U = 1 << 7
|
|
25
|
+
COMPUTE_32I = 1 << 9
|
|
26
|
+
COMPUTE_16BF = 1 << 10
|
|
27
|
+
COMPUTE_TF32 = 1 << 12
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class cudaDataType(IntEnum):
|
|
31
|
+
"""An enumeration of `cudaDataType_t`."""
|
|
32
|
+
|
|
33
|
+
CUDA_R_16F = 2
|
|
34
|
+
CUDA_C_16F = 6
|
|
35
|
+
CUDA_R_16BF = 14
|
|
36
|
+
CUDA_C_16BF = 15
|
|
37
|
+
CUDA_R_32F = 0
|
|
38
|
+
CUDA_C_32F = 4
|
|
39
|
+
CUDA_R_64F = 1
|
|
40
|
+
CUDA_C_64F = 5
|
|
41
|
+
CUDA_R_4I = 16
|
|
42
|
+
CUDA_C_4I = 17
|
|
43
|
+
CUDA_R_4U = 18
|
|
44
|
+
CUDA_C_4U = 19
|
|
45
|
+
CUDA_R_8I = 3
|
|
46
|
+
CUDA_C_8I = 7
|
|
47
|
+
CUDA_R_8U = 8
|
|
48
|
+
CUDA_C_8U = 9
|
|
49
|
+
CUDA_R_16I = 20
|
|
50
|
+
CUDA_C_16I = 21
|
|
51
|
+
CUDA_R_16U = 22
|
|
52
|
+
CUDA_C_16U = 23
|
|
53
|
+
CUDA_R_32I = 10
|
|
54
|
+
CUDA_C_32I = 11
|
|
55
|
+
CUDA_R_32U = 12
|
|
56
|
+
CUDA_C_32U = 13
|
|
57
|
+
CUDA_R_64I = 24
|
|
58
|
+
CUDA_C_64I = 25
|
|
59
|
+
CUDA_R_64U = 26
|
|
60
|
+
CUDA_C_64U = 27
|
|
61
|
+
CUDA_R_8F_E4M3 = 28
|
|
62
|
+
CUDA_R_8F_E5M2 = 29
|
|
63
|
+
CUDA_R_4F_E2M1 = 33 # supported on SM 10.0+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def create_cuda_data_type_map(cuda_data_type_enum_class):
|
|
67
|
+
"""
|
|
68
|
+
Map the data type name to the corresponding CUDA data type.
|
|
69
|
+
"""
|
|
70
|
+
cuda_data_type_pattern = re.compile(r"CUDA_(?P<cr>C|R)_(?P<width>\d+)(?P<type>F|I|U|BF)_?(?P<kind>(E\dM\d)?)")
|
|
71
|
+
|
|
72
|
+
type_code_map = {"i": "int", "u": "uint", "f": "float", "bf": "bfloat"}
|
|
73
|
+
# A map from (width, exponent kind) to qualifiers (finite, unsigned zero, ...) for data
|
|
74
|
+
# types.
|
|
75
|
+
type_qualifier_map = {
|
|
76
|
+
(8, "e4m3"): "fn",
|
|
77
|
+
# FP4: finite-only, packed 2 per byte, see for example:
|
|
78
|
+
# - https://github.com/pytorch/pytorch/issues/146414
|
|
79
|
+
# - https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
|
|
80
|
+
(4, "e2m1"): "fn_x2",
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
complex_types = {"float": "complex", "bfloat": "bcomplex"}
|
|
84
|
+
|
|
85
|
+
cuda_data_type_map = {}
|
|
86
|
+
data_type_width_map = {}
|
|
87
|
+
for d in cuda_data_type_enum_class:
|
|
88
|
+
m = cuda_data_type_pattern.match(d.name)
|
|
89
|
+
|
|
90
|
+
is_complex = m.group("cr").lower() == "c"
|
|
91
|
+
type_code = type_code_map[m.group("type").lower()]
|
|
92
|
+
|
|
93
|
+
# We'll generalize this if and when we support Gaussian integers.
|
|
94
|
+
if is_complex and type_code not in complex_types:
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
width = int(m.group("width"))
|
|
98
|
+
if is_complex:
|
|
99
|
+
width *= 2
|
|
100
|
+
type_code = complex_types[type_code]
|
|
101
|
+
|
|
102
|
+
name = type_code + str(width)
|
|
103
|
+
|
|
104
|
+
# Handle narrow type kinds.
|
|
105
|
+
if width <= 8:
|
|
106
|
+
kind = m.group("kind").lower()
|
|
107
|
+
# Handle type qualifiers for narrow types.
|
|
108
|
+
kind += type_qualifier_map.get((width, kind), "")
|
|
109
|
+
if kind:
|
|
110
|
+
name += "_" + kind
|
|
111
|
+
|
|
112
|
+
cuda_data_type_map[name] = d
|
|
113
|
+
data_type_width_map[name] = width
|
|
114
|
+
|
|
115
|
+
return cuda_data_type_map, data_type_width_map
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def create_cuda_compute_type_map(cuda_compute_type_enum_class):
|
|
119
|
+
"""
|
|
120
|
+
Map the data type name to the corresponding CUDA compute type.
|
|
121
|
+
"""
|
|
122
|
+
cuda_compute_type_pattern = re.compile(r"COMPUTE_(?:(?P<width>\d+)(?P<type>F|I|U|BF)|(?P<tf32>TF32))")
|
|
123
|
+
|
|
124
|
+
type_code_map = {"i": "int", "u": "uint", "f": "float", "bf": "bfloat"}
|
|
125
|
+
|
|
126
|
+
cuda_compute_type_map = {}
|
|
127
|
+
for c in cuda_compute_type_enum_class:
|
|
128
|
+
if c.name == "COMPUTE_DEFAULT":
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
m = cuda_compute_type_pattern.match(c.name)
|
|
132
|
+
|
|
133
|
+
if not m:
|
|
134
|
+
raise ValueError("Internal error - unexpected enum entry")
|
|
135
|
+
|
|
136
|
+
if m.group("tf32"):
|
|
137
|
+
continue
|
|
138
|
+
|
|
139
|
+
name = type_code_map[m.group("type").lower()] + m.group("width")
|
|
140
|
+
cuda_compute_type_map[name] = c
|
|
141
|
+
|
|
142
|
+
# Treat complex types as special case.
|
|
143
|
+
cuda_compute_type_map["bcomplex32"] = cuda_compute_type_enum_class.COMPUTE_16BF
|
|
144
|
+
cuda_compute_type_map["complex32"] = cuda_compute_type_enum_class.COMPUTE_16F
|
|
145
|
+
cuda_compute_type_map["complex64"] = cuda_compute_type_enum_class.COMPUTE_32F
|
|
146
|
+
cuda_compute_type_map["complex128"] = cuda_compute_type_enum_class.COMPUTE_64F
|
|
147
|
+
|
|
148
|
+
return cuda_compute_type_map
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
NAME_TO_DATA_TYPE, NAME_TO_DATA_WIDTH = create_cuda_data_type_map(cudaDataType)
|
|
152
|
+
NAME_TO_ITEM_SIZE = {k: v // 8 for k, v in NAME_TO_DATA_WIDTH.items() if v % 8 == 0}
|
|
153
|
+
DATA_TYPE_TO_NAME = {v: k for k, v in NAME_TO_DATA_TYPE.items()}
|
|
154
|
+
NAME_TO_COMPUTE_TYPE = create_cuda_compute_type_map(ComputeType)
|
|
155
|
+
COMPUTE_TYPE_TO_NAME = {v: k for k, v in NAME_TO_COMPUTE_TYPE.items()}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
FFTW_SUPPORTED_SINGLE = (cudaDataType.CUDA_R_32F, cudaDataType.CUDA_C_32F)
|
|
159
|
+
FFTW_SUPPORTED_DOUBLE = (cudaDataType.CUDA_R_64F, cudaDataType.CUDA_C_64F)
|
|
160
|
+
FFTW_SUPPORTED_FLOAT = (cudaDataType.CUDA_R_32F, cudaDataType.CUDA_R_64F)
|
|
161
|
+
FFTW_SUPPORTED_COMPLEX = (cudaDataType.CUDA_C_32F, cudaDataType.CUDA_C_64F)
|
|
162
|
+
FFTW_SUPPORTED_TYPES = sorted(FFTW_SUPPORTED_SINGLE + FFTW_SUPPORTED_DOUBLE)
|