Documentation

LeanMlir.Proofs.Architectures.MaxPool3s2

maxPool3s2 — the 3×3 stride-2 max pool of He et al.'s ResNet stem #

maxPool2 (CNN.lean) is 2×2, stride 2, non-overlapping. Every ResNet in He et al. (18/34/50/101/152) specifies a 3×3 stride-2 pool after the stem conv; this file is that op.

Which 3×3 pool: the paper's symmetric padding #

This file implements He et al. / torchvision: nn.MaxPool2d(3, stride=2, padding=1) — symmetric padding, so window i covers input [2i−1, 2i+1].

XLA's reduce_window(…, 'SAME') would be a different function: on a 112→56 axis it gives pad_total = max((56−1)·2 + 3 − 112, 0) = 1, split pad_low = 0, pad_high = 1 — window i = [2i, 2i+2], padded at the end. Measured on device at n = 12: SAME windows peak at [2,4,6,8,10,11], symmetric at [1,3,5,7,9,11]; the two grids are offset by one input position. The JAX reference's max_pool2d uses the same symmetric padding (p, p) with p = (size−1)//2.

At 2×2 symmetric (k−1)//2 padding is p = 0, bit-identical to SAME, so the choice only matters for the 3×3 pools (the ResNet-34 and ResNet-50 ImageNet stems).

The padding needs no extended-reals type #

reduce_window pads with -∞, which Tensor3 _ _ _ = … → ℝ cannot hold. It does not need to: for max, clamping the index is equivalent to -∞ padding. The only out-of-range read is 2i−1 at i = 0, and Nat's truncated subtraction clamps it to 0 — a cell the window already contains at offset a = 1. So max over the clamped triple equals max over the unpadded pair, which is exactly what -∞ padding computes. win3RowInv_first_dup is that statement, and win3ColInv_first_dup its column half.

The symmetric form needs no min: the upper end 2(h−1)+2−1 = 2h−1 is in range by construction, so truncated subtraction is the whole story.

The pool is a windowMax instance #

maxPool3s2 is windowMax win3RowInv win3ColInv (WindowMax.lean), and every analytic fact here is that file's lemma at these window maps. What is particular to this pool is the window geometry: the clamped duplicate (win3RowInv_first_dup), which is why smoothness is stated over positions, and the overlap (win3Row_mem_le_two): an input lies in up to four windows, so where maxPool2's backward is a lookup, this one accumulates. The witness is maxPool3s2HasVJPAt3, with its flat form maxPool3s2FlatHasVJPAt; the ResNet-34/50 stems, their seals and the float stem bridge build on it.

def Proofs.win3RowInv {h : ℕ} (hi_out : Fin h) (a : Fin 3) :
Fin (2 * h)

Input row of offset a ∈ Fin 3 inside output window hi_out: 2·hi + a − 1, in Nat. The truncated subtraction is the low pad (see the header) — it is the only clamp needed, because the high end 2(h−1)+2−1 = 2h−1 is in range by construction.

Equations
Instances For
    def Proofs.win3ColInv {w : ℕ} (wi_out : Fin w) (b : Fin 3) :
    Fin (2 * w)

    Column peer of win3RowInv.

    Equations
    Instances For
      theorem Proofs.win3RowInv_first_dup {h : ℕ} (hi_out : Fin h) (hfirst : ↑hi_out = 0) :
      win3RowInv hi_out ⟨0, ⋯⟩ = win3RowInv hi_out ⟨1, ⋯⟩

      The padding statement. In the FIRST window offset a = 0 duplicates a = 1 rather than reading out of range — exactly what a -∞ pad contributes to a max.

      theorem Proofs.win3ColInv_first_dup {w : ℕ} (wi_out : Fin w) (hfirst : ↑wi_out = 0) :
      win3ColInv wi_out ⟨0, ⋯⟩ = win3ColInv wi_out ⟨1, ⋯⟩
      @[reducible, inline]
      noncomputable abbrev Proofs.maxPool3s2 {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) :
      Tensor3 c h w

      3×3 stride-2 symmetrically-padded max pool, [c, 2h, 2w] → [c, h, w]: the max over the window [2i−1, 2i+1] × [2j−1, 2j+1], clamped at the near edge (= -∞ padded, header).

      Equations
      Instances For
        @[reducible, inline]
        abbrev Proofs.MaxPool3s2Smooth {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) :

        Smoothness: every 3×3 window attains its max at exactly one input position (WindowSmooth). Stated over positions, so the clamped duplicate in the first window is not a tie; a window whose max sits at two positions (an all-zero post-ReLU window) does not qualify.

        Equations
        Instances For
          theorem Proofs.maxPool3s2Smooth_of_injective {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (hinj : ∀ (ci : Fin c) (r r' : Fin (2 * h)) (s s' : Fin (2 * w)), x ci r s = x ci r' s' → r = r' ∧ s = s') :

          Positional injectivity ⇒ MaxPool3s2Smooth, the discharge used by BatchSeal.ctConv_pool_smooth for the ResNet-34 and ResNet-50 full-width seals: one injectivity argument in place of a per-window case split.

          @[reducible, inline]
          abbrev Proofs.MaxPool3s2SmoothOrDead {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) :

          Smooth or dead (WindowSmoothOrDead): every 3×3 window has its maximum at one position, or every cell ≤ 0. The ResNet stems state their pool condition in this form (StemPoolSmoothAt), and maxPool3s2Flat_relu_eventuallyEq is the lemma that uses it.

          Equations
          Instances For

            A smooth pool input is smooth-or-dead.

            @[reducible, inline]
            abbrev Proofs.MaxPool3s2SmoothUpTo {c h w : ℕ} (T : Fin (2 * h) × Fin (2 * w) → Fin (2 * h) × Fin (2 * w) → Prop) (x : Tensor3 c (2 * h) (2 * w)) :

            Smooth, dead, or tied only between twins (WindowSmoothUpTo): the ResNet stem's twins are cells reading identical input patches (StemPoolTwinAt).

            Equations
            Instances For
              theorem Proofs.maxPool3s2SmoothUpTo_of_smoothOrDead {c h w : ℕ} (T : Fin (2 * h) × Fin (2 * w) → Fin (2 * h) × Fin (2 * w) → Prop) {x : Tensor3 c (2 * h) (2 * w)} (hx : MaxPool3s2SmoothOrDead x) :

              A smooth-or-dead pool input is smooth up to any twin relation.

              theorem Proofs.win3Row_mem_le_two {h : ℕ} (p : Fin (2 * h)) (hi_out : Fin h) (hmem : ∃ (a : Fin 3), win3RowInv hi_out a = p) :
              ↑hi_out = ↑p / 2 ∨ 2 * ↑hi_out = ↑p + 1

              The overlap fact, stated rather than assumed: an input row lies in at most TWO windows — p/2 and (p+1)/2. With symmetric padding the shared cell is at ODD p (window (p−1)/2 takes it at offset 2, window (p+1)/2 at offset 0); even p lies in exactly one. So an input feeds at most 4 outputs and the backward accumulates at most 4 terms — the count maxPool2 does not have.

              @[reducible, inline]
              noncomputable abbrev Proofs.maxPool3s2Argmax {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (co : Fin c) (ho : Fin h) (wo : Fin w) :
              Fin 3 × Fin 3

              A (not necessarily unique) argmax of the 3×3 window at output (co, ho, wo).

              Equations
              Instances For
                theorem Proofs.maxPool3s2Argmax_max {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (co : Fin c) (ho : Fin h) (wo : Fin w) (ab : Fin 3 × Fin 3) :
                x co (win3RowInv ho ab.1) (win3ColInv wo ab.2) ≤ x co (win3RowInv ho (maxPool3s2Argmax x co ho wo).1) (win3ColInv wo (maxPool3s2Argmax x co ho wo).2)
                theorem Proofs.maxPool3s2_eq_at_max {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (co : Fin c) (ho : Fin h) (wo : Fin w) (a b : Fin 3) (h_max : ∀ (a' b' : Fin 3), x co (win3RowInv ho a') (win3ColInv wo b') ≤ x co (win3RowInv ho a) (win3ColInv wo b)) :
                maxPool3s2 x co ho wo = x co (win3RowInv ho a) (win3ColInv wo b)

                If (a, b) dominates every window cell, the pooled value is the value there.

                @[reducible, inline]
                noncomputable abbrev Proofs.maxPool3s2LocalReindex {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (k_out : Fin (c * h * w)) :
                Fin (c * (2 * h) * (2 * w))

                For each output flat index, the flat index of its argmax's input position. Not injective: two overlapping windows may select the same input.

                Equations
                Instances For
                  noncomputable def Proofs.maxPool3s2HasVJPAt3 {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (h_smooth : MaxPool3s2Smooth x) :

                  The VJP witness. The backward accumulates dy over every output whose window selects this input, at most 4 of them (win3Row_mem_le_two squared). The backward is spelled out rather than taken from windowMaxHasVJPAt3, so that unfolding this name exposes the sum the backward ties match.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    noncomputable def Proofs.maxPool3s2Flat (c h w : ℕ) :
                    Vec (c * (2 * h) * (2 * w)) → Vec (c * h * w)

                    Flattened 3×3/s2 pool, the Vec-level form the codegen denotes. Spelled through maxPool3s2, which is windowMaxFlat at the 3×3/s2 maps by unfolding.

                    Equations
                    Instances For
                      noncomputable def Proofs.maxPool3s2FlatHasVJPAt {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (h_smooth : MaxPool3s2Smooth x) :

                      The VJP of maxPool3s2Flat at a flattened input satisfying MaxPool3s2Smooth: maxPool3s2HasVJPAt3 moved to Vec form.

                      Equations
                      Instances For
                        theorem Proofs.maxPool3s2Flat_abs_le {c h w : ℕ} {v : Vec (c * (2 * h) * (2 * w))} {A : ℝ} (hv : ∀ (k : Fin (c * (2 * h) * (2 * w))), |v k| ≤ A) (k : Fin (c * h * w)) :
                        |maxPool3s2Flat c h w v k| ≤ A

                        Flattened magnitude bound, the form floatClose_maxPool3s2 threads.

                        theorem Proofs.maxPool3s2Flat_close {c h w : ℕ} (vt va : Vec (c * (2 * h) * (2 * w))) {e : ℝ} (hv : ∀ (k : Fin (c * (2 * h) * (2 * w))), |vt k - va k| ≤ e) (k : Fin (c * h * w)) :
                        |maxPool3s2Flat c h w vt k - maxPool3s2Flat c h w va k| ≤ e

                        Flattened closeness: the pool is 1-Lipschitz in the sup norm.

                        maxPool3s2Flat is continuous (a sup' of coordinates).

                        theorem Proofs.maxPool3s2_shift {c h w : ℕ} (x y : Tensor3 c (2 * h) (2 * w)) (δ : ℝ) (ci : Fin c) (hxy : ∀ (r : Fin (2 * h)) (s : Fin (2 * w)), x ci r s = y ci r s + δ) (hi : Fin h) (wi : Fin w) :
                        maxPool3s2 x ci hi wi = maxPool3s2 y ci hi wi + δ

                        The 3×3/s2 pool shifts with a uniform offset, at every point of the ray, which is what lets the carrier cross the only real kink in the net.

                        theorem Proofs.maxPool3s2_nonneg {c h w : ℕ} (x : Tensor3 c (2 * h) (2 * w)) (hx : ∀ (ci : Fin c) (r : Fin (2 * h)) (s : Fin (2 * w)), 0 ≤ x ci r s) (ci : Fin c) (hi : Fin h) (wi : Fin w) :
                        0 ≤ maxPool3s2 x ci hi wi

                        The pool keeps a nonnegative slab nonnegative (it selects a window cell).