Download code/tt_diffusion_planner/ttaw/ops/deform.py from changh95/diffusion-planner-p150: direct link, hf CLI and curl.
- Browser
- Download file 10.4 kB
-
https://huggingface.co/changh95/diffusion-planner-p150/resolve/main/code/tt_diffusion_planner/ttaw/ops/deform.py
- Command line
-
hf download hf://changh95/diffusion-planner-p150/code/tt_diffusion_planner/ttaw/ops/deform.py
-
curl -L -o deform.py https://huggingface.co/changh95/diffusion-planner-p150/resolve/main/code/tt_diffusion_planner/ttaw/ops/deform.py
10.4 kB
| # SPDX-License-Identifier: Apache-2.0 | |
| """C23: ``ttnn.grid_sample`` helpers (PLAN.md section 1.2 row C23; probe P9, common/PROBES.md; first built by the | |
| BEVDet port for AlignBEV and FPN_LSS). | |
| Rules from probe P9 (``common/probes/g4-attention-gridsample-msda.md``), enforced or encoded here: | |
| - **fp32 grids** for every data-dependent grid (bf16 grids cost PCC 0.9988 at 53 px and 0.992 at 128 px); | |
| - **input C % 32 == 0** (C = 80 is rejected; zero pad channels stay exactly 0): :func:`padded_channels`, | |
| :func:`pad_channels`; | |
| - **per-batch grids**: grid N must equal input N (no broadcast over the batch); | |
| - **ROW_MAJOR, interleaved (or height-sharded)** input and grid, ``padding_mode="zeros"`` only; | |
| - **never a FLOAT32 input together with ``fp32_dest_acc_en``**: wrong, non-deterministic output (strict xfail in P9); | |
| :func:`grid_sample` refuses it; | |
| - **exact integer coordinates**: the kernel recovers pixel coordinates as ``x = g * W/2 + (W - 1)/2`` in fp32 | |
| (``grid_sample_reader_common.hpp``, align_corners=False), so the align_corners=False normalisation | |
| ``g = (2x + 1) / W - 1`` returns integer x exactly whenever ``(2x + 1) / W`` is exact in fp32 (``W`` a power of | |
| two): an identity warp is then a bit-exact copy (P9: the literal align_corners=True normalisation leaves 2.8-7.6 % | |
| of values off by up to 1/32). Zero padding acts in pixel space, so the normalisation choice does not change what | |
| is sampled: callers state pixel coordinates (:func:`affine_grid`, :func:`resize_grid`) and always call the op with | |
| ``align_corners=False``; | |
| - the four bilinear weights are computed in fp32 and **truncated** (not rounded) to bf16 by the kernel: a 0.33-0.6 % | |
| rrmse floor for fractional coordinates (plan risk R3; K5 with fp32 weights removes it). :func:`emulate_grid_sample` | |
| reproduces that arithmetic on the host (the device test's oracle). | |
| Host functions are numpy only (grids are built on the host, per frame or once, and uploaded as fp32 ROW_MAJOR | |
| tensors); :func:`grid_sample` is the device call with the checks above. DCNv2 as one grid_sample with K = 9 | |
| (``batch_output_channels=True``, BEVFormer / METEOR) and the fused MSDA wrapper are added by their ports. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any, Optional, Sequence, Tuple | |
| import numpy as np | |
| __all__ = ["OUTSIDE", "padded_channels", "pad_channels", "pixel_to_grid", "kernel_pixels", "affine_pixel_coords", | |
| "affine_grid", "resize_pixel_coords", "resize_grid", "emulate_grid_sample", "grid_sample"] | |
| F32 = np.float32 | |
| # A normalised coordinate whose four taps fall outside any input (pixel -1.5 W - 0.5): the sample is exactly 0. | |
| OUTSIDE = F32(-4.0) | |
| def padded_channels(c: int, multiple: int = 32) -> int: | |
| """The channel count ``grid_sample`` accepts for ``c`` real channels (the next multiple of 32).""" | |
| return -(-int(c) // int(multiple)) * int(multiple) | |
| def pad_channels(x: np.ndarray, multiple: int = 32) -> np.ndarray: | |
| """Zero-pad the last (channel) dimension of an NHWC array to a multiple of ``multiple`` (no copy when aligned).""" | |
| x = np.asarray(x) | |
| c = x.shape[-1] | |
| cp = padded_channels(c, multiple) | |
| if cp == c: | |
| return x | |
| out = np.zeros(x.shape[:-1] + (cp,), x.dtype) | |
| out[..., :c] = x | |
| return out | |
| def pixel_to_grid(px: Any, size: int) -> np.ndarray: | |
| """Pixel coordinate (0 = centre of the first pixel) -> normalised coordinate for ``align_corners=False``: | |
| ``(2 px + 1) / size - 1`` in float32 (exact for integer ``px`` when ``size`` is a power of two).""" | |
| p = np.asarray(px, F32) | |
| return (F32(2.0) * p + F32(1.0)) / F32(size) - F32(1.0) | |
| def kernel_pixels(g: Any, size: int) -> np.ndarray: | |
| """The pixel coordinate the device kernel recovers from a normalised coordinate (align_corners=False): | |
| ``g * size/2 + (size - 1)/2`` in float32.""" | |
| g = np.asarray(g, F32) | |
| return g * F32(size / 2.0) + F32((size - 1) / 2.0) | |
| def affine_pixel_coords(transforms: np.ndarray, out_hw: Tuple[int, int]) -> Tuple[np.ndarray, np.ndarray]: | |
| """Per batch n and output pixel (h, w): ``ix = a w + b h + c``, ``iy = d w + e h + f`` in float32 with one | |
| rounding per operation (``transforms`` [N, 6] = (a, b, c, d, e, f), the BEVDet AlignBEV / BEVFormer-style pixel | |
| affine) -> (ix, iy) [N, H, W].""" | |
| t = np.asarray(transforms, F32).reshape(-1, 6) | |
| h, w = out_hw | |
| hh, ww = np.meshgrid(np.arange(h, dtype=F32), np.arange(w, dtype=F32), indexing="ij") | |
| a, b, c, d, e, f = (t[:, k, None, None] for k in range(6)) | |
| ix = (a * ww + b * hh) + c | |
| iy = (d * ww + e * hh) + f | |
| return ix.astype(F32), iy.astype(F32) | |
| def affine_grid(transforms: np.ndarray, in_hw: Tuple[int, int], out_hw: Optional[Tuple[int, int]] = None, *, | |
| valid: Optional[Sequence[bool]] = None) -> np.ndarray: | |
| """fp32 grid [N, H, W, 2] (x, y) sampling an ``in_hw`` input at :func:`affine_pixel_coords` (align_corners=False | |
| normalisation: identity transforms are bit-exact copies for power-of-two input sizes). Batches with | |
| ``valid[n] == False`` sample :data:`OUTSIDE` (exact zeros, e.g. a history slot that holds no frame yet).""" | |
| out_hw = tuple(in_hw) if out_hw is None else tuple(out_hw) | |
| ix, iy = affine_pixel_coords(transforms, out_hw) | |
| grid = np.stack([pixel_to_grid(ix, in_hw[1]), pixel_to_grid(iy, in_hw[0])], axis=-1).astype(F32) | |
| if valid is not None: | |
| v = np.asarray(valid, bool).reshape(-1) | |
| if v.size != grid.shape[0]: | |
| raise ValueError(f"valid has {v.size} entries for {grid.shape[0]} batches") | |
| grid[~v] = OUTSIDE | |
| return np.ascontiguousarray(grid) | |
| def resize_pixel_coords(in_size: int, out_size: int, align_corners: bool = True) -> np.ndarray: | |
| """Source pixel of every output pixel of a 1-D bilinear resize (float64), torch's ``F.interpolate`` rules: | |
| align_corners=True ``i (in - 1) / (out - 1)``; False ``(i + 0.5) in / out - 0.5`` (not clamped: the zero padding | |
| of grid_sample differs from torch's edge clamp there, so prefer C18 ``Resize2d`` for align_corners=False).""" | |
| i = np.arange(out_size, dtype=np.float64) | |
| if align_corners: | |
| return i * (in_size - 1) / max(out_size - 1, 1) | |
| return (i + 0.5) * in_size / out_size - 0.5 | |
| def resize_grid(in_hw: Tuple[int, int], out_hw: Tuple[int, int], *, align_corners: bool = True, | |
| batch: int = 1) -> np.ndarray: | |
| """Static fp32 grid [batch, Ho, Wo, 2] of a bilinear resize (source pixels in float64, normalised with the | |
| align_corners=False formula; call :func:`grid_sample`). For align_corners=True every source pixel lies inside | |
| the input, so the result equals ``F.interpolate(..., align_corners=True)`` up to the bf16 weight truncation.""" | |
| sy = resize_pixel_coords(in_hw[0], out_hw[0], align_corners) | |
| sx = resize_pixel_coords(in_hw[1], out_hw[1], align_corners) | |
| gx = ((2.0 * sx + 1.0) / in_hw[1] - 1.0).astype(F32) | |
| gy = ((2.0 * sy + 1.0) / in_hw[0] - 1.0).astype(F32) | |
| grid = np.empty((out_hw[0], out_hw[1], 2), F32) | |
| grid[..., 0] = gx[None, :] | |
| grid[..., 1] = gy[:, None] | |
| return np.ascontiguousarray(np.broadcast_to(grid, (int(batch),) + grid.shape)) | |
| def _truncate_bf16(a: np.ndarray) -> np.ndarray: | |
| bits = np.ascontiguousarray(a, F32).view(np.uint32) & np.uint32(0xFFFF0000) | |
| return bits.view(F32) | |
| def emulate_grid_sample(x: np.ndarray, grid: np.ndarray) -> np.ndarray: | |
| """Host emulation of the device's bilinear ``grid_sample`` (align_corners=False, zero padding): pixel recovery | |
| as :func:`kernel_pixels`, ``floor``, fp32 fractions and weights truncated to bf16, taps outside the input skipped. | |
| ``x`` [N, H, W, C], ``grid`` [N, Ho, Wo, 2] -> [N, Ho, Wo, C] float64 (the device sums the four bf16 products | |
| in its own order, so compare with a tolerance; an exact identity / outside sample is exact on both).""" | |
| x = np.asarray(x, np.float64) | |
| g = np.asarray(grid, F32) | |
| n, h, w, _ = x.shape | |
| px = kernel_pixels(g[..., 0], w) | |
| py = kernel_pixels(g[..., 1], h) | |
| x0 = np.floor(px).astype(np.int64) | |
| y0 = np.floor(py).astype(np.int64) | |
| fx = (px - x0.astype(F32)).astype(F32) | |
| fy = (py - y0.astype(F32)).astype(F32) | |
| one = F32(1.0) | |
| out = np.zeros(g.shape[:-1] + (x.shape[-1],), np.float64) | |
| bidx = np.arange(n)[:, None, None] | |
| for dy, wy in ((0, one - fy), (1, fy)): | |
| for dx, wx in ((0, one - fx), (1, fx)): | |
| yy, xx = y0 + dy, x0 + dx | |
| ok = (yy >= 0) & (yy < h) & (xx >= 0) & (xx < w) | |
| wgt = _truncate_bf16((wy * wx).astype(F32)).astype(np.float64) * ok | |
| vals = x[bidx, np.clip(yy, 0, h - 1), np.clip(xx, 0, w - 1)] | |
| out += vals * wgt[..., None] | |
| return out | |
| def grid_sample(x: Any, grid: Any, *, compute_kernel_config: Any = None, memory_config: Any = None, | |
| batch_output_channels: bool = False): | |
| """``ttnn.grid_sample(x, grid)``: bilinear, zero padding, ``align_corners=False`` (pair it with | |
| :func:`pixel_to_grid` / :func:`affine_grid` / :func:`resize_grid`), with the P9 rules checked before the call. | |
| The output goes to DRAM by default.""" | |
| import ttnn | |
| if x.layout != ttnn.ROW_MAJOR_LAYOUT or grid.layout != ttnn.ROW_MAJOR_LAYOUT: | |
| raise ValueError("grid_sample needs ROW_MAJOR input and grid") | |
| if int(x.padded_shape[-1]) % 32: | |
| raise ValueError(f"grid_sample input channels must be a multiple of 32, got {x.padded_shape[-1]} " | |
| "(pad them: deform.pad_channels)") | |
| if int(x.shape[0]) != int(grid.shape[0]): | |
| raise ValueError(f"grid batch {grid.shape[0]} != input batch {x.shape[0]} (expand the grid per batch)") | |
| if grid.dtype != ttnn.float32: | |
| raise ValueError("use an fp32 grid for data-dependent sampling (probe P9: bf16 grids lose PCC)") | |
| if x.dtype == ttnn.float32 and compute_kernel_config is not None and \ | |
| getattr(compute_kernel_config, "fp32_dest_acc_en", False): | |
| raise ValueError("a FLOAT32 input with fp32_dest_acc_en returns garbage (probe P9 defect)") | |
| return ttnn.grid_sample(x, grid, mode="bilinear", padding_mode="zeros", align_corners=False, | |
| use_precomputed_grid=False, batch_output_channels=batch_output_channels, | |
| memory_config=ttnn.DRAM_MEMORY_CONFIG if memory_config is None else memory_config, | |
| compute_kernel_config=compute_kernel_config) | |