Skip to content

PNTensor

danling.tensors.pn_tensor

[PNTensor][] (Potential Nested Tensor) — a torch.Tensor subclass that collates into [NestedTensor][nested_tensor.NestedTensor] via PyTorch DataLoader after importing [danling.tensors][].

PNTensor

Bases: Tensor

A tensor wrapper that can be collated into NestedTensor with PyTorch DataLoader.

PNTensor (Potential Nested Tensor) seamlessly bridges the gap between individual tensors and batched NestedTensor objects in PyTorch workflows. It’s designed specifically to work with PyTorch’s DataLoader collation mechanism, allowing datasets to return variable-length tensors that can be combined into a NestedTensor when batched.

The class provides three properties that mirror those of NestedTensor: - .tensor: The tensor itself (self) - .mask: A tensor of ones with the same shape as self - .concat: The tensor itself (self)

Examples:

Basic usage with PyTorch DataLoader:

Python Console Session
>>> from torch.utils.data import Dataset, DataLoader
>>> from danling.tensors import PNTensor
>>> class VariableLengthDataset(Dataset):
...     def __init__(self, data):
...         self.data = data
...     def __len__(self):
...         return len(self.data)
...     def __getitem__(self, idx):
...         return PNTensor(self.data[idx])
>>> # Create a dataset with variable-length sequences
>>> dataset = VariableLengthDataset([[1, 2, 3], [4, 5], [6, 7, 8, 9]])
>>> dataloader = DataLoader(dataset, batch_size=3)
>>> # The DataLoader produces NestedTensor batches by default for PNTensor
>>> batch = next(iter(dataloader))
>>> batch
NestedTensor([
    [1., 2., 3.],
    [4., 5.],
    [6., 7., 8., 9.]
])

Using PNTensor directly:

Python Console Session
1
2
3
4
5
6
7
>>> tensor = PNTensor([1, 2, 3])
>>> tensor
PNTensor([1., 2., 3.])
>>> tensor.tensor
PNTensor([1., 2., 3.])
>>> tensor.mask
PNTensor([True, True, True])
Source code in danling/tensors/pn_tensor.py
Python
class PNTensor(Tensor):
    r"""
    A tensor wrapper that can be collated into NestedTensor with PyTorch DataLoader.

    `PNTensor` (Potential Nested Tensor) seamlessly bridges the gap between individual tensors
    and batched `NestedTensor` objects in PyTorch workflows. It's designed specifically to work
    with PyTorch's DataLoader collation mechanism, allowing datasets to return variable-length
    tensors that can be combined into a `NestedTensor` when batched.

    The class provides three properties that mirror those of NestedTensor:
    - `.tensor`: The tensor itself (self)
    - `.mask`: A tensor of ones with the same shape as self
    - `.concat`: The tensor itself (self)

    Attributes:
        Inherits all attributes from torch.Tensor

    Methods:
        Inherits all methods from torch.Tensor

    Examples:
        Basic usage with PyTorch DataLoader:

        >>> from torch.utils.data import Dataset, DataLoader
        >>> from danling.tensors import PNTensor
        >>> class VariableLengthDataset(Dataset):
        ...     def __init__(self, data):
        ...         self.data = data
        ...     def __len__(self):
        ...         return len(self.data)
        ...     def __getitem__(self, idx):
        ...         return PNTensor(self.data[idx])
        >>> # Create a dataset with variable-length sequences
        >>> dataset = VariableLengthDataset([[1, 2, 3], [4, 5], [6, 7, 8, 9]])
        >>> dataloader = DataLoader(dataset, batch_size=3)
        >>> # The DataLoader produces NestedTensor batches by default for PNTensor
        >>> batch = next(iter(dataloader))
        >>> batch
        NestedTensor([
            [1., 2., 3.],
            [4., 5.],
            [6., 7., 8., 9.]
        ])

        Using PNTensor directly:

        >>> tensor = PNTensor([1, 2, 3])
        >>> tensor
        PNTensor([1., 2., 3.])
        >>> tensor.tensor
        PNTensor([1., 2., 3.])
        >>> tensor.mask
        PNTensor([True, True, True])
    """

    @property
    def tensor(self) -> Tensor:
        r"""
        Identical to `self`.

        Returns:
            (torch.Tensor):

        Examples:
            >>> tensor = torch.tensor([1, 2, 3])
            >>> pn_tensor = PNTensor([1, 2, 3])
            >>> bool((tensor == pn_tensor).all())
            True
            >>> bool((tensor == pn_tensor.tensor).all())
            True
        """

        return self

    @property
    def mask(self) -> Tensor:
        r"""
        All-True boolean mask (PNTensor has no padding).

        Returns a stride-0 expanded view — no memory allocation beyond a scalar.

        Returns:
            (torch.Tensor):

        Examples:
            >>> tensor = torch.tensor([1, 2, 3])
            >>> pn_tensor = PNTensor([1, 2, 3])
            >>> bool((pn_tensor.mask == torch.ones_like(pn_tensor)).all().item())
            True
        """

        return torch.ones((), dtype=torch.bool, device=self.device).expand_as(self)

    @property
    def concat(self) -> Tensor:
        r"""
        Identical to `self`.

        Returns:
            (torch.Tensor):

        Examples:
            >>> pn_tensor = PNTensor([1, 2, 3])
            >>> bool((pn_tensor == pn_tensor.concat).all())
            True
        """

        return self

    def new_empty(self, *args, **kwargs):
        r"""Return a new empty PNTensor with the same type."""
        return PNTensor(super().new_empty(*args, **kwargs))

tensor property

Python
tensor: Tensor

Identical to self.

Returns:

Type Description
Tensor

Examples:

Python Console Session
1
2
3
4
5
6
>>> tensor = torch.tensor([1, 2, 3])
>>> pn_tensor = PNTensor([1, 2, 3])
>>> bool((tensor == pn_tensor).all())
True
>>> bool((tensor == pn_tensor.tensor).all())
True

mask property

Python
mask: Tensor

All-True boolean mask (PNTensor has no padding).

Returns a stride-0 expanded view — no memory allocation beyond a scalar.

Returns:

Type Description
Tensor

Examples:

Python Console Session
1
2
3
4
>>> tensor = torch.tensor([1, 2, 3])
>>> pn_tensor = PNTensor([1, 2, 3])
>>> bool((pn_tensor.mask == torch.ones_like(pn_tensor)).all().item())
True

concat property

Python
concat: Tensor

Identical to self.

Returns:

Type Description
Tensor

Examples:

Python Console Session
1
2
3
>>> pn_tensor = PNTensor([1, 2, 3])
>>> bool((pn_tensor == pn_tensor.concat).all())
True

new_empty

Python
new_empty(*args, **kwargs)

Return a new empty PNTensor with the same type.

Source code in danling/tensors/pn_tensor.py
Python
def new_empty(self, *args, **kwargs):
    r"""Return a new empty PNTensor with the same type."""
    return PNTensor(super().new_empty(*args, **kwargs))

tensor

Python
tensor(
    data: Any,
    dtype=None,
    device=None,
    requires_grad: bool = False,
    pin_memory: bool = False,
) -> PNTensor

Create a PNTensor from data, similar to torch.tensor() but returning a PNTensor.

This function is a convenient way to create PNTensor objects that can be collated into NestedTensor when used with PyTorch DataLoader after importing danling.tensors. The interface mirrors torch.tensor() to make it easy to switch between regular tensors and PNTensors.

Parameters:

Name Type Description Default

data

Any

Initial data for the tensor. Can be a list, tuple, NumPy ndarray, scalar, etc.

required

dtype

Desired data type of the returned tensor.

None

device

Device on which to place the tensor.

None

requires_grad

bool

If autograd should record operations on the returned tensor.

False

pin_memory

bool

If True, the tensor will be allocated in pinned memory.

False

Returns:

Name Type Description
PNTensor PNTensor

A tensor wrapper for NestedTensor-oriented collation

Examples:

Python Console Session
1
2
3
4
>>> from danling.tensors import tensor
>>> t = tensor([1, 2, 3])
>>> t
PNTensor([1, 2, 3])
Source code in danling/tensors/pn_tensor.py
Python
def tensor(data: Any, dtype=None, device=None, requires_grad: bool = False, pin_memory: bool = False) -> PNTensor:
    r"""
    Create a PNTensor from data, similar to torch.tensor() but returning a PNTensor.

    This function is a convenient way to create PNTensor objects that can be
    collated into NestedTensor when used with PyTorch DataLoader after importing
    ``danling.tensors``. The interface mirrors torch.tensor() to make it easy to
    switch between regular tensors and PNTensors.

    Args:
        data: Initial data for the tensor. Can be a list, tuple, NumPy ndarray, scalar, etc.
        dtype: Desired data type of the returned tensor.
        device: Device on which to place the tensor.
        requires_grad: If autograd should record operations on the returned tensor.
        pin_memory: If True, the tensor will be allocated in pinned memory.

    Returns:
        PNTensor: A tensor wrapper for NestedTensor-oriented collation

    Examples:
        >>> from danling.tensors import tensor
        >>> t = tensor([1, 2, 3])
        >>> t
        PNTensor([1, 2, 3])
    """
    return PNTensor(torch.tensor(data, dtype=dtype, device=device, requires_grad=requires_grad, pin_memory=pin_memory))