Spaces:
Runtime error
Runtime error
# Copyright (C) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
# | |
# This work is made available under the Nvidia Source Code License-NC. | |
# To view a copy of this license, check out LICENSE.md | |
"""Miscellaneous utils.""" | |
import collections | |
from collections import OrderedDict | |
import torch | |
import torch.nn.functional as F | |
string_classes = (str, bytes) | |
def split_labels(labels, label_lengths): | |
r"""Split concatenated labels into their parts. | |
Args: | |
labels (torch.Tensor): Labels obtained through concatenation. | |
label_lengths (OrderedDict): Containing order of labels & their lengths. | |
Returns: | |
""" | |
assert isinstance(label_lengths, OrderedDict) | |
start = 0 | |
outputs = {} | |
for data_type, length in label_lengths.items(): | |
end = start + length | |
if labels.dim() == 5: | |
outputs[data_type] = labels[:, :, start:end] | |
elif labels.dim() == 4: | |
outputs[data_type] = labels[:, start:end] | |
elif labels.dim() == 3: | |
outputs[data_type] = labels[start:end] | |
start = end | |
return outputs | |
def requires_grad(model, require=True): | |
r""" Set a model to require gradient or not. | |
Args: | |
model (nn.Module): Neural network model. | |
require (bool): Whether the network requires gradient or not. | |
Returns: | |
""" | |
for p in model.parameters(): | |
p.requires_grad = require | |
def to_device(data, device): | |
r"""Move all tensors inside data to device. | |
Args: | |
data (dict, list, or tensor): Input data. | |
device (str): 'cpu' or 'cuda'. | |
""" | |
assert device in ['cpu', 'cuda'] | |
if isinstance(data, torch.Tensor): | |
data = data.to(torch.device(device)) | |
return data | |
elif isinstance(data, collections.abc.Mapping): | |
return {key: to_device(data[key], device) for key in data} | |
elif isinstance(data, collections.abc.Sequence) and \ | |
not isinstance(data, string_classes): | |
return [to_device(d, device) for d in data] | |
else: | |
return data | |
def to_cuda(data): | |
r"""Move all tensors inside data to gpu. | |
Args: | |
data (dict, list, or tensor): Input data. | |
""" | |
return to_device(data, 'cuda') | |
def to_cpu(data): | |
r"""Move all tensors inside data to cpu. | |
Args: | |
data (dict, list, or tensor): Input data. | |
""" | |
return to_device(data, 'cpu') | |
def to_half(data): | |
r"""Move all floats to half. | |
Args: | |
data (dict, list or tensor): Input data. | |
""" | |
if isinstance(data, torch.Tensor) and torch.is_floating_point(data): | |
data = data.half() | |
return data | |
elif isinstance(data, collections.abc.Mapping): | |
return {key: to_half(data[key]) for key in data} | |
elif isinstance(data, collections.abc.Sequence) and \ | |
not isinstance(data, string_classes): | |
return [to_half(d) for d in data] | |
else: | |
return data | |
def to_float(data): | |
r"""Move all halfs to float. | |
Args: | |
data (dict, list or tensor): Input data. | |
""" | |
if isinstance(data, torch.Tensor) and torch.is_floating_point(data): | |
data = data.float() | |
return data | |
elif isinstance(data, collections.abc.Mapping): | |
return {key: to_float(data[key]) for key in data} | |
elif isinstance(data, collections.abc.Sequence) and \ | |
not isinstance(data, string_classes): | |
return [to_float(d) for d in data] | |
else: | |
return data | |
def to_channels_last(data): | |
r"""Move all data to ``channels_last`` format. | |
Args: | |
data (dict, list or tensor): Input data. | |
""" | |
if isinstance(data, torch.Tensor): | |
if data.dim() == 4: | |
data = data.to(memory_format=torch.channels_last) | |
return data | |
elif isinstance(data, collections.abc.Mapping): | |
return {key: to_channels_last(data[key]) for key in data} | |
elif isinstance(data, collections.abc.Sequence) and \ | |
not isinstance(data, string_classes): | |
return [to_channels_last(d) for d in data] | |
else: | |
return data | |
def slice_tensor(data, start, end): | |
r"""Slice all tensors from start to end. | |
Args: | |
data (dict, list or tensor): Input data. | |
""" | |
if isinstance(data, torch.Tensor): | |
data = data[start:end] | |
return data | |
elif isinstance(data, collections.abc.Mapping): | |
return {key: slice_tensor(data[key], start, end) for key in data} | |
elif isinstance(data, collections.abc.Sequence) and \ | |
not isinstance(data, string_classes): | |
return [slice_tensor(d, start, end) for d in data] | |
else: | |
return data | |
def get_and_setattr(cfg, name, default): | |
r"""Get attribute with default choice. If attribute does not exist, set it | |
using the default value. | |
Args: | |
cfg (obj) : Config options. | |
name (str) : Attribute name. | |
default (obj) : Default attribute. | |
Returns: | |
(obj) : Desired attribute. | |
""" | |
if not hasattr(cfg, name) or name not in cfg.__dict__: | |
setattr(cfg, name, default) | |
return getattr(cfg, name) | |
def get_nested_attr(cfg, attr_name, default): | |
r"""Iteratively try to get the attribute from cfg. If not found, return | |
default. | |
Args: | |
cfg (obj): Config file. | |
attr_name (str): Attribute name (e.g. XXX.YYY.ZZZ). | |
default (obj): Default return value for the attribute. | |
Returns: | |
(obj): Attribute value. | |
""" | |
names = attr_name.split('.') | |
atr = cfg | |
for name in names: | |
if not hasattr(atr, name): | |
return default | |
atr = getattr(atr, name) | |
return atr | |
def gradient_norm(model): | |
r"""Return the gradient norm of model. | |
Args: | |
model (PyTorch module): Your network. | |
""" | |
total_norm = 0 | |
for p in model.parameters(): | |
if p.grad is not None: | |
param_norm = p.grad.norm(2) | |
total_norm += param_norm.item() ** 2 | |
return total_norm ** (1. / 2) | |
def random_shift(x, offset=0.05, mode='bilinear', padding_mode='reflection'): | |
r"""Randomly shift the input tensor. | |
Args: | |
x (4D tensor): The input batch of images. | |
offset (int): The maximum offset ratio that is between [0, 1]. | |
The maximum shift is offset * image_size for each direction. | |
mode (str): The resample mode for 'F.grid_sample'. | |
padding_mode (str): The padding mode for 'F.grid_sample'. | |
Returns: | |
x (4D tensor) : The randomly shifted image. | |
""" | |
assert x.dim() == 4, "Input must be a 4D tensor." | |
batch_size = x.size(0) | |
theta = torch.eye(2, 3, device=x.device).unsqueeze(0).repeat( | |
batch_size, 1, 1) | |
theta[:, :, 2] = 2 * offset * torch.rand(batch_size, 2) - offset | |
grid = F.affine_grid(theta, x.size()) | |
x = F.grid_sample(x, grid, mode=mode, padding_mode=padding_mode) | |
return x | |
# def truncated_gaussian(threshold, size, seed=None, device=None): | |
# r"""Apply the truncated gaussian trick to trade diversity for quality | |
# | |
# Args: | |
# threshold (float): Truncation threshold. | |
# size (list of integer): Tensor size. | |
# seed (int): Random seed. | |
# device: | |
# """ | |
# state = None if seed is None else np.random.RandomState(seed) | |
# values = truncnorm.rvs(-threshold, threshold, | |
# size=size, random_state=state) | |
# return torch.tensor(values, device=device).float() | |
def apply_imagenet_normalization(input): | |
r"""Normalize using ImageNet mean and std. | |
Args: | |
input (4D tensor NxCxHxW): The input images, assuming to be [-1, 1]. | |
Returns: | |
Normalized inputs using the ImageNet normalization. | |
""" | |
# normalize the input back to [0, 1] | |
normalized_input = (input + 1) / 2 | |
# normalize the input using the ImageNet mean and std | |
mean = normalized_input.new_tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1) | |
std = normalized_input.new_tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1) | |
output = (normalized_input - mean) / std | |
return output | |