import torch


def denormalize(data, mean, std):
    """
        Denormalize a tensor image with mean and standard deviation.
    """
    shape = data.shape

    if isinstance(mean, float):
        mean = torch.tensor([mean] * shape[1], device=data.device, dtype=data.dtype)

    if isinstance(std, float):
        std = torch.tensor([std] * shape[1], device=data.device, dtype=data.dtype)

    if not isinstance(data, torch.Tensor):
        raise TypeError("data should be a tensor. Got {}".format(type(data)))

    if not isinstance(mean, torch.Tensor):
        raise TypeError("mean should be a tensor or a float. Got {}".format(type(mean)))

    if not isinstance(std, torch.Tensor):
        raise TypeError("std should be a tensor or float. Got {}".format(type(std)))

    # Allow broadcast on channel dimension
    if mean.shape and mean.shape[0] != 1:
        if mean.shape[0] != data.shape[-3] and mean.shape[:2] != data.shape[:2]:
            raise ValueError(f"mean length and number of channels do not match. Got {mean.shape} and {data.shape}.")

    # Allow broadcast on channel dimension
    if std.shape and std.shape[0] != 1:
        if std.shape[0] != data.shape[-3] and std.shape[:2] != data.shape[:2]:
            raise ValueError(f"std length and number of channels do not match. Got {std.shape} and {data.shape}.")

    mean = torch.as_tensor(mean, device=data.device, dtype=data.dtype)
    std = torch.as_tensor(std, device=data.device, dtype=data.dtype)

    if mean.shape:
        mean = mean[..., :, None]
    if std.shape:
        std = std[..., :, None]

    out = (data.view(shape[0], shape[1], -1) * std) + mean

    return out.view(shape)