Source code for torch_lattice.nn.functional.conv.kmap.upsample
from typing import Tuple, Union, Optional
import torch
import torch_lattice
import torch_lattice.backend
from torch_lattice.utils import make_ntuple, make_tensor
from torch_lattice.nn.utils.kernel import get_kernel_offsets
__all__ = ["spupsample_generative"]
[docs]
def spupsample_generative(
_coords: torch.Tensor,
stride: Union[int, Tuple[int, ...]] = 2,
kernel_size: Union[int, Tuple[int, ...]] = 2,
padding: torch.Tensor = 0,
spatial_range: Optional[Tuple[int]] = None,
) -> torch.Tensor:
stride = make_ntuple(stride, ndim=3)
kernel_size = make_ntuple(kernel_size, ndim=3)
padding = make_ntuple(padding, ndim=3)
sample_stride = make_tensor(
stride, dtype=torch.int, device=_coords.device
).unsqueeze(0)
# stride and dilation are both 1
kernel_offsets = get_kernel_offsets(kernel_size, 1, 1, device=_coords.device)
assert (
spatial_range is not None
), "spatial range must be specified in generative mode"
if (
_coords.device.type == "cuda"
and _coords.dtype == torch.int32
and not torch_lattice.tensor.get_allow_negative_coordinates()
and all(p == 0 for p in padding)
and all(stride[k] == kernel_size[k] for k in range(3))
and all(
spatial_range[k + 1]
>= int(_coords[:, k + 1].max().item()) * stride[k] + kernel_size[k]
for k in range(3)
)
and hasattr(torch_lattice.backend, "upsample_generative_cuda")
):
stride_t = make_tensor(stride, dtype=torch.int, device=_coords.device)
return torch_lattice.backend.upsample_generative_cuda(
_coords.contiguous(),
kernel_offsets.contiguous(),
stride_t,
)
coords = _coords.clone()
coords[:, 1:] *= sample_stride
coords = coords.unsqueeze(1).repeat(1, kernel_offsets.size(0), 1)
coords[:, :, 1:] = coords[:, :, 1:] + kernel_offsets.unsqueeze(0)
for i in range(1, coords.size(-1)):
coords[:, :, i].clamp_(min=0, max=spatial_range[i] - 1)
coords = coords.reshape(-1, coords.size(-1))
coords = torch.unique(coords, dim=0)
return coords