|
57 | 57 | KERNEL_CDF_DEFAULT_BANDWIDTH: float = 1.0 |
58 | 58 | KERNEL_CDF_DEFAULT_KNOTS: int = 64 |
59 | 59 |
|
| 60 | +# Queries per block of the forward-transform evaluation. The exact kernel sum |
| 61 | +# broadcasts an (M, N, 2) array; blocking the query dimension caps the peak at |
| 62 | +# (block, N, 2) — 512 queries × 15.4k points × 2 axes × 8 B ≈ 126 MB at |
| 63 | +# production imaging scale (previously ~60 GB unblocked at M ≈ 246k). Values |
| 64 | +# are identical to float precision: the sum over points is unchanged, blocks |
| 65 | +# only tile the query axis. |
| 66 | +KERNEL_FORWARD_BLOCK: int = 512 |
| 67 | + |
60 | 68 | _SQRT2 = np.sqrt(2.0) |
61 | 69 |
|
62 | 70 |
|
@@ -119,10 +127,34 @@ def create_transforms_kernel( |
119 | 127 | span = hi - lo |
120 | 128 | h = bandwidth * span / mesh_pixels |
121 | 129 |
|
122 | | - def F_raw(q): |
123 | | - t = (q[:, None, :] - points[None, :, :]) / h[None, None, :] |
| 130 | + def F_raw_block(q_block): |
| 131 | + t = (q_block[:, None, :] - points[None, :, :]) / h[None, None, :] |
124 | 132 | return xp.sum(w[None, :, None] * _norm_cdf(t, xp), axis=1) |
125 | 133 |
|
| 134 | + if xp.__name__.startswith("jax"): |
| 135 | + |
| 136 | + def F_raw(q): |
| 137 | + import jax |
| 138 | + |
| 139 | + M = q.shape[0] |
| 140 | + n_blocks = -(-M // KERNEL_FORWARD_BLOCK) |
| 141 | + pad = n_blocks * KERNEL_FORWARD_BLOCK - M |
| 142 | + q_padded = xp.pad(q, ((0, pad), (0, 0))) |
| 143 | + blocks = q_padded.reshape(n_blocks, KERNEL_FORWARD_BLOCK, 2) |
| 144 | + out = jax.lax.map(F_raw_block, blocks) |
| 145 | + return out.reshape(n_blocks * KERNEL_FORWARD_BLOCK, 2)[:M] |
| 146 | + |
| 147 | + else: |
| 148 | + |
| 149 | + def F_raw(q): |
| 150 | + return np.concatenate( |
| 151 | + [ |
| 152 | + F_raw_block(q[i : i + KERNEL_FORWARD_BLOCK]) |
| 153 | + for i in range(0, q.shape[0], KERNEL_FORWARD_BLOCK) |
| 154 | + ], |
| 155 | + axis=0, |
| 156 | + ) |
| 157 | + |
126 | 158 | # The unit square maps onto the data bounding box exactly, matching the |
127 | 159 | # linear variant's convention (its empirical-CDF knots end at the extreme |
128 | 160 | # points); the kernel tails outside [lo, hi] are absorbed by the rescale. |
|
0 commit comments