Reconstruct and mix transformed outputs back into the original input sequence shape. Key operations: 1. Reshapes and transposes `transformed_x` to prepare for scattering. 2. Applies the `mask` to zero out invalid positions. 3. Uses `torch.scatter_add_` to scatter and sum the tr
(transformed_x, indices: torch.Tensor, sorted_indices: torch.Tensor, batch_size: int, seq_len: int, topk: int, routing_weights: torch.Tensor, mask: torch.Tensor)
| 114 | |
| 115 | # @torch.jit.script |
| 116 | def reconstruct(transformed_x, indices: torch.Tensor, sorted_indices: torch.Tensor, batch_size: int, seq_len: int, topk: int, routing_weights: torch.Tensor, mask: torch.Tensor): |
| 117 | ''' |
| 118 | Reconstruct and mix transformed outputs back into the original input sequence shape. |
| 119 | |
| 120 | Key operations: |
| 121 | 1. Reshapes and transposes `transformed_x` to prepare for scattering. |
| 122 | 2. Applies the `mask` to zero out invalid positions. |
| 123 | 3. Uses `torch.scatter_add_` to scatter and sum the transformed outputs back to their original positions based on `indices`. |
| 124 | 4. Rearranges the scattered outputs using `sorted_indices` to ensure correct ordering. |
| 125 | 5. Applies the `routing_weights` to weight the outputs. |
| 126 | 6. Sums over the `topk` dimension to produce the final reconstructed output. |
| 127 | |
| 128 | Args: |
| 129 | transformed_x (torch.Tensor): |
| 130 | The transformed output tensor from memory units or experts. |
| 131 | Shape: (num_memories, batch_size, capacity_len, hidden_size) |
| 132 | indices (torch.Tensor): |
| 133 | Indices used for scattering the transformed outputs back to their corresponding positions. |
| 134 | Shape: (batch*num_memories, max_len) |
| 135 | sorted_indices (torch.Tensor): |
| 136 | Sorting indices used to rearrange the scattered outputs back into the original sequence order. |
| 137 | Shape: (batch_size*seq_len*topk) |
| 138 | batch_size (int): |
| 139 | The size of the batch. |
| 140 | seq_len (int): |
| 141 | The length of the input sequence. |
| 142 | topk (int): |
| 143 | The number of top elements selected (`topk`) per token during the selection process. |
| 144 | routing_weights (torch.Tensor): |
| 145 | Routing weights assigned to the top-k selected outputs when reconstructing the final output. |
| 146 | Shape: (batch_size, seq_len, topk) |
| 147 | mask (torch.Tensor): |
| 148 | Boolean mask indicating valid positions in the sequence. |
| 149 | Shape: (batch*num_memories, max_len) |
| 150 | |
| 151 | Returns: |
| 152 | restored_x (torch.Tensor): |
| 153 | The reconstructed output tensor in the original input sequence shape. |
| 154 | Shape: (batch_size, seq_len, hidden_size) |
| 155 | ''' |
| 156 | transformed_x = transformed_x.transpose(0, 1).reshape((-1, transformed_x.shape[2], transformed_x.shape[3], transformed_x.shape[4])) |
| 157 | b, s, k, h, d = batch_size, seq_len, topk, transformed_x.shape[2], transformed_x.shape[3] |
| 158 | gathered_x = transformed_x.reshape((transformed_x.shape[0] * transformed_x.shape[1], transformed_x.shape[2], transformed_x.shape[3])) |
| 159 | mask_expanded = mask.reshape(-1).unsqueeze(-1).unsqueeze(-1).expand_as(gathered_x) |
| 160 | gathered_x = gathered_x * mask_expanded |
| 161 | |
| 162 | assert (indices >= 0).all(), "Indices should be non-negative" |
| 163 | |
| 164 | resortd_x = torch.zeros((b * s * k, h, d) ,device=gathered_x.device, dtype=gathered_x.dtype).scatter_add_( |
| 165 | 0, |
| 166 | indices.reshape(-1).unsqueeze(-1).unsqueeze(-1).expand(-1, h, d), |
| 167 | gathered_x, |
| 168 | ) |
| 169 | assert (indices < resortd_x.size(0)).all(), "Indices should be less than resortd_x size" |
| 170 | |
| 171 | inverse_indices = sorted_indices.argsort() |
| 172 | rearranged_x_flat = resortd_x[inverse_indices] |
| 173 | restored_x = rearranged_x_flat.reshape((b, s * k, h, d)) |