Spaces:
Running
Running
from typing import List, Tuple | |
import numpy as np | |
import torch | |
import torch.nn.functional as F | |
def get_device() -> torch.device: | |
r"""Function returns the device where the model and tensors should be placed. | |
Returns | |
torch.device: The device where the model and tensors should be placed. | |
""" | |
return torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
def pad(input_ele: List[torch.Tensor], max_len: int) -> torch.Tensor: | |
r"""Takes a list of 1D or 2D tensors and pads them to match the maximum length. | |
Args: | |
input_ele (List[torch.Tensor]): The list of tensors to be padded. | |
max_len (int): The length to which the tensors should be padded. | |
Returns: | |
torch.Tensor: A tensor containing all the padded input tensors. | |
""" | |
# Create an empty list to store the padded tensors | |
out_list = torch.jit.annotate(List[torch.Tensor], []) | |
for batch in input_ele: | |
if len(batch.shape) == 1: | |
# Perform padding for 1D tensor | |
one_batch_padded = F.pad( | |
batch, | |
(0, max_len - batch.size(0)), | |
"constant", | |
0.0, | |
) | |
else: | |
# Perform padding for 2D tensor | |
one_batch_padded = F.pad( | |
batch, | |
(0, 0, 0, max_len - batch.size(0)), | |
"constant", | |
0.0, | |
) | |
# Append the padded tensor to the list | |
out_list.append(one_batch_padded) | |
# Stack all the tensors in the list into a single tensor | |
return torch.stack(out_list) | |
def get_mask_from_lengths(lengths: torch.Tensor) -> torch.Tensor: | |
r"""Generate a mask tensor from a tensor of sequence lengths. | |
Args: | |
lengths (torch.Tensor): A tensor of sequence lengths of shape: (batch_size, ) | |
Returns: | |
torch.Tensor: A mask tensor of shape: (batch_size, max_len) where max_len is the | |
maximum sequence length in the provided tensor. The mask tensor has a value of | |
True at each position that is more than the length of the sequence (padding positions). | |
Example: | |
lengths: `torch.tensor([2, 3, 1, 4])` | |
Mask tensor will be: `torch.tensor([ | |
[False, False, True, True], | |
[False, False, False, True], | |
[False, True, True, True], | |
[False, False, False, False] | |
])` | |
""" | |
# Get batch size | |
batch_size = lengths.shape[0] | |
# Get maximum sequence length in the batch | |
max_len = int(torch.max(lengths).item()) | |
# Generate a tensor of shape (batch_size, max_len) | |
# where each row contains values from 0 to max_len | |
ids = ( | |
torch.arange(0, max_len, device=lengths.device) | |
.unsqueeze(0) | |
.expand(batch_size, -1) | |
) | |
# Compare each value in the ids tensor with | |
# corresponding sequence length to generate a mask. | |
# The mask will have True at positions where id >= sequence length, | |
# indicating padding positions in the original sequences | |
return ids >= lengths.unsqueeze(1).type(torch.int64).expand(-1, max_len) | |
def stride_lens_downsampling(lens: torch.Tensor, stride: int = 2) -> torch.Tensor: | |
r"""Function computes the lengths of 1D tensor when applying a stride for downsampling. | |
Args: | |
lens (torch.Tensor): Tensor containing the lengths to be downsampled. | |
stride (int, optional): The stride to be used for downsampling. Defaults to 2. | |
Returns: | |
torch.Tensor: A tensor of the same shape as the input containing the downsampled lengths. | |
""" | |
# The torch.ceil function is used to handle cases where the length is not evenly divisible | |
# by the stride. The torch.ceil function rounds up to the nearest integer, ensuring that | |
# each item is present at least once in the downsampled lengths. | |
# Finally, the .int() is used to convert the resulting float32 tensor to an integer tensor. | |
return torch.ceil(lens / stride).int() | |
def calc_same_padding(kernel_size: int) -> Tuple[int, int]: | |
r"""Calculates the necessary padding for 'same' padding in convolutional operations. | |
For 'same' padding, the output size is the same as the input size for `stride=1`. This function returns | |
two integers, representing the padding to be added on either side of the input to achieve 'same' padding. | |
Args: | |
kernel_size (int): Size of the convolving kernel. | |
Returns: | |
Tuple[int, int]: A tuple of two integers representing the number of padding elements to be applied on | |
left and right (or top and bottom for 2D) of the input tensor respectively. | |
""" | |
# Check if kernel_size is an integer greater than zero | |
if not isinstance(kernel_size, int) or kernel_size <= 0: | |
raise ValueError("kernel_size must be an integer greater than zero") | |
# Determine base padding amount (equal to half the kernel size, truncated down) | |
pad = kernel_size // 2 | |
# Return padding for each side of the kernel. If kernel size is odd, padding is (pad, pad). | |
# If kernel size is even, padding is (pad, pad - 1) because we can't pad equally on both sides. | |
return (pad, pad - (kernel_size + 1) % 2) | |
def initialize_embeddings(shape: Tuple[int, ...]) -> torch.Tensor: | |
r"""Initialize embeddings using Kaiming initialization (He initialization). | |
This method is specifically designed for 2D matrices and helps to avoid | |
the vanishing/exploding gradient problem in deep neural networks. | |
This is achieved by keeping the variance of the outputs of a layer to be | |
the same as the variance of its inputs. | |
Args: | |
shape (Tuple[int, ...]): The shape of the embedding matrix to create, denoted as a tuple of integers. | |
The shape should comprise 2 dimensions, i.e., (embedding_dim, num_embeddings). | |
Raises: | |
AssertionError: if the provided shape is not 2D. | |
Returns: | |
torch.Tensor: the created embedding matrix. | |
""" | |
# Check if the input shape is 2D | |
assert len(shape) == 2, "Can only initialize 2-D embedding matrices ..." | |
# Initialize the embedding matrix using Kaiming initialization | |
return torch.randn(shape) * np.sqrt(2 / shape[1]) | |