Shortcuts

Source code for catalyst.data.transforms

# based on https://github.com/pytorch/vision
import numpy as np

import torch

_IMAGENET_STD = (0.229, 0.224, 0.225)
_IMAGENET_MEAN = (0.485, 0.456, 0.406)


def to_tensor(pic: np.ndarray) -> torch.Tensor:
    """Convert ``numpy.ndarray`` to tensor.

    Args:
        pic (PIL Image or numpy.ndarray): Image to be converted to tensor.

    Returns:
        torch.Tensor: Converted image.

    Raises:
        TypeError: if `pic` is not np.ndarray
        ValueError: if `pic` is not 2/3 dimensional.
    """
    if not isinstance(pic, np.ndarray):
        raise TypeError(f"pic should be ndarray. Got {type(pic)}")
    if pic.ndim not in {2, 3}:
        raise ValueError(f"pic should be 2/3 dimensional. Got {pic.ndim} dimensions.")

    if pic.ndim == 2:
        pic = pic[:, :, None]

    img = torch.from_numpy(pic.transpose((2, 0, 1)))
    # backward compatibility
    if isinstance(img, torch.ByteTensor):
        return img.float().div(255)
    return img


def normalize(tensor: torch.Tensor, mean, std, inplace=False):
    """Normalize a tensor image with mean and standard deviation.

    .. note::
        This transform acts out of place by default, i.e., it does not mutates the input tensor.

    Args:
        tensor: Tensor image of size (C, H, W) to be normalized.
        mean: Sequence of means for each channel.
        std: Sequence of standard deviations for each channel.
        inplace(bool,optional): Bool to make this operation inplace.

    Returns:
        torch.Tensor: Normalized Tensor image.

    Raises:
        TypeError: if `tensor` is not torch.Tensor
    """
    if not (torch.is_tensor(tensor) and tensor.ndimension() == 3):
        raise TypeError("tensor is not a torch image.")

    if not inplace:
        tensor = tensor.clone()

    dtype = tensor.dtype
    mean = torch.as_tensor(mean, dtype=dtype, device=tensor.device)
    std = torch.as_tensor(std, dtype=dtype, device=tensor.device)
    tensor.sub_(mean[:, None, None]).div_(std[:, None, None])
    return tensor


[docs]class Compose: """Composes several transforms together."""
[docs] def __init__(self, transforms): """ Args: transforms: list of transforms to compose. Example: >>> Compose([ToTensor(), Normalize()]) """ self.transforms = transforms
def __call__(self, x): """Applies several transforms to the data.""" for t in self.transforms: x = t(x) return x def __repr__(self): """@TODO: Docs. Contribution is welcome.""" format_string = self.__class__.__name__ + "(" for t in self.transforms: format_string += "\n" format_string += " {0}".format(t) format_string += "\n)" return format_string
[docs]class ToTensor(object): """Convert a ``numpy.ndarray`` to tensor. Converts numpy.ndarray (H x W x C) in the range [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0] if the numpy.ndarray has dtype = np.uint8 In the other cases, tensors are returned without scaling. """ def __call__(self, pic): """ Args: pic (PIL Image or numpy.ndarray): Image to be converted to tensor. Returns: torch.Tensor: Converted image. """ return to_tensor(pic) def __repr__(self): """@TODO: Docs. Contribution is welcome.""" return self.__class__.__name__ + "()"
[docs]class Normalize(object): """Normalize a tensor image with mean and standard deviation. Given mean: ``(mean[1],...,mean[n])`` and std: ``(std[1],..,std[n])`` for ``n`` channels, this transform will normalize each channel of the input ``torch.*Tensor`` i.e., ``output[channel] = (input[channel] - mean[channel]) / std[channel]`` .. note:: This transform acts out of place, i.e., it does not mutate the input tensor. """
[docs] def __init__(self, mean, std, inplace=False): """ Args: mean: Sequence of means for each channel. std: Sequence of standard deviations for each channel. inplace(bool,optional): Bool to make this operation in-place. """ self.mean = mean self.std = std self.inplace = inplace
def __call__(self, tensor): """ Args: tensor: Tensor image of size (C, H, W) to be normalized. Returns: torch.Tensor: Normalized Tensor image. """ return normalize(tensor, self.mean, self.std, self.inplace) def __repr__(self): """@TODO: Docs. Contribution is welcome.""" return self.__class__.__name__ + "(mean={0}, std={1})".format(self.mean, self.std)
__all__ = ["Compose", "Normalize", "ToTensor", "to_tensor", "normalize"]