Emit IR nodes for N-dimensional pooling. Decomposes pooling into: Transpose (channels-first -> channels-last) -> Pad (if needed) -> Reshape+Transpose (fast path) or AsStrided (general path) -> Max/Mean reduction over kernel dims -> Transpose (channels-last -> chann
(
P: MLXProgramBuilder,
n: Node,
ndim: int,
reduce_node_cls: type,
padding_value: float,
kernel_size: List[int],
stride: List[int],
padding: List[int],
)
| 3520 | |
| 3521 | |
| 3522 | def _emit_pool_nd( |
| 3523 | P: MLXProgramBuilder, |
| 3524 | n: Node, |
| 3525 | ndim: int, |
| 3526 | reduce_node_cls: type, |
| 3527 | padding_value: float, |
| 3528 | kernel_size: List[int], |
| 3529 | stride: List[int], |
| 3530 | padding: List[int], |
| 3531 | ) -> Slot: |
| 3532 | """Emit IR nodes for N-dimensional pooling. |
| 3533 | |
| 3534 | Decomposes pooling into: |
| 3535 | Transpose (channels-first -> channels-last) |
| 3536 | -> Pad (if needed) |
| 3537 | -> Reshape+Transpose (fast path) or AsStrided (general path) |
| 3538 | -> Max/Mean reduction over kernel dims |
| 3539 | -> Transpose (channels-last -> channels-first) |
| 3540 | |
| 3541 | Works for 1D, 2D, and 3D pooling uniformly. |
| 3542 | |
| 3543 | Args: |
| 3544 | P: Program builder. |
| 3545 | n: FX graph node for the pooling op. |
| 3546 | ndim: Spatial dimensionality (1, 2, or 3). |
| 3547 | reduce_node_cls: MaxNode or MeanNode. |
| 3548 | padding_value: Padding fill value (-inf for max, 0 for avg). |
| 3549 | kernel_size: Kernel size per spatial dim, length ndim. |
| 3550 | stride: Stride per spatial dim, length ndim. |
| 3551 | padding: Padding per spatial dim, length ndim. |
| 3552 | |
| 3553 | Returns: |
| 3554 | Output Slot with shape [N, C, *out_spatial]. |
| 3555 | """ |
| 3556 | x_node = P.args(n)[0] |
| 3557 | (x,) = P.slot_map([x_node]) |
| 3558 | x_meta = n.args[0].meta["val"] |
| 3559 | shape = list(x_meta.shape) # [N, C, *spatial] |
| 3560 | |
| 3561 | N = shape[0] |
| 3562 | C = shape[1] |
| 3563 | spatial = shape[2:] # length == ndim |
| 3564 | |
| 3565 | # 1. Transpose: channels-first [N, C, *spatial] -> channels-last [N, *spatial, C] |
| 3566 | to_cl = [0] + list(range(2, ndim + 2)) + [1] |
| 3567 | _, cur = P.make_tmp_slot() |
| 3568 | P.emit( |
| 3569 | TransposeNode( |
| 3570 | x=P.slot_to_tid(x), |
| 3571 | out=P.slot_to_tid(cur), |
| 3572 | perm=to_cl, |
| 3573 | ) |
| 3574 | ) |
| 3575 | |
| 3576 | # 2. Pad spatial dims if needed |
| 3577 | spatial_padded = [s + 2 * p for s, p in zip(spatial, padding)] |
| 3578 | if any(p > 0 for p in padding): |
| 3579 | pad_width = [0, 0] # batch dim: no pad |
no test coverage detected