|
21 | 21 |
|
22 | 22 | logger = init_logger(__name__) |
23 | 23 | _INT8_WORKSPACES: dict[tuple[int, int, int, int], tuple[torch.Tensor, torch.Tensor]] = {} |
| 24 | +_INT8_BF16PACK_WORKSPACES: dict[ |
| 25 | + tuple[int, int, int, int], tuple[torch.Tensor, torch.Tensor, int] |
| 26 | +] = {} |
24 | 27 | _FP4_WORKSPACES: dict[tuple[int, int, int, int], tuple[torch.Tensor, torch.Tensor]] = {} |
25 | 28 | _SHARED_ROW_WORKSPACES: dict[tuple[int, int, int], tuple[torch.Tensor, torch.Tensor]] = {} |
26 | 29 |
|
@@ -287,6 +290,7 @@ def should_use_tp3_lowbit_hidden_reduce( |
287 | 290 | "fp4_block16", |
288 | 291 | "fp4_block16_packed", |
289 | 292 | "int8_shared_row", |
| 293 | + "int8_bf16pack", |
290 | 294 | ) |
291 | 295 | and should_use_tp3_int8_hidden_reduce(input_, world_size, min_tokens) |
292 | 296 | ) |
@@ -328,6 +332,29 @@ def _int8_workspace( |
328 | 332 | return send, gathered |
329 | 333 |
|
330 | 334 |
|
| 335 | +def _int8_bf16pack_workspace( |
| 336 | + device: torch.device, |
| 337 | + world_size: int, |
| 338 | + rows: int, |
| 339 | + cols: int, |
| 340 | +) -> tuple[torch.Tensor, torch.Tensor, int]: |
| 341 | + device_index = device.index if device.index is not None else torch.cuda.current_device() |
| 342 | + q_nbytes = rows * cols |
| 343 | + s_nbytes = rows * 4 |
| 344 | + total_nbytes = q_nbytes + s_nbytes |
| 345 | + packed_numel = (total_nbytes + 1) // 2 |
| 346 | + key = (device_index, world_size, rows, cols) |
| 347 | + cached = _INT8_BF16PACK_WORKSPACES.get(key) |
| 348 | + if cached is not None and cached[0].numel() == packed_numel: |
| 349 | + return cached |
| 350 | + send = torch.empty(packed_numel, device=device, dtype=torch.bfloat16) |
| 351 | + gathered = torch.empty((world_size, packed_numel), device=device, |
| 352 | + dtype=torch.bfloat16) |
| 353 | + cached = (send, gathered, total_nbytes) |
| 354 | + _INT8_BF16PACK_WORKSPACES[key] = cached |
| 355 | + return cached |
| 356 | + |
| 357 | + |
331 | 358 | def _fp4_workspace( |
332 | 359 | device: torch.device, |
333 | 360 | world_size: int, |
@@ -403,6 +430,58 @@ def tp3_int8_hidden_all_reduce( |
403 | 430 | return out |
404 | 431 |
|
405 | 432 |
|
| 433 | +def tp3_int8_bf16pack_hidden_all_reduce( |
| 434 | + input_: torch.Tensor, |
| 435 | + group: ProcessGroup, |
| 436 | +) -> torch.Tensor: |
| 437 | + """Approximate SUM all-reduce with int8 bytes transported as BF16. |
| 438 | +
|
| 439 | + This does not use BF16 arithmetic. The BF16 tensor is only a 16-bit NCCL |
| 440 | + transport container for the existing int8 codes plus fp32 row scales. |
| 441 | + """ |
| 442 | + assert triton is not None |
| 443 | + world_size = dist.get_world_size(group) |
| 444 | + assert world_size == 3 |
| 445 | + rows, cols = input_.shape |
| 446 | + trace, trace_sync = _trace_enabled(input_) |
| 447 | + t0 = _mark_trace(trace, trace_sync, input_.device) |
| 448 | + q_nbytes = rows * cols |
| 449 | + send_bf16, gathered_bf16, total_nbytes = _int8_bf16pack_workspace( |
| 450 | + input_.device, world_size, rows, cols |
| 451 | + ) |
| 452 | + send = send_bf16.view(torch.uint8)[:total_nbytes] |
| 453 | + gathered = gathered_bf16.view(torch.uint8).view(world_size, -1)[:, :total_nbytes] |
| 454 | + q_local = send[:q_nbytes].view(rows, cols) |
| 455 | + s_local = send[q_nbytes:].view(torch.float32) |
| 456 | + block = triton.next_power_of_2(cols) |
| 457 | + _quantize_i8_row_kernel[(rows,)](input_, q_local, s_local, cols, block) |
| 458 | + t1 = _mark_trace(trace, trace_sync, input_.device) |
| 459 | + dist.all_gather_into_tensor(gathered_bf16, send_bf16, group=group) |
| 460 | + t2 = _mark_trace(trace, trace_sync, input_.device) |
| 461 | + out = torch.empty_like(input_) |
| 462 | + q_gathered = gathered[:, :q_nbytes].view(world_size, rows, cols) |
| 463 | + s_gathered = gathered[:, q_nbytes:].view(torch.float32).view(world_size, rows) |
| 464 | + _dequant_sum_i8_row_kernel[(rows,)]( |
| 465 | + q_gathered[0], q_gathered[1], q_gathered[2], |
| 466 | + s_gathered[0], s_gathered[1], s_gathered[2], |
| 467 | + out, cols, block, |
| 468 | + ) |
| 469 | + t3 = _mark_trace(trace, trace_sync, input_.device) |
| 470 | + if trace: |
| 471 | + logger.warning( |
| 472 | + "AG2_LOWBIT_REDUCE_TRACE mode=int8_bf16pack tokens=%d hidden=%d " |
| 473 | + "quant=%.6f gather=%.6f dequant=%.6f total=%.6f payload_mib=%.3f", |
| 474 | + rows, |
| 475 | + cols, |
| 476 | + t1 - t0, |
| 477 | + t2 - t1, |
| 478 | + t3 - t2, |
| 479 | + t3 - t0, |
| 480 | + send_bf16.numel() * send_bf16.element_size() / 2**20, |
| 481 | + ) |
| 482 | + return out |
| 483 | + |
| 484 | + |
406 | 485 | def tp3_int8_tensor_hidden_all_reduce( |
407 | 486 | input_: torch.Tensor, |
408 | 487 | group: ProcessGroup, |
@@ -588,6 +667,8 @@ def tp3_lowbit_hidden_all_reduce( |
588 | 667 | group: ProcessGroup, |
589 | 668 | mode: str, |
590 | 669 | ) -> torch.Tensor: |
| 670 | + if mode == "int8_bf16pack": |
| 671 | + return tp3_int8_bf16pack_hidden_all_reduce(input_, group) |
591 | 672 | if mode == "int8_shared_row": |
592 | 673 | return tp3_int8_shared_row_hidden_all_reduce(input_, group) |
593 | 674 | if mode == "int8_tensor": |
|
0 commit comments