|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| from typing import TYPE_CHECKING
|
|
|
| import torch
|
| import torch.nn.functional as F
|
|
|
| from ...extras import logging
|
|
|
|
|
| if TYPE_CHECKING:
|
| from ...hparams import ModelArguments
|
|
|
|
|
| logger = logging.get_logger(__name__)
|
|
|
|
|
| def get_seqlens_in_batch(attention_mask: "torch.Tensor") -> "torch.Tensor":
|
| r"""Get the sequnce lengths in the current batch.
|
|
|
| e.g.
|
| ```python
|
| # input
|
| [
|
| [1, 1, 2, 2, 2, 0],
|
| [1, 2, 2, 3, 3, 3],
|
| ]
|
| # output
|
| [2, 3, 1, 2, 3]
|
| ```
|
| """
|
| bsz = attention_mask.size(0)
|
| dtype, device = attention_mask.dtype, attention_mask.device
|
| max_num = torch.max(attention_mask).item()
|
| counts: torch.Tensor = torch.zeros((bsz, max_num), dtype=dtype, device=device)
|
| for i in range(max_num):
|
| counts[:, i] = torch.sum(attention_mask == (i + 1), dim=-1)
|
|
|
| counts = counts.flatten()
|
| seqlens = counts[counts.nonzero().squeeze(dim=-1)]
|
| return seqlens
|
|
|
|
|
| def get_unpad_data(attention_mask: "torch.Tensor") -> tuple["torch.Tensor", "torch.Tensor", int]:
|
| r"""Prepare the indices and seqlens for flash attn varlen function.
|
|
|
| Returns:
|
| indices: indices of non-masked tokens from the flattened sequence.
|
| cu_seqlens: the cumulative sequence lengths in the current batch, always starts from 0.
|
| max_seqlen_in_batch: the largest seqlen in the current batch.
|
|
|
| e.g.
|
| ```python
|
| # input
|
| [
|
| [1, 1, 2, 2, 2, 0],
|
| [1, 2, 2, 3, 3, 3],
|
| ]
|
| # output
|
| [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11]
|
| [0, 2, 5, 6, 8, 11]
|
| 3
|
| ```
|
|
|
| """
|
| seqlens_in_batch = get_seqlens_in_batch(attention_mask)
|
| indices = torch.nonzero(attention_mask.flatten(), as_tuple=False).flatten()
|
| max_seqlen_in_batch = seqlens_in_batch.max().item()
|
| cu_seqlens = F.pad(torch.cumsum(seqlens_in_batch, dim=0, dtype=torch.int32), (1, 0))
|
| return indices, cu_seqlens, max_seqlen_in_batch
|
|
|
|
|
| def configure_packing(model_args: "ModelArguments", is_trainable: bool) -> None:
|
| if not is_trainable or not model_args.block_diag_attn:
|
| return
|
|
|
| import transformers.modeling_flash_attention_utils
|
|
|
| transformers.modeling_flash_attention_utils._get_unpad_data = get_unpad_data
|
| logger.info_rank0("Using block diagonal attention for sequence packing without cross-attention.")
|
|
|