|
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): |
|
|
|
kDLCPU = 1, |
|
kDLGPU = 2, |
|
kDLCPUPinned = 3, |
|
kDLOpenCL = 4, |
|
kDLVulkan = 7, |
|
kDLMetal = 8, |
|
kDLVPI = 9, |
|
kDLROCM = 10, |
|
kDLExtDev = 12, |
|
kDLOneAPI = 14, |
|
|
|
|
|
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. |
|
""") |
|
|
|
|
|
|
|
|
|
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__() |
|
|
|
|
|
if device[0] in (DLDeviceType.kDLGPU, DLDeviceType.kDLROCM): |
|
stream = torch.cuda.current_stream(f'cuda:{device[1]}') |
|
|
|
|
|
|
|
|
|
|
|
is_cuda = device[0] == DLDeviceType.kDLGPU |
|
|
|
|
|
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: |
|
|
|
dlpack = ext_tensor |
|
return _from_dlpack(dlpack) |
|
|