Download GRID/src/data/loading/components/label_function.py from SYHDSG/TIGER: direct link, hf CLI and curl.
- Browser
- Download file 9.23 kB
-
https://huggingface.co/SYHDSG/TIGER/resolve/main/GRID/src/data/loading/components/label_function.py
- Command line
-
hf download hf://SYHDSG/TIGER/GRID/src/data/loading/components/label_function.py
-
curl -L -o label_function.py https://huggingface.co/SYHDSG/TIGER/resolve/main/GRID/src/data/loading/components/label_function.py
9.23 kB
| from abc import ABC, abstractmethod | |
| from typing import Optional | |
| import torch | |
| from src.data.loading.components.interfaces import ( | |
| LabelFunctionOutput, | |
| ) | |
| class LabelFunction(ABC): | |
| """ | |
| An interface for the LabelFunction classes. The LabelFunction classes are used to transform the input sequence for training or inference and collecting the labels and label prediction locations. | |
| """ | |
| def __init__(self) -> None: | |
| super().__init__() | |
| def transform_label(self, sequence: torch.Tensor) -> LabelFunctionOutput: | |
| """ | |
| Function to transform the input sequence for training or inference and collecting the labels and label prediction locations. | |
| The exact functionality needs to be implemented in the child class. | |
| Parameters | |
| ---------- | |
| sequence: torch.Tensor of size (batch_size, sequence_length) | |
| The matrix for input sequences. | |
| Returns | |
| ---------- | |
| A LabelFunctionOutput object with the following attributes: | |
| sequence: torch.Tensor of size (batch_size, new_sequence_length) | |
| The original input sequence transformed for training or inference. The new_sequence_length can be the same as the original sequence length or different depending on the LabelFunction. | |
| labels: torch.Tensor of size (number of labels,) | |
| The labels across the sequences in the batch stacked together as labels for training. | |
| label_location: torch.Tensor of size (number of masked tokens, 2) | |
| The (row, col) location of the label_prediction corresponding to the labels in the batch stacked together. | |
| """ | |
| raise NotImplementedError("Need to implement in the child class.") | |
| def get_input_attention_mask( | |
| self, sequence: torch.Tensor, padding_token: int | |
| ) -> torch.Tensor: | |
| """ | |
| Function to get the input attention mask for the input sequence. | |
| Defaults to returning the mask for the non-padding tokens but | |
| can be overridden in the child class to return a different mask. | |
| Parameters | |
| ---------- | |
| sequence: torch.Tensor of size (batch_size, sequence_length) | |
| The matrix for input sequences. | |
| padding_token: int | |
| The index of token for padding. | |
| Returns | |
| ---------- | |
| A tensor of size (batch_size, sequence_length) with 1s for non-padding tokens and 0s for padding tokens. | |
| """ | |
| return sequence != padding_token | |
| class Identity(LabelFunction): | |
| """ | |
| LabelFunction class to return the original input for the non-masked values of the sequence. It's useful in situations where we don't to transform the input sequence. | |
| """ | |
| def transform_label( | |
| self, sequence: torch.Tensor, padding_token: int = 0, masking_token: int = 0 | |
| ) -> LabelFunctionOutput: | |
| """ | |
| Returns the original input for the non-masked values of the sequence. | |
| Parameters | |
| ---------- | |
| sequence: torch.Tensor of size (batch_size, sequence_length) | |
| The matrix for input sequences. | |
| padding_token: int | |
| The index of token for padding. | |
| The padding_token is defined in the DataloaderConfig of LightningDataModule and is passed to the collate_fn which then passes it to the LabelFunction's transform_label function. | |
| Thus, to change the padding_token, the user needs to change the padding_token in the DataloaderConfig. | |
| Returns | |
| ---------- | |
| A LabelFunctionOutput object with the following attributes: | |
| sequence: torch.Tensor of size (batch_size, sequence_length) | |
| The original input sequence. | |
| labels: torch.Tensor of size (number of non-padding tokens in batch,) | |
| Collecting all the non-padding tokens in the batch stacked together as labels for training. | |
| label_location: torch.Tensor of size (number of non-padding tokens in batch, 2) | |
| The location of the label predictions, that is the (row, col) location of all non-padding tokens in the batch stacked together. | |
| """ | |
| content_mask = sequence != padding_token | |
| labels = sequence[content_mask] | |
| label_location = content_mask.nonzero() | |
| return LabelFunctionOutput( | |
| sequence=sequence, labels=labels, label_location=label_location | |
| ) | |
| class NextKTokenMasking(LabelFunction): | |
| """ | |
| LabelFunction to create masking to use the last K tokens at the end of each sequence as labels. | |
| Implements the `All Action` training objective from Pinnerformer (https://arxiv.org/pdf/2205.04507) | |
| """ | |
| def __init__(self, next_k: int = 5): | |
| """ | |
| Initialize the LabelFunction with the number of tokens to mask as labels. | |
| Parameters | |
| ---------- | |
| next_k: int | |
| Number of tokens K to mask as labels. | |
| """ | |
| self.next_k = next_k | |
| def transform_label( | |
| self, sequence: torch.Tensor, padding_token: int, masking_token: int | |
| ) -> LabelFunctionOutput: | |
| """ | |
| For each row of sequence, we save the original last next_k tokens as labels and replace them with 1 masking token and next_k - 1 padding tokens. | |
| For all the next_k tokens, we use the first masked token as the label prediction. | |
| Parameters | |
| ---------- | |
| sequence: torch.Tensor of size (batch_size, sequence_length) | |
| The matrix for input sequences. | |
| padding_token: int | |
| The index of token for padding. | |
| masking_token: int | |
| The index of token for masked tokens. | |
| The padding_token and the masking_token are defined in the DataloaderConfig of LightningDataModule and are passed to the collate_fn which then passes it to the LabelFunction's transform_label function. | |
| Thus, to change the padding_token and the masking_token, the user needs to change them in the DataloaderConfig. | |
| Returns | |
| ---------- | |
| A LabelFunctionOutput object with the following attributes: | |
| sequence: torch.Tensor of size (batch_size, sequence_length), | |
| The original input sequence transformed such that for each row, the last next_k non-padding tokens are replaced with 1 masking token and next_k - 1 padding tokens. | |
| labels: torch.Tensor of size (batch_size * self.next_k,) | |
| The original last next_k tokens of each row chosen as labels stacked together. | |
| label_location: torch.Tensor of size (batch_size * self.next_k, 2) | |
| The location of the label predictions, for each row the first masked token's location is returned as the label prediction location for all the next_k tokens. | |
| """ | |
| content_mask = sequence != padding_token | |
| # check each sequence in batch is greater than next_k + 1 | |
| unpadded_seq_lengths = content_mask.sum(1) # shape: (batch_size,) | |
| if torch.any(unpadded_seq_lengths < self.next_k + 1): | |
| raise ValueError( | |
| f"Sequence lengths: {unpadded_seq_lengths[unpadded_seq_lengths < self.next_k + 1]} should be greater than next_k + 1: {self.next_k + 1}" | |
| ) | |
| # for each row, we want elements from unpadded_seq_lengths - next_k to unpadded_seq_lengths - 1 as labels | |
| label_start_indices = unpadded_seq_lengths - self.next_k # shape: (batch_size,) | |
| # for each row, we select [label_start_indices, label_start_indices + 1, ..., label_start_indices + next_k - 1] | |
| label_col_offset = torch.arange(self.next_k) # shape: (next_k,) | |
| label_col_indices = ( | |
| label_start_indices.unsqueeze(1) + label_col_offset | |
| ) # shape: (batch_size, next_k) | |
| label_col_indices = label_col_indices.reshape( | |
| -1 | |
| ) # shape: (batch_size * next_k,) | |
| # To get the row indices, we repeat each row index next_k times | |
| row_orig_indices = torch.arange(sequence.size(0)) # shape: (batch_size,) | |
| row_interleaved_indices = row_orig_indices.repeat_interleave( | |
| self.next_k | |
| ) # shape: (batch_size * next_k,) | |
| labels = sequence[row_interleaved_indices, label_col_indices] | |
| # for prediction, for each row, we replace the last next_k tokens with | |
| # 1 masking token at the label_start_indices, and next_k - 1 with padding tokens | |
| sequence[row_interleaved_indices, label_col_indices] = padding_token | |
| sequence[row_orig_indices, label_start_indices] = masking_token | |
| # for each row, we use the label_start_index (which was masked) as label prediction for all the next_k labels | |
| label_location = torch.stack( | |
| ( | |
| row_interleaved_indices, | |
| label_start_indices.repeat_interleave(self.next_k), | |
| ), | |
| dim=1, | |
| ) | |
| return LabelFunctionOutput( | |
| sequence=sequence, | |
| labels=labels, | |
| label_location=label_location, | |
| ) | |