Download code/tt_bevdet/reference/plugins.py from changh95/bevdet-p150: direct link, hf CLI and curl.
- Browser
- Download file 4.52 kB
-
https://huggingface.co/changh95/bevdet-p150/resolve/main/code/tt_bevdet/reference/plugins.py
- Command line
-
hf download hf://changh95/bevdet-p150/code/tt_bevdet/reference/plugins.py
-
curl -L -o plugins.py https://huggingface.co/changh95/bevdet-p150/resolve/main/code/tt_bevdet/reference/plugins.py
4.52 kB
| # SPDX-License-Identifier: Apache-2.0 | |
| """The three in-network TensorRT plugins of ``bevdet_one_lt_d.onnx`` in torch fp32 (the vendor fp32 path). | |
| Clean-room from research/bevdet/SPEC.md section 4.2 (no vendor code), ported from the verified research reference | |
| (``research/bevdet/scripts/bevdet_common.py``): | |
| - :func:`bev_pool`: ``bevdet::BEVPool``: ``out[c, ranks_bev[k]] += feat[ranks_feat[k] -> (n, c, hw)] * | |
| depth_flat[ranks_depth[k]]`` over every table entry, zero-initialised (the intended semantics; the TRT plugin | |
| leaves never-hit cells uninitialised, S:162). One ``index_add_`` in fp32. | |
| - :func:`align_bev`: ``bevdet::AlignBEV``: for history slot n and BEV pixel (h, w): ``ix = a w + b h + c``, | |
| ``iy = d w + e h + f`` (pixel coordinates), bilinear over the 4 neighbours with zero outside | |
| (= ``grid_sample(align_corners=True, padding_mode="zeros")``, as in training). The 4 taps are evaluated literally | |
| in float32 like the CUDA kernel, so an identity transform is an exact copy. | |
| - :func:`gather_bev`: ``bevdet::GatherBEV``: ``cat(curr, s_1 .. s_8)`` with ``s_j = aligned[j - 1]`` if ``flag`` | |
| else ``curr``; channel order [t, t-1, ..., t-8]. | |
| Inputs and outputs are torch tensors or numpy arrays (outputs: torch). The Preprocess plugin is host work | |
| (``host.preprocess``). | |
| """ | |
| from __future__ import annotations | |
| from typing import Any | |
| import numpy as np | |
| from ..host.calib import BEVPoolTables | |
| from .config import BEVDetConfig | |
| __all__ = ["bev_pool", "align_bev", "gather_bev"] | |
| def _t(x: Any): | |
| import torch | |
| return torch.as_tensor(np.asarray(x, np.float32)) if not isinstance(x, torch.Tensor) else x.to(torch.float32) | |
| def bev_pool(depth: Any, feat: Any, tables: BEVPoolTables, cfg: BEVDetConfig): | |
| """depth [N, D, H, W] (softmax), feat [N, C, H, W] -> curr [1, C, ny, nx] (fp32, cells never hit are 0).""" | |
| import torch | |
| depth_t, feat_t = _t(depth), _t(feat) | |
| N, C, H, W = feat_t.shape | |
| ny, nx = cfg.bev_hw | |
| nz = cfg.bev_xyz[2] | |
| dflat = depth_t.reshape(-1) | |
| fflat = feat_t.reshape(N, C, H * W).permute(1, 0, 2).reshape(C, N * H * W) | |
| rd = torch.from_numpy(tables.ranks_depth.astype(np.int64)) | |
| rf = torch.from_numpy(tables.ranks_feat.astype(np.int64)) | |
| rb = torch.from_numpy(tables.ranks_bev.astype(np.int64)) | |
| contrib = fflat[:, rf] * dflat[rd][None, :] | |
| out = torch.zeros(C, nx * ny * nz, dtype=torch.float32) | |
| out.index_add_(1, rb, contrib) | |
| return out.reshape(1, C, ny, nx) | |
| def align_bev(adj_feats: Any, transforms: Any): | |
| """adj_feats [1, A, C, H, W], transforms [1, A, 6] -> aligned [1, A, C, H, W] (bilinear, zero outside).""" | |
| import torch | |
| adj = _t(adj_feats) | |
| trs = _t(transforms) | |
| B, A, C, H, W = adj.shape | |
| out = torch.zeros_like(adj) | |
| hh, ww = torch.meshgrid(torch.arange(H, dtype=torch.float32), torch.arange(W, dtype=torch.float32), | |
| indexing="ij") | |
| identity = torch.tensor([1, 0, 0, 0, 1, 0], dtype=torch.float32) | |
| for n in range(A): | |
| if torch.equal(trs[0, n], identity): # one tap with weight 1, three with weight 0: a copy | |
| out[0, n] = adj[0, n] | |
| continue | |
| a, b, c0, d, e, f = (trs[0, n, k] for k in range(6)) | |
| ix = a * ww + b * hh + c0 # float32, like the kernel | |
| iy = d * ww + e * hh + f | |
| x0 = torch.floor(ix).double() | |
| y0 = torch.floor(iy).double() | |
| x1, y1 = x0 + 1, y0 + 1 | |
| ixd, iyd = ix.double(), iy.double() | |
| # weights: exact differences (float64), one rounding of the product to float32 (research reference) | |
| taps = ((y0, x0, (x1 - ixd) * (y1 - iyd)), (y0, x1, (ixd - x0) * (y1 - iyd)), | |
| (y1, x0, (x1 - ixd) * (iyd - y0)), (y1, x1, (ixd - x0) * (iyd - y0))) | |
| src = adj[0, n] | |
| acc = torch.zeros((C, H, W), dtype=torch.float32) | |
| for yy, xx, wt in taps: | |
| ok = (yy >= 0) & (yy < H) & (xx >= 0) & (xx < W) | |
| yi = yy.clamp(0, H - 1).long() | |
| xi = xx.clamp(0, W - 1).long() | |
| vals = src[:, yi, xi] | |
| acc += torch.where(ok[None], vals * wt.float()[None], torch.zeros((), dtype=torch.float32)) | |
| out[0, n] = acc | |
| return out | |
| def gather_bev(aligned: Any, curr: Any, flag: int): | |
| """aligned [1, A, C, H, W], curr [1, C, H, W] -> [1, (1 + A) C, H, W].""" | |
| import torch | |
| al, cu = _t(aligned), _t(curr) | |
| A = al.shape[1] | |
| parts = [cu[0]] + [cu[0] if int(flag) == 0 else al[0, n] for n in range(A)] | |
| return torch.cat(parts, 0)[None] | |