tensor-ee 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. tensor_ee/__init__.py +28 -0
  2. tensor_ee/_swin_parameters.py +304 -0
  3. tensor_ee/blocks/__init__.py +0 -0
  4. tensor_ee/blocks/raster/__init__.py +36 -0
  5. tensor_ee/blocks/raster/activations.py +183 -0
  6. tensor_ee/blocks/raster/conv.py +183 -0
  7. tensor_ee/blocks/raster/merge.py +66 -0
  8. tensor_ee/blocks/raster/outputs.py +211 -0
  9. tensor_ee/blocks/raster/pooling.py +182 -0
  10. tensor_ee/blocks/raster/resample.py +64 -0
  11. tensor_ee/blocks/window/__init__.py +44 -0
  12. tensor_ee/blocks/window/activations.py +54 -0
  13. tensor_ee/blocks/window/attention.py +366 -0
  14. tensor_ee/blocks/window/conv.py +323 -0
  15. tensor_ee/blocks/window/linear.py +129 -0
  16. tensor_ee/blocks/window/merge.py +67 -0
  17. tensor_ee/blocks/window/normalization.py +197 -0
  18. tensor_ee/blocks/window/patch.py +362 -0
  19. tensor_ee/blocks/window/pooling.py +275 -0
  20. tensor_ee/blocks/window/resample.py +286 -0
  21. tensor_ee/blocks/window/segformer.py +718 -0
  22. tensor_ee/blocks/window/swin.py +602 -0
  23. tensor_ee/blocks/window/swin_upernet_config.py +361 -0
  24. tensor_ee/blocks/window/upernet.py +1016 -0
  25. tensor_ee/comparison.py +213 -0
  26. tensor_ee/compatibility.py +180 -0
  27. tensor_ee/compiler.py +356 -0
  28. tensor_ee/converter/__init__.py +72 -0
  29. tensor_ee/converter/build.py +120 -0
  30. tensor_ee/converter/convert.py +388 -0
  31. tensor_ee/converter/export.py +846 -0
  32. tensor_ee/converter/graph.py +417 -0
  33. tensor_ee/converter/operations.py +790 -0
  34. tensor_ee/converter/plan.py +675 -0
  35. tensor_ee/converter/recognizers.py +1273 -0
  36. tensor_ee/converter/request.py +146 -0
  37. tensor_ee/converter/run.py +950 -0
  38. tensor_ee/core/__init__.py +8 -0
  39. tensor_ee/core/errors.py +25 -0
  40. tensor_ee/core/grid.py +323 -0
  41. tensor_ee/core/metadata.py +398 -0
  42. tensor_ee/core/ops.py +336 -0
  43. tensor_ee/core/precision.py +133 -0
  44. tensor_ee/core/tensor.py +129 -0
  45. tensor_ee/examples/__init__.py +1 -0
  46. tensor_ee/examples/nonwater.py +251 -0
  47. tensor_ee/layouts/__init__.py +17 -0
  48. tensor_ee/layouts/boundaries.py +103 -0
  49. tensor_ee/layouts/raster.py +117 -0
  50. tensor_ee/layouts/shift.py +226 -0
  51. tensor_ee/layouts/window.py +201 -0
  52. tensor_ee/models/__init__.py +16 -0
  53. tensor_ee/models/fixtures.py +119 -0
  54. tensor_ee/models/segformer_b0/__init__.py +9 -0
  55. tensor_ee/models/segformer_b0/configuration.py +209 -0
  56. tensor_ee/models/segformer_b0/decoder.py +130 -0
  57. tensor_ee/models/segformer_b0/encoder.py +90 -0
  58. tensor_ee/models/swin_t224/__init__.py +30 -0
  59. tensor_ee/models/swin_t224/configuration.py +103 -0
  60. tensor_ee/models/swin_t224/decoder.py +53 -0
  61. tensor_ee/models/swin_t224/encoder.py +50 -0
  62. tensor_ee/onnx_import.py +431 -0
  63. tensor_ee/outputs.py +16 -0
  64. tensor_ee/primitives.py +110 -0
  65. tensor_ee/receptive_field.py +257 -0
  66. tensor_ee/resnet_models.py +185 -0
  67. tensor_ee/segwater_inference.py +235 -0
  68. tensor_ee/segwater_preprocessing.py +182 -0
  69. tensor_ee/segwater_pytorch.py +249 -0
  70. tensor_ee/semantics.py +389 -0
  71. tensor_ee/smp.py +155 -0
  72. tensor_ee/swin.py +197 -0
  73. tensor_ee/swin_workflow.py +470 -0
  74. tensor_ee/tiling.py +287 -0
  75. tensor_ee/weight_assets.py +371 -0
  76. tensor_ee/weight_mapping.py +51 -0
  77. tensor_ee/weights/__init__.py +14 -0
  78. tensor_ee/weights/assets.py +160 -0
  79. tensor_ee/weights/constants.py +156 -0
  80. tensor_ee-0.1.0.dist-info/METADATA +172 -0
  81. tensor_ee-0.1.0.dist-info/RECORD +84 -0
  82. tensor_ee-0.1.0.dist-info/WHEEL +5 -0
  83. tensor_ee-0.1.0.dist-info/licenses/LICENSE +21 -0
  84. tensor_ee-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,323 @@
1
+ """The window-layout 3 x 3 convolution and its input-channel groups.
2
+
3
+ Moved from ``upernet/earth_engine/conv2d.py`` (``Conv3x3Constants``, ``conv3x3_window``
4
+ and its helper ``_finish``) and ``upernet/earth_engine/fusion.py`` (``group_weight``,
5
+ ``group_product``), research code archived at the tag ``research-archive-2026-10-12``
6
+ (docs/history/README.md). The dense formulations (``dense_im2col``, ``conv3x3_dense``,
7
+ ``conv_convolve``) were research only; the fusion composites are with the model.
8
+
9
+ Inference Conv2d (stride 1, dilation 1, groups 1, zero padding k // 2), PyTorch
10
+ semantics (weight [Cout, Cin, kh, kw], padding p = k // 2):
11
+
12
+ y[o, i, j] = b[o] + sum_{c, ky, kx} W[o, c, ky, kx] * x_pad[c, i + ky, j + kx]
13
+
14
+ i.e. an im2col matrix product: the zero-padded k x k neighbourhood of each token as a
15
+ row in (ky, kx, c) order times W^T [k*k*Cin, Cout] in the same row order (the weight
16
+ permutation (o, c, ky, kx) -> (ky, kx, c, o) is applied once, to the constant). In
17
+ window layout the neighbourhood is the [w + 2, w + 2, C] halo of each window (its
18
+ one-token ring from the 8 neighbouring windows, zeros outside the raster):
19
+ ``tensor_ee.layouts.window.halo`` and ``im2col``.
20
+
21
+ **Policy** ``double_round_once``: EE's matrixMultiply accumulates every dot product
22
+ sequentially in double; the bias is added in double and the sum rounded to float32
23
+ once. ``group_product`` leaves its partial in double (no rounding): the fusion's
24
+ ``grouped_double`` variant sums the four group partials in double before its one
25
+ rounding, so ``group_product`` accepts both ``double_round_once`` and
26
+ ``grouped_double``.
27
+
28
+ The research ``window_taps`` method (nine [N, Cin] x [Cin, Cout] products summed in
29
+ double, with per-tap constants) was removed when the research code was archived; the im2col product is the only form.
30
+ Kernel 3, window 7 and 4 groups are the defaults. The 3 x 3 kernel is the window
31
+ convolution's identity, not a setting: other kernels are refused. ``conv3x3_window`` is
32
+ validated at windows 5, 7, 8 and 12. ``group_product`` is validated at 1, 2, 4 and 8
33
+ contiguous input-channel groups, at windows 7 and 12, and at 4 groups at window 8 (the
34
+ window-8 Swin-UPerNet validation model's fusion), its partials summed in double in group order and rounded once by
35
+ the caller, against the unsplit convolution. Other group counts and windows are not
36
+ validated.
37
+
38
+ ``depthwise_conv3x3_window`` computes y[d] = bias[d] + sum_t x[t,d] weight[d,t].
39
+ Its halo/im2col taps are [rows,9,D], multiplied once in double and reduced over
40
+ the nine taps in double, with one final float32 rounding. Weights and optional
41
+ bias are pre-repeated to the layout rows. Live coverage is window7, D4 with/without
42
+ bias, D1024 with bias, and D16 with bias within the C4/D16 Mix-FFN fixture.
43
+ Other widths/windows and ServerArray asset transport have no live coverage here.
44
+ """
45
+
46
+ from __future__ import annotations
47
+
48
+ import operator
49
+
50
+ import numpy as np
51
+
52
+ from ...core.errors import reject
53
+ from ...core.metadata import BlockMetadata, Locality, Validated, validate_metadata
54
+ from ...core.ops import WindowOps
55
+ from ...core.precision import DOUBLE_ROUND_ONCE, GROUPED_DOUBLE, validate_policy
56
+ from ...core.tensor import WINDOW
57
+ from ...layouts.window import halo, im2col
58
+ from ...weights.constants import ServerArray, WindowLayout, check_rows, constant_value
59
+ from .linear import WINDOW_LAYOUT, builder_rows
60
+
61
+ KERNEL = 3
62
+ """The window convolution's kernel: its identity (other kernels are refused)."""
63
+
64
+ GROUPS = 4
65
+ """Default input-channel groups of the fusion convolution (the model's four levels). 1, 2,
66
+ 4 and 8 groups are validated."""
67
+
68
+
69
+ def _depthwise_parameter(value, name):
70
+ """Validate coefficient transport before building any new depthwise expression."""
71
+ if isinstance(value, ServerArray):
72
+ shape = value.shape
73
+ if not isinstance(shape, (tuple, list)) or any(
74
+ isinstance(n, bool) or not isinstance(n, (int, np.integer)) or n < 1 for n in shape):
75
+ reject(f"depthwise {name} shape must contain positive integer dimensions; received {shape!r}")
76
+ return value
77
+ try:
78
+ with np.errstate(over="ignore", invalid="ignore"):
79
+ array = np.asarray(value, dtype=np.float32)
80
+ except (TypeError, ValueError):
81
+ reject(f"depthwise {name} must contain float32 coefficients")
82
+ if not np.isfinite(array).all():
83
+ reject(f"depthwise {name} coefficients must be finite float32 values")
84
+ return array
85
+
86
+
87
+ class DepthwiseConv3x3Constants:
88
+ """Depthwise [D,1,3,3] NumPy or [D,9] ServerArray weights, pre-repeated
89
+ as [rows,9,D] in double; optional [D] bias repeated as [rows,D].
90
+
91
+ Only kernel3, stride1, padding1, dilation1 and multiplier1 are supported.
92
+ ``rows`` is the window layout or its positive row count; consumption checks it.
93
+ """
94
+
95
+ def __init__(self, ops, weight, bias=None, rows=WINDOW_LAYOUT, *, k=3,
96
+ stride=1, padding=1, dilation=1, multiplier=1,
97
+ policy: str = DOUBLE_ROUND_ONCE):
98
+ self.policy = validate_policy(policy, allowed=DOUBLE_ROUND_ONCE)
99
+ for name, value, expected in (("k", k, 3), ("stride", stride, 1),
100
+ ("padding", padding, 1), ("dilation", dilation, 1),
101
+ ("multiplier", multiplier, 1)):
102
+ if isinstance(value, bool) or not isinstance(value, (int, np.integer)) or value != expected:
103
+ reject(f"depthwise_conv3x3_window requires {name}={expected}; received {value!r}")
104
+ weight = _depthwise_parameter(weight, "weight")
105
+ if bias is not None:
106
+ bias = _depthwise_parameter(bias, "bias")
107
+ shape = weight.shape
108
+ expected = (9,) if isinstance(weight, ServerArray) else (1, 3, 3)
109
+ if len(shape) != len(expected) + 1 or tuple(shape[1:]) != expected or shape[0] < 1:
110
+ reject(f"depthwise weight must be [D,9] ServerArray or [D,1,3,3] NumPy; received {shape}")
111
+ self.channels = int(shape[0])
112
+ if bias is not None and tuple(bias.shape if isinstance(bias, ServerArray) else np.shape(bias)) != (self.channels,):
113
+ reject(f"depthwise bias must be [{self.channels}]")
114
+ self.rows = builder_rows(rows)
115
+ source = constant_value(ops.ee, weight)
116
+ repeated = source.reshape([self.channels, 9]).transpose().reshape([1, 9, self.channels]).repeat(0, self.rows)
117
+ self.weight = ops.to_double(ops.wrap(repeated))
118
+ self.bias = None if bias is None else ops.constant(bias, repeat_rows=self.rows)
119
+
120
+ @property
121
+ def embedded_values(self) -> int:
122
+ return depthwise_conv3x3_values(self.channels, bias=self.bias is not None, layout=self.rows)
123
+
124
+
125
+ def depthwise_conv3x3_window(ops, x, c: DepthwiseConv3x3Constants, coarse, *,
126
+ window: int = WINDOW, policy: str = DOUBLE_ROUND_ONCE):
127
+ """W [window²,D] → W [window²,D], finite-chip zero padding, radius1.
128
+
129
+ One double product and one nine-tap double reduction, optional double bias
130
+ addition, then one float32 output cast. Live window7 coverage: D4 optional
131
+ bias, D1024 biased, D16 biased within C4/D16 Mix-FFN. Constants for mismatched
132
+ rows/policy are refused; other widths/windows are not live validated here.
133
+ """
134
+ validate_policy(policy, allowed=DOUBLE_ROUND_ONCE)
135
+ if c.policy != policy:
136
+ reject("depthwise constants and block precision policies differ")
137
+ check_rows(c, WindowLayout(window))
138
+ neighbourhood = halo(ops.ee, x, coarse, c.channels, window=window, ring=1)
139
+ columns = im2col(ops.ee, neighbourhood, c.channels, 3, window=window)
140
+ taps = ops.reshape(ops.to_double(columns), [c.rows, 9, c.channels])
141
+ product = taps.multiply(c.weight)
142
+ # row_total reduces axis1: put all nine taps in that axis, one row per token/channel.
143
+ products = ops.reshape(ops.transpose(product, 1, 2), [c.rows * c.channels, 9])
144
+ total = ops.reshape(ops.row_total(products), [c.rows, c.channels])
145
+ return ops.to_float(total if c.bias is None else total.add(c.bias))
146
+
147
+
148
+ class Conv3x3Constants:
149
+ """W^T of a k x k convolution in (ky, kx, c) row order, [k*k*Cin, Cout]; the bias with
150
+ rows repeated (None: bias-free conv).
151
+
152
+ weight: NumPy [Cout, Cin, k, k] or a ServerArray [Cout, Cin * k * k] in PyTorch's
153
+ flatten order (c, ky, kx) (the asset format); the permutation runs on the server.
154
+ ``rows``: the layout the bias serves (default ``WindowLayout(7)``: 49 rows) or its
155
+ row count; recorded as ``rows``."""
156
+
157
+ def __init__(self, ops, weight, bias=None, rows=WINDOW_LAYOUT, k: int = KERNEL):
158
+ ee = ops.ee
159
+ if isinstance(weight, ServerArray):
160
+ cout, flat = weight.shape
161
+ if flat % (k * k):
162
+ raise ValueError(f"a [Cout, Cin * {k * k}] weight cannot have {flat} columns (kernel {k})")
163
+ cin = flat // (k * k)
164
+ w = (weight.array.reshape([cout, cin, k * k]).transpose(1, 2) # [Cout, kk, Cin]
165
+ .reshape([cout, k * k * cin]).transpose()) # [kk Cin, Cout]
166
+ else:
167
+ weight = np.asarray(weight, dtype=np.float32)
168
+ cout, cin = weight.shape[:2]
169
+ w = constant_value(ee, weight.transpose(2, 3, 1, 0).reshape(k * k * cin, cout))
170
+ self.k, self.cin, self.cout = k, cin, cout
171
+ self.rows = builder_rows(rows)
172
+ self.weight_t = ops.wrap(w)
173
+ self.bias = None if bias is None else ops.constant(bias, repeat_rows=self.rows)
174
+
175
+ @property
176
+ def embedded_values(self) -> int:
177
+ bias_rows = 0 if self.bias is None else self.cout
178
+ return self.k * self.k * self.cin * self.cout + bias_rows
179
+
180
+
181
+ def _finish(ops, product, c: Conv3x3Constants):
182
+ return ops.to_float(product if c.bias is None else product.add(c.bias))
183
+
184
+
185
+ def _check_kernel(c: Conv3x3Constants) -> None:
186
+ """The window convolution reads a one-token ring (``halo``) and taps at offsets -1, 0
187
+ and 1 (``taps``): its kernel is 3 x 3, the block's identity. Constants built for another
188
+ kernel are refused (client-side; the graph is unchanged)."""
189
+ if c.k != KERNEL:
190
+ raise ValueError(f"the window convolution is {KERNEL} x {KERNEL}; constants were built for k = {c.k}")
191
+
192
+
193
+ def conv3x3_window(ops, x, c: Conv3x3Constants, coarse, *, window: int = WINDOW,
194
+ policy: str = DOUBLE_ROUND_ONCE):
195
+ """Window layout [w^2, Cin] on the window grid `coarse` -> [w^2, Cout] (zero padding at
196
+ the raster edge, exactly PyTorch's). Constants built for another row count than
197
+ ``window ** 2`` are refused, and so are constants for another kernel than 3 x 3, the
198
+ block's identity. Validated at windows 5, 7, 8 and 12."""
199
+ validate_policy(policy, allowed=DOUBLE_ROUND_ONCE)
200
+ _check_kernel(c)
201
+ check_rows(c, WindowLayout(window))
202
+ ee = ops.ee
203
+ halo3 = halo(ee, x, coarse, c.cin, window=window)
204
+ return _finish(ops, ops.matmul_double(im2col(ee, halo3, c.cin, c.k, window=window), c.weight_t), c)
205
+
206
+
207
+ def group_weight(weight, g: int, groups: int = GROUPS):
208
+ """W_g, input-channel group g of a [Cout, Cin, 3, 3] weight: channels
209
+ [g Cin / groups, (g + 1) Cin / groups), the g-th of ``groups`` contiguous groups in
210
+ channel order. As an asset ServerArray [Cout, Cin * 9] in PyTorch's flatten order
211
+ (c, ky, kx), group g is the contiguous column slice [g Cin * 9 / groups,
212
+ (g + 1) Cin * 9 / groups).
213
+
214
+ ``groups`` must divide Cin and 0 <= g < groups; otherwise the slice would drop or share
215
+ channels, so it is refused (client-side; the graph is unchanged)."""
216
+ groups, g = operator.index(groups), operator.index(g)
217
+ if groups < 1 or not 0 <= g < groups:
218
+ raise ValueError(f"group {g} of {groups} groups does not exist")
219
+ if isinstance(weight, ServerArray):
220
+ cout, flat = weight.shape
221
+ if flat % (KERNEL * KERNEL) or (flat // (KERNEL * KERNEL)) % groups:
222
+ raise ValueError(f"{groups} groups do not split the {flat} columns of a "
223
+ f"[Cout, Cin * {KERNEL * KERNEL}] weight into whole channels")
224
+ width = flat // groups
225
+ return ServerArray(weight.array.slice(1, g * width, (g + 1) * width), (cout, width))
226
+ w = np.asarray(weight, np.float32)
227
+ if w.ndim != 4 or w.shape[2:] != (KERNEL, KERNEL):
228
+ raise ValueError(f"expected a [Cout, Cin, {KERNEL}, {KERNEL}] weight; received {w.shape}")
229
+ if w.shape[1] % groups:
230
+ raise ValueError(f"{groups} groups do not split {w.shape[1]} input channels evenly")
231
+ width = w.shape[1] // groups
232
+ return w[:, g * width:(g + 1) * width]
233
+
234
+
235
+ def group_product(ee, part, w: Conv3x3Constants, *, policy: str = DOUBLE_ROUND_ONCE):
236
+ """X_g's [w^2, 9 C_g] im2col times W_g^T, left in double (no rounding).
237
+
238
+ ``part`` is a W tensor (the decoder's ``Feature``); its window gives the halo and
239
+ the rows the constants must have. Policy ``double_round_once`` (the default) or its
240
+ ``grouped_double`` variant: the caller rounds once, after summing the groups. Validated
241
+ at 1, 2, 4 and 8 groups (``group_weight``) at windows 7 and 12, and at 4 groups at
242
+ window 8, with the partials summed in double in group order and rounded once."""
243
+ validate_policy(policy, allowed=(DOUBLE_ROUND_ONCE, GROUPED_DOUBLE))
244
+ _check_kernel(w)
245
+ check_rows(w, part)
246
+ img = WindowOps(ee)
247
+ halo3 = halo(ee, part.image, part.grid.coarse(part.window), w.cin, window=part.window)
248
+ return img.matmul_double(im2col(ee, halo3, w.cin, w.k, window=part.window), w.weight_t)
249
+
250
+
251
+ # ---------------------------------------------------------------------------
252
+ # Cost functions (contract section 9)
253
+ # ---------------------------------------------------------------------------
254
+ def conv3x3_values(cin: int, cout: int, *, k: int = KERNEL, bias: bool = False, layout=WINDOW_LAYOUT) -> int:
255
+ """Values of the constants: W^T [k*k*Cin, Cout], plus the bias rows [rows, Cout] (the
256
+ research budgets' convention; ``Conv3x3Constants.embedded_values`` counts a bias as
257
+ Cout values, before the server-side repeat)."""
258
+ return k * k * cin * cout + (builder_rows(layout) * cout if bias else 0)
259
+
260
+
261
+ def conv3x3_arrays(*, bias: bool = False) -> int:
262
+ """Server arrays read for ServerArray weights: the weight, and the bias if any."""
263
+ return 2 if bias else 1
264
+
265
+
266
+ def group_product_values(cin: int, cout: int, *, k: int = KERNEL) -> int:
267
+ """Values of one group's W_g^T [k*k*C_g, Cout] (C_g = Cin / groups): the groups
268
+ together embed the weight once, as column slices."""
269
+ return k * k * cin * cout
270
+
271
+
272
+ def group_product_arrays() -> int:
273
+ """Server arrays read: the group's column slice of the one weight array."""
274
+ return 1
275
+
276
+
277
+ def depthwise_conv3x3_values(channels: int, *, bias: bool = True, layout=WINDOW_LAYOUT) -> int:
278
+ """Evaluated repeated weights [rows,9,D] and optional bias [rows,D]."""
279
+ return builder_rows(layout) * channels * (9 + int(bias))
280
+
281
+
282
+ def depthwise_conv3x3_arrays(*, bias: bool = True) -> int:
283
+ """Source ServerArrays: one weight and optional one bias; repeats are expressions."""
284
+ return 2 if bias else 1
285
+
286
+
287
+ METADATA = validate_metadata({
288
+ "depthwise_conv3x3_window": BlockMetadata(
289
+ name="depthwise_conv3x3_window", layout_in="W", layout_out="W",
290
+ locality=Locality.WINDOW_RING, radius=1,
291
+ policy=DOUBLE_ROUND_ONCE, embedded_constants=depthwise_conv3x3_values,
292
+ asset_arrays=depthwise_conv3x3_arrays,
293
+ status="Ready — 3 × 3, stride1, padding1, dilation1, multiplier1; window7; D4 optional bias, D1024 biased; D16 biased in C4/D16 Mix-FFN",
294
+ evidence=("docs/evidence/segformer_b0-offline.json", "docs/evidence/segformer_b0-live.json"),
295
+ # Validated: the status's form at window 7, with the channel counts (D) and bias it names.
296
+ validated=Validated(tuple(
297
+ {"k": (3,), "stride": (1,), "padding": (1,), "dilation": (1,), "multiplier": (1,), "window": (7,),
298
+ "channels": channels, "bias": bias}
299
+ for channels, bias in (((4,), (True, False)), ((16, 1024), (True,)))),
300
+ sources=(DepthwiseConv3x3Constants,))),
301
+ "conv3x3_window": BlockMetadata(
302
+ name="conv3x3_window", layout_in="W", layout_out="W", locality=Locality.WINDOW_RING, radius=1,
303
+ policy=DOUBLE_ROUND_ONCE, embedded_constants=conv3x3_values, asset_arrays=conv3x3_arrays,
304
+ status="Ready — 3 × 3 kernel, stride 1; windows 5, 7, 8, 12",
305
+ evidence=("docs/history/building-blocks-2026-10-11.md#33-convolution", "docs/history/upernet/notes/milestone7_findings.md",
306
+ "docs/evidence/p01-offline.json",
307
+ "docs/evidence/live-fixtures/20261013T074301Z-p01a.json", "docs/evidence/live-fixtures/20261013T074330Z-p01b.json", "docs/evidence/live-fixtures/20261013T075542Z-window-relative_position_bias-w12.json",
308
+ "docs/evidence/live-fixtures/20261013T115558Z-p04.json"), # decoder-setting validation live record
309
+ # The 3 x 3 kernel is the block's identity (k, refused otherwise); stride 1 is its only stride.
310
+ validated=Validated(({"k": (KERNEL,), "window": (5, 7, 8, 12)},), sources=(Conv3x3Constants,))),
311
+ "group_product": BlockMetadata(
312
+ name="group_product", layout_in="W", layout_out="W", locality=Locality.WINDOW_RING, radius=1,
313
+ policy=DOUBLE_ROUND_ONCE, embedded_constants=group_product_values, asset_arrays=group_product_arrays,
314
+ status="Ready — 1, 2, 4, 8 groups at windows 7, 12; 4 groups at window 8",
315
+ evidence=("docs/history/building-blocks-2026-10-11.md#33-convolution", "variant: grouped_double",
316
+ "docs/history/upernet/notes/milestone10_findings.md", "docs/evidence/p04-offline.json",
317
+ "docs/evidence/live-fixtures/20261013T115558Z-p04.json", "docs/evidence/c0b-offline.json",
318
+ "docs/evidence/live-fixtures/20261013T154410Z-c0b.json"),
319
+ # groups is group_weight's; the 3 x 3 kernel (k) never varied.
320
+ validated=Validated(({"groups": (1, 2, 4, 8), "k": (KERNEL,), "window": (7, 12)},
321
+ {"groups": (4,), "k": (KERNEL,), "window": (8,)}),
322
+ sources=(group_weight, Conv3x3Constants))),
323
+ })
@@ -0,0 +1,129 @@
1
+ """The linear layer y = x W^T + b (torch.nn.Linear) per token, and the 1 x 1 convolution.
2
+
3
+ Moved from ``swin_block/earth_engine/linear.py`` (``LinearConstants``, ``linear``)
4
+ and ``upernet/earth_engine/conv2d.py`` (``conv1x1_constants``, ``conv1x1``), research
5
+ code archived at the tag ``research-archive-2026-10-12`` (docs/history/README.md).
6
+
7
+ One primitive serves every projection of the Swin block (QKV, attention output,
8
+ MLP fc1/fc2), Patch Merging's reduction, the patch-embedding projection and the
9
+ decoder's 1 x 1 convolutions. In window layout a whole window is one matrix
10
+ product, [N, in] x [in, out] per pixel, against a constant W^T; on a value (V) it
11
+ is the same product on an ee.Array.
12
+
13
+ **Policy** ``double_round_once``: matrixMultiply accumulates the float32 operands
14
+ in double (window-attention validation: its results rounded to float32 equal the correctly rounded
15
+ float64 dot products); the bias is added in double and the sum is rounded to
16
+ float32 once.
17
+
18
+ **Rows.** The bias is pre-repeated to the rows of the layout it serves (EE arrays
19
+ do not broadcast): ``WindowLayout(7)`` -> 49, ``WindowLayout(1)`` -> 1, a V value
20
+ -> its row count. Builders take that layout (or tensor), as the reference-model composites pass
21
+ it, or a row count, the builders' original call form (still accepted), and record
22
+ ``rows``. A block given ``layout=`` refuses constants built for another one
23
+ (client-side only).
24
+ Windows 5, 7, 8 and 12 (and one-row dense constants) are validated live (including the window-size checks).
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import numpy as np
30
+
31
+ from ...core.metadata import ANY_SETTINGS, BlockMetadata, Locality, validate_metadata
32
+ from ...core.precision import DOUBLE_ROUND_ONCE, validate_policy
33
+ from ...weights.constants import ServerArray, ValueLayout, WindowLayout, check_rows, constant_rows
34
+
35
+ WINDOW_LAYOUT = WindowLayout()
36
+ """Today's layout: window 7, 49 rows per constant (the only one validated live)."""
37
+
38
+
39
+ def as_layout(layout):
40
+ """``layout`` itself (a ``WindowLayout``, ``ValueLayout``, ``WindowTensor`` or 2-D V
41
+ value), or a positive ``int`` row count, the builders' original call form (still
42
+ accepted; the reference-model composites pass layouts), as the ``ValueLayout`` with that many rows:
43
+ only the count matters to a per-channel constant."""
44
+ if isinstance(layout, (int, np.integer)) and not isinstance(layout, bool):
45
+ return ValueLayout(int(layout))
46
+ return layout
47
+
48
+
49
+ def builder_rows(layout) -> int:
50
+ """Rows of a per-channel constant for ``layout`` (see ``as_layout``):
51
+ ``tensor_ee.weights.constants.constant_rows``."""
52
+ return constant_rows(as_layout(layout))
53
+
54
+
55
+ def no_constants(**parameters) -> int:
56
+ """Cost function of a block that embeds and reads no constants."""
57
+ return 0
58
+
59
+
60
+ class LinearConstants:
61
+ """W^T [in, out] and the bias with rows repeated to [rows, out].
62
+
63
+ weight and bias are NumPy arrays or ServerArrays. bias=None is a layer without
64
+ bias (torch.nn.Linear(bias=False), e.g. Patch Merging's reduction): no addition
65
+ at all, not the addition of zeros. ``tokens`` is the layout the bias serves
66
+ (or its row count; see ``builder_rows``); ``rows`` records it.
67
+ """
68
+
69
+ def __init__(self, ops, weight, bias, tokens):
70
+ if not isinstance(weight, ServerArray):
71
+ weight = np.asarray(weight, dtype=np.float32)
72
+ self.in_features, self.out_features = weight.shape[1], weight.shape[0]
73
+ self.rows = builder_rows(tokens)
74
+ self.weight_t = ops.constant(weight.T)
75
+ self.bias = None if bias is None else ops.constant(bias, repeat_rows=self.rows)
76
+
77
+
78
+ def linear(ops, x, layer: LinearConstants, *, policy: str = DOUBLE_ROUND_ONCE, layout=None):
79
+ """x: float32 [N, in] -> float32 [N, out].
80
+
81
+ ``layout``, when given (the layout x is in: a ``WindowTensor``, ``WindowLayout``
82
+ or ``ValueLayout``), refuses constants built for another row count."""
83
+ validate_policy(policy, allowed=DOUBLE_ROUND_ONCE)
84
+ if layout is not None:
85
+ check_rows(layer, as_layout(layout))
86
+ product = ops.matmul_double(x, layer.weight_t)
87
+ return ops.to_float(product if layer.bias is None else product.add(layer.bias))
88
+
89
+
90
+ def conv1x1_constants(ops, weight, bias, rows) -> LinearConstants:
91
+ """Conv2d 1 x 1 weight [Cout, Cin, 1, 1] (or [Cout, Cin]) -> the Swin block's linear.
92
+ ``rows``: the layout the bias serves, or its row count."""
93
+ if not isinstance(weight, ServerArray):
94
+ weight = np.asarray(weight, dtype=np.float32).reshape(np.shape(weight)[0], -1)
95
+ return LinearConstants(ops, weight, bias, rows)
96
+
97
+
98
+ def conv1x1(ops, x, layer: LinearConstants, *, policy: str = DOUBLE_ROUND_ONCE, layout=None):
99
+ """x: float32 [rows, Cin] arrays -> [rows, Cout] (exactly ``linear``)."""
100
+ return linear(ops, x, layer, policy=policy, layout=layout)
101
+
102
+
103
+ # ---------------------------------------------------------------------------
104
+ # Cost functions (contract section 9)
105
+ # ---------------------------------------------------------------------------
106
+ def linear_values(in_features: int, out_features: int, *, bias: bool = True, layout=WINDOW_LAYOUT) -> int:
107
+ """Values embedded for NumPy weights: W^T [in, out], plus the bias rows [rows, out]."""
108
+ return in_features * out_features + (builder_rows(layout) * out_features if bias else 0)
109
+
110
+
111
+ def linear_arrays(*, bias: bool = True) -> int:
112
+ """Server arrays read for ServerArray weights: the weight, and the bias if any."""
113
+ return 2 if bias else 1
114
+
115
+
116
+ METADATA = validate_metadata({
117
+ "linear": BlockMetadata(
118
+ name="linear", layout_in="W", layout_out="W", locality=Locality.POINTWISE,
119
+ policy=DOUBLE_ROUND_ONCE, embedded_constants=linear_values, asset_arrays=linear_arrays,
120
+ status="Ready",
121
+ evidence=("docs/history/building-blocks-2026-10-11.md#36-linear-layers-and-attention", "docs/history/swin_block/notes/findings.md"),
122
+ validated=ANY_SETTINGS),
123
+ "conv1x1": BlockMetadata(
124
+ name="conv1x1", layout_in="W", layout_out="W", locality=Locality.POINTWISE,
125
+ policy=DOUBLE_ROUND_ONCE, embedded_constants=linear_values, asset_arrays=linear_arrays,
126
+ status="Ready",
127
+ evidence=("docs/history/building-blocks-2026-10-11.md#33-convolution", "docs/history/upernet/notes/milestone7_findings.md"),
128
+ validated=ANY_SETTINGS),
129
+ })
@@ -0,0 +1,67 @@
1
+ """W merges: the FPN's addition and the channel concatenation.
2
+
3
+ Moved from ``upernet/earth_engine/feature_ops.py`` (``add``, ``concat``), research code
4
+ archived at the tag ``research-archive-2026-10-12`` (docs/history/README.md). The
5
+ operands are W tensors (the decoder's ``Feature``)
6
+ carried with their grid and layout, so operands that do not share a grid, layout or
7
+ window are refused client-side (``same_grid``). Earth Engine itself would not refuse
8
+ them: binary operations on images of different grids are evaluated in the request's
9
+ projection with each input resampled (nearest), which silently replicates coarse values.
10
+
11
+ - ``add``: float32 + float32 -> float32; EE rounds the exact sum once, as IEEE / PyTorch
12
+ do (policy ``double_round_once``: one rounding at the operation boundary).
13
+ - ``concat``: torch.cat(dim=1) order (first operand's channels first); window layout
14
+ ``arrayCat`` on axis 1, dense bands renamed and stacked. Values are moved, never
15
+ rounded: no arithmetic, no cast, no policy.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from ...core.errors import GridMismatch
21
+ from ...core.metadata import ANY_SETTINGS, NO_ARITHMETIC, BlockMetadata, Locality, validate_metadata
22
+ from ...core.precision import DOUBLE_ROUND_ONCE, validate_policy
23
+ from ...core.tensor import _layout, band_names, same_grid
24
+ from .linear import no_constants
25
+
26
+
27
+ def add(a, b, *, policy: str = DOUBLE_ROUND_ONCE):
28
+ """a + b of two W tensors on the same grid, layout and window, with equal channels."""
29
+ validate_policy(policy, allowed=DOUBLE_ROUND_ONCE)
30
+ same_grid(a, b)
31
+ if a.channels != b.channels:
32
+ raise GridMismatch(f"{a.channels} vs {b.channels} channels")
33
+ return a.like(a.image.add(b.image).toFloat())
34
+
35
+
36
+ def concat(parts: list):
37
+ """torch.cat(parts, dim=1) of W tensors: the decoder's ``Feature`` or a bare
38
+ ``WindowTensor`` (window layout)."""
39
+ same_grid(*parts)
40
+ total = sum(p.channels for p in parts)
41
+ if _layout(parts[0]) == "dense_bands":
42
+ renamed = [p.image.select(band_names(p.channels), band_names(p.channels, f"p{i}_"))
43
+ for i, p in enumerate(parts)]
44
+ image = renamed[0]
45
+ for part in renamed[1:]:
46
+ image = image.addBands(part)
47
+ return parts[0].like(image.rename(band_names(total)), total)
48
+ image = parts[0].image
49
+ for p in parts[1:]:
50
+ image = image.arrayCat(p.image, 1)
51
+ return parts[0].like(image, total)
52
+
53
+
54
+ METADATA = validate_metadata({
55
+ "add": BlockMetadata(
56
+ name="add", layout_in="W", layout_out="W", locality=Locality.POINTWISE,
57
+ policy=DOUBLE_ROUND_ONCE, embedded_constants=no_constants, asset_arrays=no_constants,
58
+ status="Ready",
59
+ evidence=("docs/history/building-blocks-2026-10-11.md#35-activations-merges-and-outputs", "docs/history/upernet/notes/milestone9_findings.md"),
60
+ validated=ANY_SETTINGS),
61
+ "concat": BlockMetadata(
62
+ name="concat", layout_in="W", layout_out="W", locality=Locality.POINTWISE,
63
+ policy=NO_ARITHMETIC, embedded_constants=no_constants, asset_arrays=no_constants,
64
+ status="Ready",
65
+ evidence=("docs/history/building-blocks-2026-10-11.md#35-activations-merges-and-outputs", "docs/history/upernet/notes/milestone8_findings.md"),
66
+ validated=ANY_SETTINGS),
67
+ })