windowMax — the max pool over a family of product windows #
One max pool, proved once. Output cell (ch, hi, wi) is the max of the input over the window
{(r hi a, s wi b) : a, b ∈ Fin k}, where r and s are the row and column index maps of the
window. The pools the nets use are instances:
maxPool2(CNN.lean), 2×2 stride 2:r hi a = 2·hi + a(winRowInv),k = 2. Its own four-waymaxspelling is kept, because the graph ties and the generated certificates read it;maxPool2_eq_windowMaxis the bridge.maxPool3s2(MaxPool3s2.lean), He et al.'s 3×3 stride-2 stem pool:r hi a = 2·hi + a − 1(win3RowInv),k = 3, and it ISwindowMaxat those maps.
Smoothness is stated over positions #
WindowSmooth asks that a cell dominating its window be strictly above every cell at another
input position, not at another offset. The two differ when r or s is not injective: the
3×3/s2 pool's clamped first window names one input cell at two offsets, and those two values are
the same number, so a smoothness condition over offsets could never hold there. For the 2×2 pool
offsets and positions coincide (windowSmooth_of_maxPool2Smooth).
Why overlapping windows cost nothing extra #
At a smooth point the pool is locally the reindexing y ↦ y ∘ σ (windowMax_flat_hasFDerivAt),
σ sending each output to its argmax's input position. The argmax is the first maximal offset
in row-major order (windowArgmax), the cell the emitted select_and_scatter (GE select)
picks, so at a tie the gather and the printed scatter still name one cell. Overlapping windows
only make σ non-injective, and reindexCLM's adjoint already sums over preimages, so the VJP
(windowMaxHasVJPAt3) accumulates over every output whose window selects an input: one term for
tiling windows, up to four for the 3×3/s2 pool.
The window max pool, [c, H, W] → [c, h, w]: the max of x ch over the window
{(r hi a, s wi b)}.
Equations
- Proofs.windowMax r s x ch hi wi = Finset.univ.sup' ⋯ fun (ab : Fin k × Fin k) => x ch (r hi ab.1) (s wi ab.2)
Instances For
The pool never grows magnitudes: it selects an existing window cell.
The pool is 1-Lipschitz in the sup norm: each side is ≤ the other plus e, from the
attained cell on one side and le_windowMax on the other.
The pool shifts with a uniform offset. If one slab's channel is another's plus the
constant δ, so are their pooled values (Finset.apply_sup'_eq_sup'_comp at (· + δ)). It
holds at every point, with no argmax argument.
Smoothness: every window attains its max at exactly one input POSITION. A cell that dominates its window is strictly above every cell at another position; other cells may tie with each other. A window whose max sits at two positions does not qualify, and there the pool has no derivative.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Windows whose cells at distinct positions have distinct values are smooth.
Positional injectivity ⇒ smoothness. If on each channel (p, q) ↦ x ci p q is
injective, no two positions tie. Because smoothness is quantified over positions, the
injectivity lands directly on the hypothesis, with no decoding from positions back to
offsets.
Smooth or dead: every window either has its maximum at one input position, or has every
cell ≤ 0. The second case is what a pool AFTER a ReLU needs: a window of dead ReLUs ties at
0, so the pool alone has no derivative there, but pool ∘ relu is locally constant at a
pre-activation whose cells are all strictly negative.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A smooth pool input is smooth-or-dead.
Smooth, dead, or tied only between twins: every window is entirely ≤ 0, or its maximum
is strictly above every cell at another position except positions T relates to the
maximum's. With T empty this is WindowSmoothOrDead. The twins a parameter gradient can
afford are cells that are the SAME function of the moving parameter: a tie between them
persists along the parameter, and the pool may pick either.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A smooth-or-dead pool input is smooth up to any twin relation.
Margin up to twins, the quantitative WindowSmoothUpTo: every window is entirely ≤ 0,
or a cell dominating it is more than 2δ above every cell at another position, except
positions T relates to its own. A perturbation of at most δ per entry then keeps every
such cell strictly below, so the dominating cell keeps dominating; the twins it ties with
must be the same function of whatever moves the input, and then they stay tied. Stated on the
pool's input before any ReLU: the descent rungs apply it to the pre-activation, where a dead
window is one whose cells are all ≤ 0.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A margin up to twins holds at every smaller margin.
A margin up to twins from one designated cell per window. If T is an equivalence and
every live window has a cell m with every other cell at m's position, a twin of it, or
more than 2δ below it, the margin holds: a cell dominating the window is m or a twin of
m (it cannot sit 2δ below), and twins of m inherit m's gaps. The form a concrete
instance discharges, one certificate per window.
At a nonnegative margin the margined input is smooth up to the same twins.
The offsets attaining the max of the window at output (co, ho, wo), as row-major flat
indices a·k + b (finProdFinEquiv).
Equations
- One or more equations did not get rendered due to their size.
Instances For
The first argmax of the window at output (co, ho, wo), as an offset: the least maximal
offset in row-major order (a major, windowArgmax_first). That is the cell the emitted
select_and_scatter routes to: its GE select keeps the current pick while it is ≥ the
next cell, so it ends on the first maximum in window iteration order. Unique under
WindowSmooth up to position, and only windowArgmax_max is needed off a tie.
Equations
- Proofs.windowArgmax r s x co ho wo = finProdFinEquiv.symm ((Proofs.windowMaxOffsets r s x co ho wo).min' ⋯)
Instances For
No earlier offset attains the max. Every offset before windowArgmax in row-major order
is strictly below the window max: the first-maximum half of the select_and_scatter reading.
If offset ab dominates every window cell, the pooled value is the value there.
The window gather at a fixed selection σ: output (ch, hi, wi) reads the window cell
at offset σ ch hi wi. Linear in x, with no argmax to decide. Wherever σ names a cell
dominating every window, it IS the pool (windowMax_eq_windowGather); that is how a pool
with tied windows is handled, the ties being routed to one fixed cell.
Equations
- Proofs.windowGather r s σ x ch hi wi = x ch (r hi (σ ch hi wi).1) (s wi (σ ch hi wi).2)
Instances For
The pool is the gather at a dominating selection.
For each output flat index, the flat index of its argmax's input position: the carrier of
the local linearisation. Not injective when windows overlap; reindexCLM's adjoint sums over
preimages, which is where the backward accumulates.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Smooth-point local linearisation. Near flatten x the flattened pool agrees with the
reindex y ↦ y ∘ σ: every window keeps its argmax, since finitely many strict inequalities
persist on a neighbourhood (Filter.eventually_all). An offset naming the argmax's own
position is equal to it, not below, so the domination argument branches on positions.
Smooth-point Jacobian. pdiv3 is the 0/1 indicator that the local reindex sends output
(co, ho, wo) to input (ci, hi_in, wi_in). Left as the reindex equation: with overlapping
windows an input has no single owning window to decode it into.
The VJP witness. The backward accumulates dy over every output whose window selects
this input.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The flattened window max, the Vec-level form a codegen op denotes.
Equations
- Proofs.windowMaxFlat r s v = (Proofs.windowMax r s (Proofs.Tensor3.unflatten v)).flatten
Instances For
windowMaxFlat is continuous (a sup' of coordinates).