nvmath-python 1.0.0__cp314-cp314t-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 +130 -0
- nvmath/_internal/threadsafe.py +106 -0
- nvmath/_internal/utils.py +43 -0
- nvmath/_internal/workspace.py +490 -0
- nvmath/_utils.py +147 -0
- nvmath/bindings/__init__.py +60 -0
- nvmath/bindings/_internal/__init__.pxd +0 -0
- nvmath/bindings/_internal/__init__.py +0 -0
- nvmath/bindings/_internal/common_types.pxd +31 -0
- nvmath/bindings/_internal/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublas.pxd +530 -0
- nvmath/bindings/_internal/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cublasLt.pxd +59 -0
- nvmath/bindings/_internal/cublasMp.pxd +52 -0
- nvmath/bindings/_internal/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cudss.pxd +54 -0
- nvmath/bindings/_internal/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cufft.pxd +70 -0
- nvmath/bindings/_internal/cufftMp.pxd +77 -0
- nvmath/bindings/_internal/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/curand.pxd +42 -0
- nvmath/bindings/_internal/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolver.pxd +15 -0
- nvmath/bindings/_internal/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverDn.pxd +406 -0
- nvmath/bindings/_internal/cusolverMp.pxd +71 -0
- nvmath/bindings/_internal/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusolverSp.pxd +75 -0
- nvmath/bindings/_internal/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparse.pxd +471 -0
- nvmath/bindings/_internal/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cusparseLt.pxd +48 -0
- nvmath/bindings/_internal/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/cutensor.pxd +58 -0
- nvmath/bindings/_internal/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/mathdx.pxd +116 -0
- nvmath/bindings/_internal/nvshmem.pxd +29 -0
- nvmath/bindings/_internal/utils.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/_internal/utils.pxd +174 -0
- nvmath/bindings/_internal/utils.pyi +10 -0
- nvmath/bindings/cublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublas.pxd +558 -0
- nvmath/bindings/cublas.pyi +812 -0
- nvmath/bindings/cublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cublasLt.pxd +109 -0
- nvmath/bindings/cublasLt.pyi +1461 -0
- nvmath/bindings/cublasMp.pxd +85 -0
- nvmath/bindings/cublasMp.pyi +267 -0
- nvmath/bindings/cudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cudss.pxd +98 -0
- nvmath/bindings/cudss.pyi +443 -0
- nvmath/bindings/cufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cufft.pxd +118 -0
- nvmath/bindings/cufft.pyi +301 -0
- nvmath/bindings/cufftMp.pxd +124 -0
- nvmath/bindings/cufftMp.pyi +326 -0
- nvmath/bindings/curand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/curand.pxd +71 -0
- nvmath/bindings/curand.pyi +189 -0
- nvmath/bindings/cusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolver.pxd +62 -0
- nvmath/bindings/cusolver.pyi +320 -0
- nvmath/bindings/cusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverDn.pxd +430 -0
- nvmath/bindings/cusolverDn.pyi +422 -0
- nvmath/bindings/cusolverMp.pxd +98 -0
- nvmath/bindings/cusolverMp.pyi +114 -0
- nvmath/bindings/cusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusolverSp.pxd +95 -0
- nvmath/bindings/cusolverSp.pyi +70 -0
- nvmath/bindings/cusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparse.pxd +546 -0
- nvmath/bindings/cusparse.pyi +1017 -0
- nvmath/bindings/cusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cusparseLt.pxd +99 -0
- nvmath/bindings/cusparseLt.pyi +252 -0
- nvmath/bindings/cutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cutensor.pxd +98 -0
- nvmath/bindings/cutensor.pyi +324 -0
- nvmath/bindings/cycublas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublas.pxd +664 -0
- nvmath/bindings/cycublasLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycublasLt.pxd +1045 -0
- nvmath/bindings/cycublasMp.pxd +171 -0
- nvmath/bindings/cycudss.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycudss.pxd +277 -0
- nvmath/bindings/cycufft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycufft.pxd +333 -0
- nvmath/bindings/cycufftMp.pxd +342 -0
- nvmath/bindings/cycurand.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycurand.pxd +141 -0
- nvmath/bindings/cycusolver.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolver.pxd +137 -0
- nvmath/bindings/cycusolverDn.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverDn.pxd +443 -0
- nvmath/bindings/cycusolverMp.pxd +107 -0
- nvmath/bindings/cycusolverSp.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusolverSp.pxd +93 -0
- nvmath/bindings/cycusparse.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparse.pxd +679 -0
- nvmath/bindings/cycusparseLt.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycusparseLt.pxd +135 -0
- nvmath/bindings/cycutensor.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cycutensor.pxd +189 -0
- nvmath/bindings/cymathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/cymathdx.pxd +552 -0
- nvmath/bindings/cynvshmem.pxd +118 -0
- nvmath/bindings/mathdx.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/mathdx.pxd +182 -0
- nvmath/bindings/mathdx.pyi +1562 -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.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/blas.pxd +237 -0
- nvmath/bindings/nvpl/_internal/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/_internal/fft.pxd +36 -0
- nvmath/bindings/nvpl/blas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/blas.pxd +131 -0
- nvmath/bindings/nvpl/blas.pyi +168 -0
- nvmath/bindings/nvpl/cyblas.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyblas.pxd +280 -0
- nvmath/bindings/nvpl/cyfft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/cyfft.pxd +93 -0
- nvmath/bindings/nvpl/fft.cp314t-win_amd64.pyd +0 -0
- nvmath/bindings/nvpl/fft.pxd +100 -0
- nvmath/bindings/nvpl/fft.pyi +168 -0
- nvmath/bindings/nvshmem.pxd +54 -0
- nvmath/bindings/nvshmem.pyi +191 -0
- nvmath/device/__init__.py +38 -0
- nvmath/device/_deprecated.py +33 -0
- nvmath/device/common.py +315 -0
- nvmath/device/common_backend.py +131 -0
- nvmath/device/common_cuda.py +201 -0
- nvmath/device/common_numba.py +300 -0
- nvmath/device/common_numba_cuda_mlir.py +202 -0
- nvmath/device/common_opaque_tensor.py +201 -0
- nvmath/device/cublasdx.py +1606 -0
- nvmath/device/cublasdx_backend.py +860 -0
- nvmath/device/cublasdx_numba.py +1534 -0
- nvmath/device/cublasdx_numba_cuda_mlir.py +208 -0
- nvmath/device/cufftdx.py +373 -0
- nvmath/device/cufftdx_backend.py +220 -0
- nvmath/device/cufftdx_numba.py +140 -0
- nvmath/device/cufftdx_numba_cuda_mlir.py +79 -0
- nvmath/device/curand_kernel.py +9147 -0
- nvmath/device/cusolverdx.py +2708 -0
- nvmath/device/cusolverdx_backend.py +440 -0
- nvmath/device/cusolverdx_numba.py +567 -0
- nvmath/device/cusolverdx_numba_cuda_mlir.py +604 -0
- nvmath/device/cusolverdx_overload_backend.py +1029 -0
- nvmath/device/llvm_array.py +29 -0
- nvmath/device/random.py +441 -0
- nvmath/device/random_helpers.py +23 -0
- nvmath/device/random_states.py +187 -0
- nvmath/device/types.py +138 -0
- nvmath/device/vector_types_numba.py +259 -0
- nvmath/distributed/__init__.py +200 -0
- nvmath/distributed/_internal/__init__.py +0 -0
- nvmath/distributed/_internal/nccl.py +86 -0
- nvmath/distributed/_internal/nvshmem.py +307 -0
- nvmath/distributed/_internal/symmetric_memory.py +35 -0
- nvmath/distributed/_internal/tensor_ifc.py +70 -0
- nvmath/distributed/_internal/tensor_ifc_cupy.py +68 -0
- nvmath/distributed/_internal/tensor_ifc_host_device.py +172 -0
- nvmath/distributed/_internal/tensor_ifc_numpy.py +46 -0
- nvmath/distributed/_internal/tensor_ifc_torch.py +162 -0
- nvmath/distributed/_internal/tensor_wrapper.py +81 -0
- nvmath/distributed/_utils.py +167 -0
- nvmath/distributed/distribution/__init__.py +30 -0
- nvmath/distributed/distribution/_configuration.py +39 -0
- nvmath/distributed/distribution/distributions.py +1024 -0
- nvmath/distributed/distribution/redistribute.py +1284 -0
- nvmath/distributed/fft/__init__.py +7 -0
- nvmath/distributed/fft/_configuration.py +82 -0
- nvmath/distributed/fft/fft.py +2742 -0
- nvmath/distributed/linalg/__init__.py +22 -0
- nvmath/distributed/linalg/_internal/__init__.py +3 -0
- nvmath/distributed/linalg/_internal/epilog_protocol.py +586 -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 +171 -0
- nvmath/distributed/linalg/advanced/matmulmod.py +3573 -0
- nvmath/distributed/linalg/generic/__init__.py +8 -0
- nvmath/distributed/linalg/generic/_caching.py +66 -0
- nvmath/distributed/linalg/generic/_configuration.py +61 -0
- nvmath/distributed/linalg/generic/_factorization.py +172 -0
- nvmath/distributed/linalg/generic/_initialization.py +966 -0
- nvmath/distributed/linalg/generic/_problem_spec.py +511 -0
- nvmath/distributed/linalg/generic/solvermod.py +1368 -0
- nvmath/distributed/process_group.py +408 -0
- nvmath/fft/__init__.py +7 -0
- nvmath/fft/_configuration.py +189 -0
- nvmath/fft/_exec_utils.py +82 -0
- nvmath/fft/_helpers.py +237 -0
- nvmath/fft/fft.py +3122 -0
- nvmath/internal/__init__.pxd +3 -0
- nvmath/internal/__init__.py +10 -0
- nvmath/internal/_bindings.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_bindings.pxd +18 -0
- nvmath/internal/_device_utils.py +45 -0
- nvmath/internal/_layout/__init__.pxd +3 -0
- nvmath/internal/_layout/__init__.py +7 -0
- nvmath/internal/_layout/_layout.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/_layout/_layout.pxd +1303 -0
- nvmath/internal/_layout/_layout.pyi +1145 -0
- nvmath/internal/enum_utils.py +142 -0
- nvmath/internal/formatters.py +87 -0
- nvmath/internal/mem_limit.py +51 -0
- nvmath/internal/memory.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/memory.pxd +13 -0
- nvmath/internal/memory.pyi +50 -0
- nvmath/internal/ndbuffer/__init__.pxd +3 -0
- nvmath/internal/ndbuffer/__init__.py +9 -0
- nvmath/internal/ndbuffer/_copy_kernel.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_copy_kernel.pxd +10 -0
- nvmath/internal/ndbuffer/_jit.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_jit.pxd +7 -0
- nvmath/internal/ndbuffer/_ndbuffer.cp314t-win_amd64.pyd +0 -0
- nvmath/internal/ndbuffer/_ndbuffer.pxd +40 -0
- nvmath/internal/ndbuffer/_ndbuffer.pyi +463 -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 +242 -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/package_ifc.py +168 -0
- nvmath/internal/package_ifc_cuda.py +57 -0
- nvmath/internal/package_ifc_cupy.py +67 -0
- nvmath/internal/package_ifc_torch.py +69 -0
- nvmath/internal/package_wrapper.py +14 -0
- nvmath/internal/tensor_ifc.py +179 -0
- nvmath/internal/tensor_ifc_cupy.py +234 -0
- nvmath/internal/tensor_ifc_ndbuffer.py +147 -0
- nvmath/internal/tensor_ifc_numpy.py +184 -0
- nvmath/internal/tensor_ifc_torch.py +178 -0
- nvmath/internal/tensor_wrapper.py +160 -0
- nvmath/internal/typemaps.py +113 -0
- nvmath/internal/utils.py +805 -0
- nvmath/linalg/__init__.py +56 -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 +234 -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/solver_utils.py +432 -0
- nvmath/linalg/_internal/typemaps.py +144 -0
- nvmath/linalg/_internal/utils.py +157 -0
- nvmath/linalg/advanced/__init__.py +8 -0
- nvmath/linalg/advanced/_algorithmmod.py +170 -0
- nvmath/linalg/advanced/_configuration.py +351 -0
- nvmath/linalg/advanced/helpers/__init__.py +5 -0
- nvmath/linalg/advanced/helpers/matmul.py +1316 -0
- nvmath/linalg/advanced/matmulmod.py +3734 -0
- nvmath/linalg/generic/__init__.py +53 -0
- nvmath/linalg/generic/_configuration/__init__.py +39 -0
- nvmath/linalg/generic/_configuration/layout.py +263 -0
- nvmath/linalg/generic/_configuration/match.py +734 -0
- nvmath/linalg/generic/_configuration/qualifiers.py +493 -0
- nvmath/linalg/generic/_configuration/solver_configuration.py +59 -0
- nvmath/linalg/generic/_configuration/wrap.py +217 -0
- nvmath/linalg/generic/_dtype.py +15 -0
- nvmath/linalg/generic/matmulmod.py +2094 -0
- nvmath/linalg/generic/solvermod.py +1301 -0
- nvmath/memory.py +279 -0
- nvmath/sparse/__init__.py +38 -0
- nvmath/sparse/_internal/__init__.py +21 -0
- nvmath/sparse/_internal/common_utils.py +147 -0
- nvmath/sparse/_internal/cudss_config_ifc.py +702 -0
- nvmath/sparse/_internal/cudss_data_ifc.py +399 -0
- nvmath/sparse/_internal/cudss_utils.py +506 -0
- nvmath/sparse/_internal/cusparse_utils.py +382 -0
- nvmath/sparse/_internal/sparse_bsc_ifc.py +303 -0
- nvmath/sparse/_internal/sparse_bsr_ifc.py +305 -0
- nvmath/sparse/_internal/sparse_coo_ifc.py +256 -0
- nvmath/sparse/_internal/sparse_csc_ifc.py +268 -0
- nvmath/sparse/_internal/sparse_csr_ifc.py +288 -0
- nvmath/sparse/_internal/sparse_dia_ifc.py +242 -0
- nvmath/sparse/_internal/sparse_format_helpers.py +601 -0
- nvmath/sparse/_internal/sparse_tensor_ifc.py +133 -0
- nvmath/sparse/_internal/sparse_ust_ifc.py +141 -0
- nvmath/sparse/_internal/utils.py +56 -0
- nvmath/sparse/advanced/__init__.py +7 -0
- nvmath/sparse/advanced/_configuration.py +227 -0
- nvmath/sparse/advanced/direct_solver.py +2069 -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 +2353 -0
- nvmath/sparse/ust/__init__.py +7 -0
- nvmath/sparse/ust/_converters.py +422 -0
- nvmath/sparse/ust/_cpp.py +28 -0
- nvmath/sparse/ust/_drawer.py +565 -0
- nvmath/sparse/ust/_emitter.py +1033 -0
- nvmath/sparse/ust/_jit.py +188 -0
- nvmath/sparse/ust/_kernel.py +282 -0
- nvmath/sparse/ust/_utils.py +149 -0
- nvmath/sparse/ust/interfaces/__init__.py +0 -0
- nvmath/sparse/ust/interfaces/torch_interface.py +476 -0
- nvmath/sparse/ust/tensor.py +1016 -0
- nvmath/sparse/ust/tensor_format.py +957 -0
- nvmath/tensor/__init__.py +6 -0
- nvmath/tensor/_configuration.py +120 -0
- nvmath/tensor/_internal/__init__.py +3 -0
- nvmath/tensor/_internal/cutensor_config_ifc.py +279 -0
- nvmath/tensor/_internal/cutensor_utils.py +230 -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 +1900 -0
- nvmath_python-1.0.0.dist-info/METADATA +134 -0
- nvmath_python-1.0.0.dist-info/RECORD +332 -0
- nvmath_python-1.0.0.dist-info/WHEEL +5 -0
- nvmath_python-1.0.0.dist-info/licenses/LICENSE +177 -0
- nvmath_python-1.0.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,234 @@
|
|
|
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 Cupy ndarray objects.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__all__ = ["CupyTensor", "HostTensor"]
|
|
10
|
+
|
|
11
|
+
from collections.abc import Sequence
|
|
12
|
+
|
|
13
|
+
import cupy
|
|
14
|
+
import numpy as np
|
|
15
|
+
from cuda.core import Buffer
|
|
16
|
+
|
|
17
|
+
from . import utils
|
|
18
|
+
from .ndbuffer import NDBuffer
|
|
19
|
+
from .package_ifc import StreamHolder
|
|
20
|
+
from .tensor_ifc import TensorHolder
|
|
21
|
+
from .tensor_ifc_ndbuffer import NDBufferTensor
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class HostTensor(NDBufferTensor):
|
|
25
|
+
"""
|
|
26
|
+
Wraps ndbuffer with data residing on the host.
|
|
27
|
+
It serves as a host counterpart for CupyTensor.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
name = "cupy_host"
|
|
31
|
+
host_tensor_class: type["HostTensor"] # set at the end of the file
|
|
32
|
+
device_tensor_class: type["CupyTensor"] # set at the end of the file
|
|
33
|
+
|
|
34
|
+
def __init__(self, tensor):
|
|
35
|
+
super().__init__(tensor)
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def create_host_from(cls, tensor: TensorHolder, stream_holder: StreamHolder):
|
|
39
|
+
src_nd = tensor.asndbuffer()
|
|
40
|
+
# empty_like (and not empty_numpy_like) is used as we don't need
|
|
41
|
+
# full-fledged numpy array (with proper layout)
|
|
42
|
+
dst_nd = NDBuffer.empty_like(src_nd, device_id="cpu")
|
|
43
|
+
dst_nd.copy_(src_nd, stream=stream_holder)
|
|
44
|
+
return cls(dst_nd)
|
|
45
|
+
|
|
46
|
+
def to(self, device_id, stream_holder):
|
|
47
|
+
if device_id == "cpu":
|
|
48
|
+
return self
|
|
49
|
+
elif isinstance(device_id, int):
|
|
50
|
+
return self.device_tensor_class.create_from_host(self, device_id, stream_holder)
|
|
51
|
+
else:
|
|
52
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class _CupyAllocatorAdapter:
|
|
56
|
+
def allocate(self, size, stream):
|
|
57
|
+
# we accept the stream, because the ndbuffer.empty_like
|
|
58
|
+
# passes it to the allocator, but we don't use it:
|
|
59
|
+
# cupy.cuda.alloc does not accept the stream, we make sure to set
|
|
60
|
+
# the correct current stream when calling ndbuffer.empty_like
|
|
61
|
+
alloc = cupy.cuda.alloc(size)
|
|
62
|
+
return Buffer.from_handle(alloc.ptr, size, owner=alloc)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
_cupy_allocator = _CupyAllocatorAdapter()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class CupyTensor(TensorHolder[cupy.ndarray]):
|
|
69
|
+
"""
|
|
70
|
+
TensorHolder for cupy ndarrays.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
name = "cupy"
|
|
74
|
+
module = cupy
|
|
75
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(
|
|
76
|
+
conversion_function=lambda name: np.dtype(name), exception_type=TypeError
|
|
77
|
+
)
|
|
78
|
+
host_tensor_class: type["HostTensor"] # set at the end of the file
|
|
79
|
+
device_tensor_class: type["CupyTensor"] # set at the end of the file
|
|
80
|
+
|
|
81
|
+
def __init__(self, tensor):
|
|
82
|
+
super().__init__(tensor)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def data_ptr(self):
|
|
86
|
+
return self.tensor.data.ptr
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def device(self):
|
|
90
|
+
return "cuda"
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def device_id(self):
|
|
94
|
+
return self.tensor.device.id
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def dtype(self):
|
|
98
|
+
"""Name of the data type"""
|
|
99
|
+
return self.tensor.dtype.name
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def itemsize(self):
|
|
103
|
+
return self.tensor.itemsize
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def shape(self):
|
|
107
|
+
return tuple(self.tensor.shape)
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def size(self):
|
|
111
|
+
return self.tensor.size
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def strides(self):
|
|
115
|
+
return tuple(stride_in_bytes // self.tensor.itemsize for stride_in_bytes in self.tensor.strides)
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def empty(
|
|
119
|
+
cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
|
|
120
|
+
):
|
|
121
|
+
"""
|
|
122
|
+
Create an empty tensor of the specified shape and data type.
|
|
123
|
+
|
|
124
|
+
Note, that the strides, if specified, MUST correspond to a dense (possibly permuted)
|
|
125
|
+
tensor, otherwise the created tensor may be corrupted.
|
|
126
|
+
"""
|
|
127
|
+
assert isinstance(device_id, int), "Internal Error: Cupy tensors must be allocated with an integer device_id."
|
|
128
|
+
dtype = CupyTensor.name_to_dtype[dtype]
|
|
129
|
+
|
|
130
|
+
# When using the strides, we need an explicit allocation (see below).
|
|
131
|
+
# If the strides are simple enough, we can still avoid this overhead.
|
|
132
|
+
order = "C"
|
|
133
|
+
if strides is not None:
|
|
134
|
+
if len(strides) == 1 and strides[0] == 1:
|
|
135
|
+
strides = None
|
|
136
|
+
elif len(strides) == 2:
|
|
137
|
+
if strides[0] == 1 and strides[1] == shape[0]:
|
|
138
|
+
strides = None
|
|
139
|
+
order = "F"
|
|
140
|
+
elif strides[0] == shape[1] and strides[1] == 1:
|
|
141
|
+
strides = None
|
|
142
|
+
|
|
143
|
+
assert isinstance(stream_holder, StreamHolder), "Internal Error: CupyTensors must be allocated on a stream."
|
|
144
|
+
with utils.device_ctx(device_id), stream_holder.ctx:
|
|
145
|
+
if strides:
|
|
146
|
+
# need an explicit allocation due to cupy/cupy#7818
|
|
147
|
+
size = dtype.itemsize
|
|
148
|
+
for s in shape:
|
|
149
|
+
size = size * s
|
|
150
|
+
ptr = cupy.cuda.alloc(size)
|
|
151
|
+
# when strides is not None, it should be of unit counts not bytes
|
|
152
|
+
strides = tuple(s * dtype.itemsize for s in strides)
|
|
153
|
+
tensor = cupy.ndarray(shape, dtype=dtype, strides=strides, memptr=ptr)
|
|
154
|
+
else:
|
|
155
|
+
tensor = cupy.ndarray(shape, dtype=dtype, order=order)
|
|
156
|
+
|
|
157
|
+
return cls(tensor)
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def create_from_host(cls, tensor: TensorHolder, device_id: int, stream_holder: StreamHolder):
|
|
161
|
+
with utils.device_ctx(device_id), stream_holder.ctx:
|
|
162
|
+
src_nd = tensor.asndbuffer()
|
|
163
|
+
dst_nd = NDBuffer.empty_like(src_nd, device_id=device_id, stream=stream_holder, memory_resource=_cupy_allocator)
|
|
164
|
+
dst_nd.copy_(src_nd, stream=stream_holder)
|
|
165
|
+
dst = cupy.ndarray(dst_nd.shape, dtype=dst_nd.dtype_name, strides=dst_nd.strides_in_bytes, memptr=dst_nd.data.owner)
|
|
166
|
+
return cls(dst)
|
|
167
|
+
|
|
168
|
+
def asndbuffer(self):
|
|
169
|
+
return NDBuffer.from_cupy(self.tensor)
|
|
170
|
+
|
|
171
|
+
def to(self, device_id, stream_holder):
|
|
172
|
+
if device_id == "cpu":
|
|
173
|
+
with utils.device_ctx(self.device_id):
|
|
174
|
+
return self.host_tensor_class.create_host_from(self, stream_holder)
|
|
175
|
+
elif device_id == self.device_id:
|
|
176
|
+
return self
|
|
177
|
+
elif isinstance(device_id, int):
|
|
178
|
+
raise ValueError(f"Unsupported copy between different devices {self.device_id} and {device_id}.")
|
|
179
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
180
|
+
|
|
181
|
+
def copy_(self, src, stream_holder):
|
|
182
|
+
"""
|
|
183
|
+
Inplace copy of src (copy the data from src into self).
|
|
184
|
+
"""
|
|
185
|
+
with utils.device_ctx(self.device_id):
|
|
186
|
+
self.asndbuffer().copy_(src.asndbuffer(), stream=stream_holder)
|
|
187
|
+
|
|
188
|
+
def istensor(self):
|
|
189
|
+
"""
|
|
190
|
+
Check if the object is ndarray-like.
|
|
191
|
+
"""
|
|
192
|
+
return isinstance(self.tensor, cupy.ndarray)
|
|
193
|
+
|
|
194
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
195
|
+
if copy:
|
|
196
|
+
raise NotImplementedError("reshape with copy=True not implemented")
|
|
197
|
+
if copy is False:
|
|
198
|
+
try:
|
|
199
|
+
reshaped_tensor = self.tensor.view()
|
|
200
|
+
reshaped_tensor.shape = shape
|
|
201
|
+
except AttributeError as e:
|
|
202
|
+
raise ValueError(
|
|
203
|
+
f"Could not reshape cupy array without copy: current shape={self.shape}, new shape={shape}"
|
|
204
|
+
) from e
|
|
205
|
+
else:
|
|
206
|
+
reshaped_tensor = self.tensor.reshape(shape)
|
|
207
|
+
return self.__class__(reshaped_tensor)
|
|
208
|
+
|
|
209
|
+
def memory_buffer(self):
|
|
210
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
211
|
+
m = cupy.cuda.UnownedMemory(self.data_ptr, self.size * self.itemsize, owner=self.tensor, device_id=self.device_id)
|
|
212
|
+
p = cupy.cuda.MemoryPointer(m, 0)
|
|
213
|
+
# TODO: ensure tensor is dense for now, and later support linear
|
|
214
|
+
# memory with constant stride.
|
|
215
|
+
t = cupy.ndarray(shape=(self.size,), dtype=self.dtype, memptr=p)
|
|
216
|
+
return CupyTensor(t)
|
|
217
|
+
|
|
218
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
219
|
+
"""
|
|
220
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
221
|
+
shape and strides.
|
|
222
|
+
"""
|
|
223
|
+
assert len(self.shape) == 1, "Internal error."
|
|
224
|
+
m = cupy.cuda.UnownedMemory(self.data_ptr, self.size * self.itemsize, owner=self.tensor)
|
|
225
|
+
p = cupy.cuda.MemoryPointer(m, 0)
|
|
226
|
+
strides = [s * self.itemsize for s in strides]
|
|
227
|
+
t = cupy.ndarray(shape=shape, dtype=self.dtype, memptr=p, strides=strides)
|
|
228
|
+
return CupyTensor(t)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
CupyTensor.host_tensor_class = HostTensor
|
|
232
|
+
HostTensor.host_tensor_class = HostTensor
|
|
233
|
+
CupyTensor.device_tensor_class = CupyTensor
|
|
234
|
+
HostTensor.device_tensor_class = CupyTensor
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
TensorHolder implementation that adapts ndbuffer for use with
|
|
7
|
+
the tensor_ifc interface. The class is meant for internal use only
|
|
8
|
+
(e.g. for internal operands of host APIs), but the NDBufferTensor
|
|
9
|
+
or underlying ndbuffer should never be returned to the user, because
|
|
10
|
+
1. the ndbuffer is opaque, i.e. it missies most of typical tensor functionality, and
|
|
11
|
+
2. we make no guarantees about the ndbuffer's API stability.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__all__ = ["NDBufferTensor"]
|
|
15
|
+
|
|
16
|
+
from collections.abc import Sequence
|
|
17
|
+
|
|
18
|
+
from . import ndbuffer, typemaps, utils
|
|
19
|
+
from .ndbuffer import NDBuffer, StridedLayout
|
|
20
|
+
from .package_ifc import StreamHolder
|
|
21
|
+
from .tensor_ifc import TensorHolder
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class NDBufferTensor(TensorHolder[NDBuffer]):
|
|
25
|
+
"""
|
|
26
|
+
TensorHolder for ndbuffer ndarrays.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
name = "ndbuffer"
|
|
30
|
+
module = ndbuffer
|
|
31
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(conversion_function=lambda name: name, exception_type=TypeError)
|
|
32
|
+
|
|
33
|
+
def __init__(self, tensor):
|
|
34
|
+
super().__init__(tensor)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def data_ptr(self):
|
|
38
|
+
return self.tensor.data_ptr
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def device(self):
|
|
42
|
+
return self.tensor.device
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def device_id(self):
|
|
46
|
+
return self.tensor.device_id
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def dtype(self):
|
|
50
|
+
"""Name of the data type"""
|
|
51
|
+
return self.tensor.dtype_name
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def itemsize(self):
|
|
55
|
+
return self.tensor.itemsize
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def shape(self):
|
|
59
|
+
return self.tensor.shape
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def size(self):
|
|
63
|
+
return self.tensor.size
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def strides(self):
|
|
67
|
+
return self.tensor.strides
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def empty(
|
|
71
|
+
cls, shape, device_id="cpu", *, dtype="float32", strides=None, stream_holder: StreamHolder | None = None, **context
|
|
72
|
+
):
|
|
73
|
+
"""
|
|
74
|
+
Create an empty tensor of the specified shape and data type.
|
|
75
|
+
|
|
76
|
+
Note, that the strides, if specified, MUST correspond to a dense (possibly permuted)
|
|
77
|
+
tensor, otherwise the created tensor may be corrupted.
|
|
78
|
+
"""
|
|
79
|
+
layout = StridedLayout(shape, strides, typemaps.NAME_TO_ITEM_SIZE[dtype])
|
|
80
|
+
if device_id == "cpu":
|
|
81
|
+
tensor = NDBuffer.empty(layout, dtype, "cpu", stream=stream_holder, **context)
|
|
82
|
+
else:
|
|
83
|
+
assert isinstance(device_id, int), "Internal Error: Cuda tensors must be allocated with an integer device_id."
|
|
84
|
+
with utils.device_ctx(device_id):
|
|
85
|
+
tensor = NDBuffer.empty(layout, dtype, device_id, stream=stream_holder, **context)
|
|
86
|
+
return cls(tensor)
|
|
87
|
+
|
|
88
|
+
def asndbuffer(self):
|
|
89
|
+
return self.tensor
|
|
90
|
+
|
|
91
|
+
def to(self, device_id, stream_holder):
|
|
92
|
+
src_device_id = self.tensor.device_id
|
|
93
|
+
if src_device_id == device_id:
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
if stream_holder is None:
|
|
97
|
+
raise ValueError("Stream holder is required for h2d/d2h transfers.")
|
|
98
|
+
|
|
99
|
+
if device_id == "cpu":
|
|
100
|
+
with utils.device_ctx(src_device_id):
|
|
101
|
+
tensor = NDBuffer.empty_like(self.tensor, device_id="cpu", stream=stream_holder)
|
|
102
|
+
tensor.copy_(self.tensor, stream=stream_holder)
|
|
103
|
+
else:
|
|
104
|
+
with utils.device_ctx(device_id):
|
|
105
|
+
tensor = NDBuffer.empty_like(self.tensor, device_id=device_id, stream=stream_holder)
|
|
106
|
+
tensor.copy_(self.tensor, stream=stream_holder)
|
|
107
|
+
|
|
108
|
+
return NDBufferTensor(tensor)
|
|
109
|
+
|
|
110
|
+
def copy_(self, src, stream_holder):
|
|
111
|
+
"""
|
|
112
|
+
Inplace copy of src (copy the data from src into self).
|
|
113
|
+
"""
|
|
114
|
+
device_id = self.tensor.device_id
|
|
115
|
+
src_nd = src.asndbuffer()
|
|
116
|
+
if device_id == "cpu":
|
|
117
|
+
device_id = src_nd.device_id
|
|
118
|
+
if device_id == "cpu":
|
|
119
|
+
self.tensor.copy_(src_nd, stream=stream_holder)
|
|
120
|
+
else:
|
|
121
|
+
with utils.device_ctx(device_id):
|
|
122
|
+
self.tensor.copy_(src_nd, stream=stream_holder)
|
|
123
|
+
|
|
124
|
+
def istensor(self):
|
|
125
|
+
"""
|
|
126
|
+
Check if the object is ndarray-like.
|
|
127
|
+
"""
|
|
128
|
+
return isinstance(self.tensor, NDBuffer)
|
|
129
|
+
|
|
130
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
131
|
+
if copy:
|
|
132
|
+
raise NotImplementedError("Reshape with copy is not supported for ndbuffer")
|
|
133
|
+
return self.__class__(self.tensor.reshape(shape))
|
|
134
|
+
|
|
135
|
+
def memory_buffer(self):
|
|
136
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
137
|
+
layout = StridedLayout.dense(self.size, itemsize=self.itemsize)
|
|
138
|
+
return self.__class__(self.tensor.as_strided(layout))
|
|
139
|
+
|
|
140
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
141
|
+
"""
|
|
142
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
143
|
+
shape and strides.
|
|
144
|
+
"""
|
|
145
|
+
assert len(self.shape) == 1, "Internal error."
|
|
146
|
+
layout = StridedLayout(shape, strides, itemsize=self.itemsize)
|
|
147
|
+
return self.__class__(self.tensor.as_strided(layout))
|
|
@@ -0,0 +1,184 @@
|
|
|
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
|
|
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
|
+
device_tensor_class: type["CudaTensor"] # set once CudaTensor is defined
|
|
33
|
+
|
|
34
|
+
def __init__(self, tensor):
|
|
35
|
+
super().__init__(tensor)
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def create_from_host(cls, tensor: TensorHolder, device_id: int, stream_holder: StreamHolder):
|
|
39
|
+
with utils.device_ctx(device_id):
|
|
40
|
+
src_ndbuffer = tensor.asndbuffer()
|
|
41
|
+
dst_ndbuffer = NDBuffer.empty_like(src_ndbuffer, device_id=device_id, stream=stream_holder)
|
|
42
|
+
dst_ndbuffer.copy_(src_ndbuffer, stream=stream_holder)
|
|
43
|
+
return cls(dst_ndbuffer)
|
|
44
|
+
|
|
45
|
+
def to(self, device_id, stream_holder):
|
|
46
|
+
if device_id == "cpu":
|
|
47
|
+
with utils.device_ctx(self.device_id):
|
|
48
|
+
dst = self.host_tensor_class.create_host_from(self, stream_holder)
|
|
49
|
+
return dst
|
|
50
|
+
elif device_id == self.device_id:
|
|
51
|
+
return self
|
|
52
|
+
elif isinstance(device_id, int):
|
|
53
|
+
raise ValueError(f"Unsupported copy between different devices {self.device_id} and {device_id}.")
|
|
54
|
+
else:
|
|
55
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class NumpyTensor(TensorHolder[npt.NDArray]):
|
|
59
|
+
"""
|
|
60
|
+
TensorHolder for numpy ndarrays.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
name = "numpy"
|
|
64
|
+
module = numpy
|
|
65
|
+
name_to_dtype = TensorHolder.create_name_dtype_map(
|
|
66
|
+
conversion_function=lambda name: numpy.dtype(name), exception_type=TypeError
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
host_tensor_class: type["NumpyTensor"] # set once NumpyTensor is defined
|
|
70
|
+
device_tensor_class: type["CudaTensor"] # set once CudaTensor is defined
|
|
71
|
+
|
|
72
|
+
def __init__(self, tensor):
|
|
73
|
+
super().__init__(tensor)
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def data_ptr(self):
|
|
77
|
+
return self.tensor.ctypes.data
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def device(self):
|
|
81
|
+
return "cpu"
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def device_id(self):
|
|
85
|
+
return "cpu"
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def dtype(self):
|
|
89
|
+
"""Name of the data type"""
|
|
90
|
+
return self.tensor.dtype.name
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def itemsize(self):
|
|
94
|
+
return self.tensor.itemsize
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def empty(cls, shape, device_id="cpu", *, dtype="float32", strides=None, **context):
|
|
98
|
+
"""
|
|
99
|
+
Create an empty tensor of the specified shape and data type.
|
|
100
|
+
"""
|
|
101
|
+
assert device_id == "cpu", "Internal Error: Numpy tensors must be allocated with device_id='cpu'"
|
|
102
|
+
dtype = NumpyTensor.name_to_dtype[dtype]
|
|
103
|
+
# when strides is not None, it should be of unit counts not bytes
|
|
104
|
+
return cls(
|
|
105
|
+
cls.module.ndarray(shape, dtype=dtype, strides=(tuple(s * dtype.itemsize for s in strides) if strides else None))
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def create_host_from(cls, tensor: TensorHolder, stream_holder: StreamHolder):
|
|
110
|
+
src_nd = tensor.asndbuffer()
|
|
111
|
+
dst_nd = NDBuffer.empty_like(src_nd, device_id="cpu", stream=stream_holder)
|
|
112
|
+
dst_nd.copy_(src_nd, stream=stream_holder)
|
|
113
|
+
return cls(dst_nd.as_numpy())
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def shape(self):
|
|
117
|
+
return tuple(self.tensor.shape)
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def size(self):
|
|
121
|
+
return self.tensor.size
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def strides(self):
|
|
125
|
+
return tuple(stride_in_bytes // self.tensor.itemsize for stride_in_bytes in self.tensor.strides)
|
|
126
|
+
|
|
127
|
+
def asndbuffer(self):
|
|
128
|
+
return NDBuffer.from_numpy(self.tensor)
|
|
129
|
+
|
|
130
|
+
def to(self, device_id, stream_holder):
|
|
131
|
+
if device_id == "cpu":
|
|
132
|
+
return self
|
|
133
|
+
elif isinstance(device_id, int):
|
|
134
|
+
dst = self.device_tensor_class.create_from_host(self, device_id, stream_holder)
|
|
135
|
+
return dst
|
|
136
|
+
else:
|
|
137
|
+
raise ValueError(f"The device must be specified as an integer or 'cpu', not '{device_id}'.")
|
|
138
|
+
|
|
139
|
+
def copy_(self, src, stream_holder):
|
|
140
|
+
match src.name:
|
|
141
|
+
case "numpy":
|
|
142
|
+
numpy.copyto(self.tensor, src.tensor)
|
|
143
|
+
case _:
|
|
144
|
+
with utils.device_ctx(src.device_id):
|
|
145
|
+
self.asndbuffer().copy_(src.asndbuffer(), stream=stream_holder)
|
|
146
|
+
|
|
147
|
+
def istensor(self):
|
|
148
|
+
"""
|
|
149
|
+
Check if the object is ndarray-like.
|
|
150
|
+
"""
|
|
151
|
+
return isinstance(self.tensor, numpy.ndarray)
|
|
152
|
+
|
|
153
|
+
def reshape(self, shape: Sequence[int], *, copy: bool | None = None):
|
|
154
|
+
if int(numpy.__version__.split(".")[0]) < 2:
|
|
155
|
+
return self.__class__(numpy.reshape(self.tensor, shape))
|
|
156
|
+
else:
|
|
157
|
+
return self.__class__(numpy.reshape(self.tensor, shape, copy=copy))
|
|
158
|
+
|
|
159
|
+
def memory_buffer(self):
|
|
160
|
+
"""Creates a view of the memory buffer as a 1D tensor."""
|
|
161
|
+
t = self.tensor
|
|
162
|
+
# TODO: ensure tensor is dense for now, and later support linear
|
|
163
|
+
# memory with constant stride.
|
|
164
|
+
v = NumpyTensor(t.ravel(order="K"))
|
|
165
|
+
assert v.data_ptr == self.data_ptr, "Internal error."
|
|
166
|
+
return v
|
|
167
|
+
|
|
168
|
+
def memory_buffer_to_tensor(self, shape, strides):
|
|
169
|
+
"""
|
|
170
|
+
Creates a N-D tensor view of the memory buffer according to the specified
|
|
171
|
+
shape and strides.
|
|
172
|
+
"""
|
|
173
|
+
assert len(self.shape) == 1, "Internal error."
|
|
174
|
+
t = self.tensor
|
|
175
|
+
strides = [s * self.itemsize for s in strides]
|
|
176
|
+
v = NumpyTensor(numpy.lib.stride_tricks.as_strided(t, shape=shape, strides=strides))
|
|
177
|
+
assert v.data_ptr == self.data_ptr, "Internal error."
|
|
178
|
+
return v
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
NumpyTensor.host_tensor_class = NumpyTensor
|
|
182
|
+
CudaTensor.host_tensor_class = NumpyTensor
|
|
183
|
+
NumpyTensor.device_tensor_class = CudaTensor
|
|
184
|
+
CudaTensor.device_tensor_class = CudaTensor
|