padding.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. # Adapted from https://github.com/mlcommons/training_results_v1.1/blob/main/NVIDIA/benchmarks/bert/implementations/pytorch/padding.py
  2. import torch
  3. import torch.nn.functional as F
  4. from einops import rearrange
  5. def unpad_input(hidden_states, attention_mask, unused_mask=None):
  6. """
  7. Arguments:
  8. hidden_states: (batch, seqlen, ...)
  9. attention_mask: (batch, seqlen), bool / int, 1 means valid and 0 means not valid.
  10. unused_mask: (batch, seqlen), bool / int, 1 means the element is allocated but unused.
  11. Return:
  12. hidden_states: (total_nnz, ...), where total_nnz = number of tokens selected in attention_mask + unused_mask.
  13. indices: (total_nnz), the indices of masked tokens from the flattened input sequence.
  14. cu_seqlens: (batch + 1), the cumulative sequence lengths, used to index into hidden_states.
  15. max_seqlen_in_batch: int
  16. seqused: (batch), returns the number of tokens selected in attention_mask + unused_mask.
  17. """
  18. all_masks = (attention_mask + unused_mask) if unused_mask is not None else attention_mask
  19. seqlens_in_batch = all_masks.sum(dim=-1, dtype=torch.int32)
  20. used_seqlens_in_batch = attention_mask.sum(dim=-1, dtype=torch.int32)
  21. indices = torch.nonzero(all_masks.flatten(), as_tuple=False).flatten()
  22. max_seqlen_in_batch = seqlens_in_batch.max().item()
  23. cu_seqlens = F.pad(torch.cumsum(seqlens_in_batch, dim=0, dtype=torch.int32), (1, 0))
  24. # TD [2022-03-04] We don't want to index with a bool mask, because Pytorch will expand the
  25. # bool mask, then call nonzero to get the indices, then index with those. The indices is @dim
  26. # times larger than it needs to be, wasting memory. It's faster and more memory-efficient to
  27. # index with integer indices.
  28. return (
  29. rearrange(hidden_states, "b s ... -> (b s) ...")[indices],
  30. indices,
  31. cu_seqlens,
  32. max_seqlen_in_batch,
  33. used_seqlens_in_batch,
  34. )
  35. def pad_input(hidden_states, indices, batch, seqlen):
  36. """
  37. Arguments:
  38. hidden_states: (total_nnz, ...), where total_nnz = number of tokens in selected in attention_mask.
  39. indices: (total_nnz), the indices that represent the non-masked tokens of the original padded input sequence.
  40. batch: int, batch size for the padded sequence.
  41. seqlen: int, maximum sequence length for the padded sequence.
  42. Return:
  43. hidden_states: (batch, seqlen, ...)
  44. """
  45. dim = hidden_states.shape[1:]
  46. output = torch.zeros((batch * seqlen), *dim, device=hidden_states.device, dtype=hidden_states.dtype)
  47. output[indices] = hidden_states
  48. return rearrange(output, "(b s) ... -> b s ...", b=batch)