|
4 | 4 | import torch |
5 | 5 | from megatron.core import mpu, tensor_parallel |
6 | 6 | from megatron.core.distributed import DistributedDataParallel as DDP |
| 7 | +from megatron.core.ssm.mamba_context_parallel import _undo_attention_load_balancing |
7 | 8 | from megatron.core.transformer.module import Float16Module |
8 | 9 | from megatron.core.transformer.multi_token_prediction import roll_tensor as mcore_roll_tensor |
9 | 10 | from megatron.core.transformer.transformer_block import get_num_layers_to_build |
@@ -67,6 +68,44 @@ def split_cp_inputs(inputs: torch.Tensor, cu_seqlens: Optional[torch.Tensor], di |
67 | 68 | return torch.cat(new_inputs, dim=dim) |
68 | 69 |
|
69 | 70 |
|
| 71 | +def reconstruct_tensor_cp(tensor, packed_seq_params, dim: int) -> torch.Tensor: |
| 72 | + """In CP mode, all-gather and undo the load-balanced (zigzag) chunking |
| 73 | + produced by ``split_cp_inputs``, restoring the full sequence in original |
| 74 | + token order along ``dim``. |
| 75 | +
|
| 76 | + Args: |
| 77 | + tensor: CP-sharded local tensor whose sequence dim is at ``dim``. |
| 78 | + packed_seq_params: ``PackedSeqParams`` for THD inputs, or ``None`` for |
| 79 | + regular ``[B, S, ...]`` inputs. |
| 80 | + dim: Sequence dimension index of ``tensor`` (default: 1). |
| 81 | +
|
| 82 | + Returns: |
| 83 | + torch.Tensor: Full-sequence tensor with the same shape as ``tensor`` |
| 84 | + except the size at ``dim`` is multiplied by ``cp_size``. |
| 85 | + """ |
| 86 | + |
| 87 | + cp_size = mpu.get_context_parallel_world_size() |
| 88 | + if cp_size <= 1: |
| 89 | + return tensor |
| 90 | + |
| 91 | + cp_rank = mpu.get_context_parallel_rank() |
| 92 | + cp_group = mpu.get_context_parallel_group() |
| 93 | + |
| 94 | + # All-gather across CP ranks (preserve local autograd graph for `tensor`). |
| 95 | + output_list = [torch.empty_like(tensor) for _ in range(cp_size)] |
| 96 | + torch.distributed.all_gather(output_list, tensor.contiguous(), group=cp_group) |
| 97 | + output_list[cp_rank] = tensor |
| 98 | + gathered = torch.cat(output_list, dim=dim) |
| 99 | + |
| 100 | + # `_undo_attention_load_balancing` assumes sequence dim is 0; transpose if needed. |
| 101 | + if dim != 0: |
| 102 | + gathered = gathered.transpose(0, dim).contiguous() |
| 103 | + out = _undo_attention_load_balancing(gathered, cp_size, packed_seq_params) |
| 104 | + if dim != 0: |
| 105 | + out = out.transpose(0, dim).contiguous() |
| 106 | + return out |
| 107 | + |
| 108 | + |
70 | 109 | def get_local_layer_specs(config, layer_specs, vp_stage=None): |
71 | 110 | num_layers_to_build = get_num_layers_to_build(config, vp_stage=vp_stage) |
72 | 111 |
|
|
0 commit comments