| from typing import Any | |
| import torch | |
| import enum | |
| from torch._C import _from_dlpack | |
| from torch._C import _to_dlpack as to_dlpack | |
| class DLDeviceType(enum.IntEnum): | |
| # Enums as in DLPack specification (aten/src/ATen/dlpack.h) | |
| kDLCPU = 1, | |
| kDLGPU = 2, | |
| kDLCPUPinned = 3, | |
| kDLOpenCL = 4, | |
| kDLVulkan = 7, | |
| kDLMetal = 8, | |
| kDLVPI = 9, | |
| kDLROCM = 10, | |
| kDLExtDev = 12, | |
| torch._C._add_docstr(to_dlpack, r"""to_dlpack(tensor) -> PyCapsule | |
| Returns an opaque object (a "DLPack capsule") representing the tensor. | |
| .. note:: | |
| ``to_dlpack`` is a legacy DLPack interface. The capsule it returns | |
| cannot be used for anything in Python other than use it as input to | |
| ``from_dlpack``. The more idiomatic use of DLPack is to call | |
| ``from_dlpack`` directly on the tensor object - this works when that | |
| object has a ``__dlpack__`` method, which PyTorch and most other | |
| libraries indeed have now. | |
| .. warning:: | |
| Only call ``from_dlpack`` once per capsule produced with ``to_dlpack``. | |
| Behavior when a capsule is consumed multiple times is undefined. | |
| Args: | |
| tensor: a tensor to be exported | |
| The DLPack capsule shares the tensor's memory. | |
| """) | |
| # TODO: add a typing.Protocol to be able to tell Mypy that only objects with | |
| # __dlpack__ and __dlpack_device__ methods are accepted. | |
| def from_dlpack(ext_tensor: Any) -> 'torch.Tensor': | |
| """from_dlpack(ext_tensor) -> Tensor | |
| Converts a tensor from an external library into a ``torch.Tensor``. | |
| The returned PyTorch tensor will share the memory with the input tensor | |
| (which may have come from another library). Note that in-place operations | |
| will therefore also affect the data of the input tensor. This may lead to | |
| unexpected issues (e.g., other libraries may have read-only flags or | |
| immutable data structures), so the user should only do this if they know | |
| for sure that this is fine. | |
| Args: | |
| ext_tensor (object with ``__dlpack__`` attribute, or a DLPack capsule): | |
| The tensor or DLPack capsule to convert. | |
| If ``ext_tensor`` is a tensor (or ndarray) object, it must support | |
| the ``__dlpack__`` protocol (i.e., have a ``ext_tensor.__dlpack__`` | |
| method). Otherwise ``ext_tensor`` may be a DLPack capsule, which is | |
| an opaque ``PyCapsule`` instance, typically produced by a | |
| ``to_dlpack`` function or method. | |
| Examples:: | |
| >>> import torch.utils.dlpack | |
| >>> t = torch.arange(4) | |
| # Convert a tensor directly (supported in PyTorch >= 1.10) | |
| >>> t2 = torch.from_dlpack(t) | |
| >>> t2[:2] = -1 # show that memory is shared | |
| >>> t2 | |
| tensor([-1, -1, 2, 3]) | |
| >>> t | |
| tensor([-1, -1, 2, 3]) | |
| # The old-style DLPack usage, with an intermediate capsule object | |
| >>> capsule = torch.utils.dlpack.to_dlpack(t) | |
| >>> capsule | |
| <capsule object "dltensor" at ...> | |
| >>> t3 = torch.from_dlpack(capsule) | |
| >>> t3 | |
| tensor([-1, -1, 2, 3]) | |
| >>> t3[0] = -9 # now we're sharing memory between 3 tensors | |
| >>> t3 | |
| tensor([-9, -1, 2, 3]) | |
| >>> t2 | |
| tensor([-9, -1, 2, 3]) | |
| >>> t | |
| tensor([-9, -1, 2, 3]) | |
| """ | |
| if hasattr(ext_tensor, '__dlpack__'): | |
| device = ext_tensor.__dlpack_device__() | |
| # device is either CUDA or ROCm, we need to pass the current | |
| # stream | |
| if device[0] in (DLDeviceType.kDLGPU, DLDeviceType.kDLROCM): | |
| stream = torch.cuda.current_stream('cuda:{}'.format(device[1])) | |
| # cuda_stream is the pointer to the stream and it is a public | |
| # attribute, but it is not documented | |
| # The array API specify that the default legacy stream must be passed | |
| # with a value of 1 for CUDA | |
| # https://data-apis.org/array-api/latest/API_specification/array_object.html?dlpack-self-stream-none#dlpack-self-stream-none # NOQA | |
| is_cuda = device[0] == DLDeviceType.kDLGPU | |
| # Since pytorch is not using PTDS by default, lets directly pass | |
| # the legacy stream | |
| stream_ptr = 1 if is_cuda and stream.cuda_stream == 0 else stream.cuda_stream | |
| dlpack = ext_tensor.__dlpack__(stream=stream_ptr) | |
| else: | |
| dlpack = ext_tensor.__dlpack__() | |
| else: | |
| # Old versions just call the converter | |
| dlpack = ext_tensor | |
| return _from_dlpack(dlpack) |