| """Padding utilities — pad variable-length sequences to a common length.""" |
|
|
| from __future__ import annotations |
|
|
| import numpy as np |
|
|
|
|
| def pad_sequences( |
| sequences: list[np.ndarray], |
| max_length: int | None = None, |
| pad_value: float = 0.0, |
| dtype: np.dtype = np.float32, |
| ) -> tuple[np.ndarray, np.ndarray]: |
| """Pad a list of 2D sequences to a common length. |
| |
| Args: |
| sequences: List of (T_i × F) arrays. |
| max_length: Target sequence length. If None, uses max observed. |
| pad_value: Fill value for padded positions. |
| dtype: Output dtype. |
| |
| Returns: |
| (padded_values, padding_mask) where: |
| padded_values: (S × max_length × F) padded tensor. |
| padding_mask: (S × max_length) boolean mask (True = padded). |
| """ |
| if not sequences: |
| return np.array([], dtype=dtype), np.array([], dtype=bool) |
|
|
| S = len(sequences) |
| F = sequences[0].shape[1] |
| max_len = max_length or max(s.shape[0] for s in sequences) |
|
|
| padded = np.full((S, max_len, F), pad_value, dtype=dtype) |
| mask = np.ones((S, max_len), dtype=bool) |
|
|
| for i, seq in enumerate(sequences): |
| length = min(seq.shape[0], max_len) |
| padded[i, :length, :] = seq[:length, :] |
| mask[i, :length] = False |
|
|
| return padded, mask |
|
|
|
|
| def unpad_sequences( |
| padded_values: np.ndarray, |
| padding_mask: np.ndarray, |
| ) -> list[np.ndarray]: |
| """Extract ragged sequences from a padded tensor. |
| |
| Args: |
| padded_values: (S × T_max × F) padded tensor. |
| padding_mask: (S × T_max) boolean mask (True = padded). |
| |
| Returns: |
| List of (T_i × F) arrays. |
| """ |
| sequences = [] |
| for s in range(padded_values.shape[0]): |
| valid = ~padding_mask[s] |
| sequences.append(padded_values[s, valid, :]) |
| return sequences |
|
|