Returns:
Single-use handle retaining transfer storage until wait.
"""
size, rank = dist.get_world_size(group), dist.get_rank(group)
inputs = (query_residual, weights, *embeddings)
if (len(embeddings) != 2 or query_residual.ndim != 3 or query_residual.shape[0] != 1
or query_residual.shape[1] * size != sum(lengths)):
raise ValueError("Indexer balance requires batch one and equal contiguous source query shards")
if any(value.ndim != 3 or value.shape[:2] != query_residual.shape[:2]
or value.device != query_residual.device for value in inputs):
raise ValueError("Indexer qr, weights and rotary embeddings must share token axes and device")
route = indexer_route(lengths, size, rank, ratio, mode, block_size,
zigzag_min_length)
rows = _device_rows(route, query_residual.device)
send_rows, receive_rows, local_sources, local_targets = rows
grouped = {}
for index, value in enumerate(inputs):
grouped.setdefault(value.dtype, []).append(index)
transfers, fields = [], []
for indices in grouped.values():
packed = torch.cat([inputs[index][0] for index in indices], dim=-1)
send = packed.index_select(0, send_rows).contiguous()
received = packed.new_empty((sum(route.output_splits), packed.shape[-1]))
work = dist.all_to_all_single(
received, send, list(route.output_splits), list(route.input_splits), group=group, async_op=True,
)
output = packed.new_empty((route.query_count, packed.shape[-1]))
output.index_copy_(0, local_targets, packed.index_select(0, local_sources))
transfers.append(_PendingRows(send, received, output, receive_rows, work))
fields.append(tuple(indices))
return IndexerInputExchange(route, rows, group, query_residual.shape[1], tuple(transfers),
tuple(fields), tuple(value.shape[-1] for value in inputs))