Documentation

LeanMlir.Proofs.Nets.MobileNet.MobileNetV4WholeBackCertifiedTieB

mnv4InputGradB and the certified whole-net MobileNetV4-Conv-M input VJP #

Ties the batched input-gradient chain mnv4InputGradB to a certified VJP for mobilenetv4ForwardBFull: the MobileNetV4 peer of MobileNetV2WholeBackCertifiedTieB.lean.

No accuracy is quoted for this net. The statements are about timm's mobilenetv4_conv_medium.

The four pieces #

  1. The concrete endpoint stage ties: the stem's (ResNet's symmetric strided conv-bn-relu tie), the first head conv's (cbReluBBack_eq_vjp_backward), conv_head's with the pool in front of it (mnv4Hc2BBack_eq_vjp_backward), and the classifier's with its relabel (mnv4ClsBBack_eq_vjp_backward).
  2. mnv4BFullHasVJPAt — the generic twenty-six-stage apex cls ∘ hc2 ∘ hc1 ∘ b21 ∘ … ∘ b1 ∘ fused ∘ stem, twenty-five vjpCompDiffAts and nothing else, with opaqueA0 … A24 naming the running activations. timm's head is three stages here: hc1 (conv-bn-relu at 7×7), hc2 (GAP, relabel to [N, 960, 1, 1], conv_head-bn-relu) and cls (relabel to [N, 1280], dense).
  3. mnv4InputGradB_eq_mnv4B_full_vjp and mnv4InputGradB_correct — the tie, and its reading as ∑ pdiv … * dy: with its fused-stage and block slots filled by certified VJPs, the chain is the Jacobian-transpose of the twenty-six-stage composition, at every batch size and class count.
  4. mobilenetv4ForwardBFull_eq_slots — the shape check: those twenty-six stages ARE mobilenetv4ForwardBFull, the forward mnv4FwdGraphBFull_faithful says the typed graph denotes. Without it the tie would be a statement about variables.

What is MobileNetV4's own, and what is borrowed #

The stem is ResNet's symmetric strided conv-bn-relu, so its tie is ResNet's; the first head conv is cbReluB. What is MobileNetV4's own is the pool stage in front of conv_head (GAP then a Fin.cast relabel, whose certified backward along a bijection is the plain relabel, reindex_cast_backward) and the relabel in front of the classifier.

The apex is composed at block granularity, not at MobileNetV4FullB.lean's groups #

mobilenetv4ForwardBFullHasVJPAt is a chain of seven vjpCompAts over the five resolution-group CertLayers, because Mnv4SmoothAt wants one .ok per group. This tie wants the finer chain — a tie whose opaque slots are groups would say nothing about which block is which — so the stages here are the twenty-one blocks themselves, mnv4Blk0 … mnv4Blk21's (MobileNetV4StepTieB.lean) stage functions. Peeling CertLayer.comp to reach .fwd inside a group is cheap (comp_fwd is a generic rfl lemma and MobileNetV4FullB's five group-faithfulness proofs each do it); what is not payable at MobileNetV4's literal resolutions is composing the compositions, which is why there is no mnv4NetLayer and why the shape check below stops at the block.

Everything generic in its widths, instantiated only in the capstone. Both stage ties bind {N ic oc h w kH kW} and the apex binds {s0 … s26}; MobileNetV4's 224/112/56/28/14/7 are literals, and stating a den- or width-indexed rfl at them lets it run into kernel timeouts. Instantiating a proven lemma is cheap.

The blocks stay opaque and there is no backward_unique step, because instantiating a tie of this shape at the concrete blocks is a KERNEL deterministic timeout when the witnesses are HasVJPAt carrying a saved activation. B0 takes that step only because swish has no kink. The shape check is what replaces it.

It is a smooth-point statement, and MobileNetV4's kink budget is relu, not relu6: one clause per site, where MobileNetV2's .selectMid carries two. The stem's and the two head convs' are bound here (conv_head's at the pooled 1×1); the ones inside the fused stage and the blocks are CertLayer.comp's and are never written down.

The train step reads the same backwards. The cotangent MobileNetV4StepTieB.mnv4_net_tiedB hands each block's parameter nodes is that block's certified VJP backward, one block at a time (mnv4HeadCotIn_eq_vjp, mnv4BodyCotIn_eq_vjp with mnv4SkipCotIn_eq_vjp, mnv4SBodyCotIn_eq_vjp, mnv4FusedCotIn_eq_vjp), wherever that block is certified. This file composes the same layers into the whole-net input gradient.

Scope. One device's batch N: the data-parallel artifacts (mnv4in_adamdp64*) normalise over the global batch, so this describes them only at N := R·N. It is about the input gradient; the 233 parameter gradients are MobileNetV4StepTieB.lean's tie.

theorem Proofs.mnv4StemBBack_eq_vjp_backward {N ic oc h w kH kW : ℕ} (hkH : 2 * ((kH - 1) / 2) + 1 = kH) (hkW : 2 * ((kW - 1) / 2) + 1 = kW) (Ws : Kernel4 oc ic kH kW) (bs : Vec oc) (ε : ℝ) (hε : 0 < ε) (γ β : Vec oc) (x : Vec (N * (ic * (2 * h) * (2 * w)))) (hs : StableHLO.Mnv4StemSmoothAtB N h w Ws bs ε γ β x) :
(StableHLO.batchMap N (flatConvStride2Back Ws) ∘ (bnBatchLAHasVJP N oc h w ε hε γ β).backward (StableHLO.batchMap N (flatConvStride2 Ws bs) x) ∘ reluMaskBack fun (i : Fin (N * (oc * h * w))) => StableHLO.bnBatchLA N oc h w ε γ β (StableHLO.batchMap N (flatConvStride2 Ws bs) x) i > 0) = (StableHLO.mnv4StemBHasVJPAt N h w Ws bs ε hε γ β x hs).backward

The STEM tie. batchMap (flatConvStride2Back) ∘ bnBack ∘ reluMaskBack IS mnv4StemB's certified backward at a smooth point — the symmetric strided conv-bn-relu tie, since mnv4StemB is cbReluStridedB at the stem's widths.

This is one step past the artifact. No render emits a gradient into %x, so MobileNetV4's committed backward ends at the stem conv's weight gradient, whose operand is the stem-BN cotangent mnv4StemCotN (MobileNetV4StepTieB). This lemma names the map that carries that cotangent the rest of the way to the image.

@[reducible]
noncomputable def Proofs.mnv4PoolB (N h w : ℕ) {c : ℕ} :
Vec (N * (c * h * w)) → Vec (N * (c * 1 * 1))

The pool stage in front of conv_head: GAP, then the relabel to [N, c, 1, 1].

Equations
Instances For
    noncomputable def Proofs.mnv4Hc2BHasVJPDiffAt (N h w : ℕ) {mid oc : ℕ} (W : Kernel4 oc mid 1 1) (b : Vec oc) (ε : ℝ) (hε : 0 < ε) (γ β : Vec oc) (v : Vec (N * (mid * h * w))) (hs : ∀ (k : Fin (N * (oc * 1 * 1))), StableHLO.bnBatchLA N oc 1 1 ε γ β (StableHLO.batchMap N (flatConv W b) (mnv4PoolB N h w v)) k ≠ 0) :
    HasVJPDiffAt (StableHLO.cbReluB N W b ε γ β ∘ mnv4PoolB N h w) v

    conv_head's stage: the pool, then conv-bn-relu at 1×1, with its VJP at a point where that relu is away from its kink.

    Equations
    • One or more equations did not get rendered due to their size.
    Instances For
      theorem Proofs.mnv4Hc2BBack_eq_vjp_backward {N h w mid oc : ℕ} (W : Kernel4 oc mid 1 1) (b : Vec oc) (ε : ℝ) (hε : 0 < ε) (γ β : Vec oc) (v : Vec (N * (mid * h * w))) (hs : ∀ (k : Fin (N * (oc * 1 * 1))), StableHLO.bnBatchLA N oc 1 1 ε γ β (StableHLO.batchMap N (flatConv W b) (mnv4PoolB N h w v)) k ≠ 0) :
      ((StableHLO.batchMap N (gapBack mid h w) ∘ fun (u : Vec (N * (mid * 1 * 1))) (i : Fin (N * mid)) => u (Fin.cast ⋯ i)) ∘ StableHLO.batchMap N (convFlatBack W) ∘ (bnBatchLAHasVJP N oc 1 1 ε hε γ β).backward (StableHLO.batchMap N (flatConv W b) (mnv4PoolB N h w v)) ∘ reluMaskBack fun (i : Fin (N * (oc * 1 * 1))) => StableHLO.bnBatchLA N oc 1 1 ε γ β (StableHLO.batchMap N (flatConv W b) (mnv4PoolB N h w v)) i > 0) = (mnv4Hc2BHasVJPDiffAt N h w W b ε hε γ β v hs).fst.backward

      conv_head's stage tie: GAP-back after the relabel, after conv-back ∘ BN-back ∘ relu mask at 1×1, IS the stage's certified backward.

      @[reducible]
      noncomputable def Proofs.mnv4ClsB (N : ℕ) {oc nCls : ℕ} (Wd : Mat oc nCls) (bd : Vec nCls) :
      Vec (N * (oc * 1 * 1)) → Vec (N * nCls)

      The classifier stage: the relabel of [N, oc, 1, 1] to [N, oc], then dense.

      Equations
      Instances For
        theorem Proofs.mnv4ClsB_differentiable (N : ℕ) {oc nCls : ℕ} (Wd : Mat oc nCls) (bd : Vec nCls) :
        noncomputable def Proofs.mnv4ClsBHasVJP (N : ℕ) {oc nCls : ℕ} (Wd : Mat oc nCls) (bd : Vec nCls) :
        HasVJP (mnv4ClsB N Wd bd)
        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          theorem Proofs.mnv4ClsBBack_eq_vjp_backward {N oc nCls : ℕ} (Wd : Mat oc nCls) (bd : Vec nCls) (x : Vec (N * (oc * 1 * 1))) :
          (fun (u : Vec (N * oc)) (i : Fin (N * (oc * 1 * 1))) => u (Fin.cast ⋯ i)) ∘ StableHLO.batchMap N (dense Wd.transpose 0) = (mnv4ClsBHasVJP N Wd bd).backward x

          The classifier stage tie: dense-back (Wᵀ), then the relabel, IS its certified backward.

          noncomputable def Proofs.mnv4BFullHasVJPAt {s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 : ℕ} (stem : Vec s0 → Vec s1) (fused : Vec s1 → Vec s2) (b1 : Vec s2 → Vec s3) (b2 : Vec s3 → Vec s4) (b3 : Vec s4 → Vec s5) (b4 : Vec s5 → Vec s6) (b5 : Vec s6 → Vec s7) (b6 : Vec s7 → Vec s8) (b7 : Vec s8 → Vec s9) (b8 : Vec s9 → Vec s10) (b9 : Vec s10 → Vec s11) (b10 : Vec s11 → Vec s12) (b11 : Vec s12 → Vec s13) (b12 : Vec s13 → Vec s14) (b13 : Vec s14 → Vec s15) (b14 : Vec s15 → Vec s16) (b15 : Vec s16 → Vec s17) (b16 : Vec s17 → Vec s18) (b17 : Vec s18 → Vec s19) (b18 : Vec s19 → Vec s20) (b19 : Vec s20 → Vec s21) (b20 : Vec s21 → Vec s22) (b21 : Vec s22 → Vec s23) (hc1 : Vec s23 → Vec s24) (hc2 : Vec s24 → Vec s25) (head : Vec s25 → Vec s26) (x : Vec s0) (hstem : HasVJPDiffAt stem x) (hfused : HasVJPDiffAt fused (opaqueA0 stem x)) (hb1 : HasVJPDiffAt b1 (opaqueA1 stem fused x)) (hb2 : HasVJPDiffAt b2 (opaqueA2 stem fused b1 x)) (hb3 : HasVJPDiffAt b3 (opaqueA3 stem fused b1 b2 x)) (hb4 : HasVJPDiffAt b4 (opaqueA4 stem fused b1 b2 b3 x)) (hb5 : HasVJPDiffAt b5 (opaqueA5 stem fused b1 b2 b3 b4 x)) (hb6 : HasVJPDiffAt b6 (opaqueA6 stem fused b1 b2 b3 b4 b5 x)) (hb7 : HasVJPDiffAt b7 (opaqueA7 stem fused b1 b2 b3 b4 b5 b6 x)) (hb8 : HasVJPDiffAt b8 (opaqueA8 stem fused b1 b2 b3 b4 b5 b6 b7 x)) (hb9 : HasVJPDiffAt b9 (opaqueA9 stem fused b1 b2 b3 b4 b5 b6 b7 b8 x)) (hb10 : HasVJPDiffAt b10 (opaqueA10 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 x)) (hb11 : HasVJPDiffAt b11 (opaqueA11 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 x)) (hb12 : HasVJPDiffAt b12 (opaqueA12 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 x)) (hb13 : HasVJPDiffAt b13 (opaqueA13 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 x)) (hb14 : HasVJPDiffAt b14 (opaqueA14 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 x)) (hb15 : HasVJPDiffAt b15 (opaqueA15 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 x)) (hb16 : HasVJPDiffAt b16 (opaqueA16 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 x)) (hb17 : HasVJPDiffAt b17 (opaqueA17 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 x)) (hb18 : HasVJPDiffAt b18 (opaqueA18 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 x)) (hb19 : HasVJPDiffAt b19 (opaqueA19 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 x)) (hb20 : HasVJPDiffAt b20 (opaqueA20 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 x)) (hb21 : HasVJPDiffAt b21 (opaqueA21 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 x)) (hhc1 : HasVJPDiffAt hc1 (opaqueA22 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x)) (hhc2 : HasVJPDiffAt hc2 (opaqueA23 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 hc1 x)) (hhead : HasVJPDiffAt head (opaqueA24 stem fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 hc1 hc2 x)) :
          HasVJPAt (head ∘ hc2 ∘ hc1 ∘ b21 ∘ b20 ∘ b19 ∘ b18 ∘ b17 ∘ b16 ∘ b15 ∘ b14 ∘ b13 ∘ b12 ∘ b11 ∘ b10 ∘ b9 ∘ b8 ∘ b7 ∘ b6 ∘ b5 ∘ b4 ∘ b3 ∘ b2 ∘ b1 ∘ fused ∘ stem) x

          Whole-network MobileNetV4-Conv-M VJP. The VJP of the twenty-six-stage chain head ∘ hc2 ∘ hc1 ∘ b21 ∘ … ∘ b1 ∘ fused ∘ stem — twenty-five vjpCompDiffAts and nothing else, dimension-generic and parametric in every component.

          Pointwise (HasVJPAt): relu is kinked, so each stage's witness carries the activation it sees. r34BFullHasVJPAt is the same construction at eighteen stages; MobileNetV4 needs its own because Conv-M's ladder is longer, not because anything differs.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            theorem Proofs.mnv4InputGradB_eq_mnv4B_full_vjp (N f : ℕ) {nCls : ℕ} (Ws : Kernel4 32 3 3 3) (bs : Vec 32) (εs : ℝ) (hεs : 0 < εs) (γs βs : Vec 32) (Wh1 : Kernel4 960 256 1 1) (bh1 : Vec 960) (εh1 : ℝ) (hεh1 : 0 < εh1) (γh1 βh1 : Vec 960) (Wh : Kernel4 1280 960 1 1) (bh : Vec 1280) (εh : ℝ) (hεh : 0 < εh) (γh βh : Vec 1280) (Wd : Mat 1280 nCls) (bd : Vec nCls) (fused : Vec (N * (32 * (16 * f) * (16 * f))) → Vec (N * (48 * (8 * f) * (8 * f)))) (b1 : Vec (N * (48 * (8 * f) * (8 * f))) → Vec (N * (80 * (4 * f) * (4 * f)))) (b2 : Vec (N * (80 * (4 * f) * (4 * f))) → Vec (N * (80 * (4 * f) * (4 * f)))) (b3 : Vec (N * (80 * (4 * f) * (4 * f))) → Vec (N * (160 * (2 * f) * (2 * f)))) (b4 b5 b6 b7 b8 b9 b10 : Vec (N * (160 * (2 * f) * (2 * f))) → Vec (N * (160 * (2 * f) * (2 * f)))) (b11 : Vec (N * (160 * (2 * f) * (2 * f))) → Vec (N * (256 * f * f))) (b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 : Vec (N * (256 * f * f)) → Vec (N * (256 * f * f))) (x : Vec (N * (3 * (2 * (16 * f)) * (2 * (16 * f))))) (h_stem : StableHLO.Mnv4StemSmoothAtB N (16 * f) (16 * f) Ws bs εs γs βs x) (hfused : HasVJPDiffAt fused (opaqueA0 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) x)) (hb1 : HasVJPDiffAt b1 (opaqueA1 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused x)) (hb2 : HasVJPDiffAt b2 (opaqueA2 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 x)) (hb3 : HasVJPDiffAt b3 (opaqueA3 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 x)) (hb4 : HasVJPDiffAt b4 (opaqueA4 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 x)) (hb5 : HasVJPDiffAt b5 (opaqueA5 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 x)) (hb6 : HasVJPDiffAt b6 (opaqueA6 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 x)) (hb7 : HasVJPDiffAt b7 (opaqueA7 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 x)) (hb8 : HasVJPDiffAt b8 (opaqueA8 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 x)) (hb9 : HasVJPDiffAt b9 (opaqueA9 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 x)) (hb10 : HasVJPDiffAt b10 (opaqueA10 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 x)) (hb11 : HasVJPDiffAt b11 (opaqueA11 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 x)) (hb12 : HasVJPDiffAt b12 (opaqueA12 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 x)) (hb13 : HasVJPDiffAt b13 (opaqueA13 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 x)) (hb14 : HasVJPDiffAt b14 (opaqueA14 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 x)) (hb15 : HasVJPDiffAt b15 (opaqueA15 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 x)) (hb16 : HasVJPDiffAt b16 (opaqueA16 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 x)) (hb17 : HasVJPDiffAt b17 (opaqueA17 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 x)) (hb18 : HasVJPDiffAt b18 (opaqueA18 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 x)) (hb19 : HasVJPDiffAt b19 (opaqueA19 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 x)) (hb20 : HasVJPDiffAt b20 (opaqueA20 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 x)) (hb21 : HasVJPDiffAt b21 (opaqueA21 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 x)) (h_h1 : ∀ (k : Fin (N * (960 * f * f))), StableHLO.bnBatchLA N 960 f f εh1 γh1 βh1 (StableHLO.batchMap N (flatConv Wh1 bh1) (opaqueA22 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x)) k ≠ 0) (h_h2 : ∀ (k : Fin (N * (1280 * 1 * 1))), StableHLO.bnBatchLA N 1280 1 1 εh γh βh (StableHLO.batchMap N (flatConv Wh bh) (mnv4PoolB N f f (opaqueA23 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) x))) k ≠ 0) :
            (mnv4InputGradB N f Ws Wh1 Wh Wd ((bnBatchLAHasVJP N 32 (16 * f) (16 * f) εs hεs γs βs).backward (StableHLO.batchMap N (flatConvStride2 Ws bs) x)) ((bnBatchLAHasVJP N 960 f f εh1 hεh1 γh1 βh1).backward (StableHLO.batchMap N (flatConv Wh1 bh1) (opaqueA22 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x))) ((bnBatchLAHasVJP N 1280 1 1 εh hεh γh βh).backward (StableHLO.batchMap N (flatConv Wh bh) (mnv4PoolB N f f (opaqueA23 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) x)))) hfused.fst.backward hb1.fst.backward hb2.fst.backward hb3.fst.backward hb4.fst.backward hb5.fst.backward hb6.fst.backward hb7.fst.backward hb8.fst.backward hb9.fst.backward hb10.fst.backward hb11.fst.backward hb12.fst.backward hb13.fst.backward hb14.fst.backward hb15.fst.backward hb16.fst.backward hb17.fst.backward hb18.fst.backward hb19.fst.backward hb20.fst.backward hb21.fst.backward (fun (i : Fin (N * (32 * (16 * f) * (16 * f)))) => StableHLO.bnBatchLA N 32 (16 * f) (16 * f) εs γs βs (StableHLO.batchMap N (flatConvStride2 Ws bs) x) i > 0) (fun (i : Fin (N * (960 * f * f))) => StableHLO.bnBatchLA N 960 f f εh1 γh1 βh1 (StableHLO.batchMap N (flatConv Wh1 bh1) (opaqueA22 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x)) i > 0) fun (i : Fin (N * (1280 * 1 * 1))) => StableHLO.bnBatchLA N 1280 1 1 εh γh βh (StableHLO.batchMap N (flatConv Wh bh) (mnv4PoolB N f f (opaqueA23 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) x))) i > 0) = (mnv4BFullHasVJPAt (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) (StableHLO.cbReluB N Wh bh εh γh βh ∘ mnv4PoolB N f f) (mnv4ClsB N Wd bd) x ⟨StableHLO.mnv4StemBHasVJPAt N (16 * f) (16 * f) Ws bs εs hεs γs βs x h_stem, ⋯⟩ hfused hb1 hb2 hb3 hb4 hb5 hb6 hb7 hb8 hb9 hb10 hb11 hb12 hb13 hb14 hb15 hb16 hb17 hb18 hb19 hb20 hb21 ⟨StableHLO.cbReluBHasVJPAt N Wh1 bh1 εh1 hεh1 γh1 βh1 (opaqueA22 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x) h_h1, ⋯⟩ (mnv4Hc2BHasVJPDiffAt N f f Wh bh εh hεh γh βh (opaqueA23 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) x) h_h2) ⟨(mnv4ClsBHasVJP N Wd bd).toHasVJPAt (opaqueA24 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) (StableHLO.cbReluB N Wh bh εh γh βh ∘ mnv4PoolB N f f) x), ⋯⟩).backward

            mnv4InputGradB is the backward of the whole-net VJP at opaque blocks. The committed backward chain, with its three BatchNorm and three relu-mask slots filled by the certified per-op backwards and its fused-stage and twenty-one block slots filled by the supplied witnesses' backwards (hfused, hb1 … hb21; the stages themselves left opaque), equals the backward of mnv4BFullHasVJPAt at those twenty-six stages, at an input where the stem and both head relu clauses (h_stem, h_h1, h_h2) hold.

            N, nCls and the final side f are binders, so this covers the 10-class Imagenette artifacts and the 1000-class mnv4in ones at every batch size, and — since 2026-10-12 — the paper tier's mnv4in256 renders at f := 8 beside the 224 ones at f := 7 (the stages' sides are 16f, 8f, 4f, 2f, f, the input 2·16f; MobileNetBackChains.mnv4InputGradB). The stage ties this rewrites with were generic in h w all along, and the apex over opaque stages binds its widths, so the side costs nothing here; mobilenetv4ForwardBFull_eq_slots, which identifies the stages with the literal-resolution forward of MobileNetV4FullB, stays at 224 (that file's note on resolution literals). On the data-parallel (sync-BN) artifacts, instantiate at the global batch R·N (see MobileNetV4SyncB).

            theorem Proofs.mnv4InputGradB_correct (N f : ℕ) {nCls : ℕ} (Ws : Kernel4 32 3 3 3) (bs : Vec 32) (εs : ℝ) (hεs : 0 < εs) (γs βs : Vec 32) (Wh1 : Kernel4 960 256 1 1) (bh1 : Vec 960) (εh1 : ℝ) (hεh1 : 0 < εh1) (γh1 βh1 : Vec 960) (Wh : Kernel4 1280 960 1 1) (bh : Vec 1280) (εh : ℝ) (hεh : 0 < εh) (γh βh : Vec 1280) (Wd : Mat 1280 nCls) (bd : Vec nCls) (fused : Vec (N * (32 * (16 * f) * (16 * f))) → Vec (N * (48 * (8 * f) * (8 * f)))) (b1 : Vec (N * (48 * (8 * f) * (8 * f))) → Vec (N * (80 * (4 * f) * (4 * f)))) (b2 : Vec (N * (80 * (4 * f) * (4 * f))) → Vec (N * (80 * (4 * f) * (4 * f)))) (b3 : Vec (N * (80 * (4 * f) * (4 * f))) → Vec (N * (160 * (2 * f) * (2 * f)))) (b4 b5 b6 b7 b8 b9 b10 : Vec (N * (160 * (2 * f) * (2 * f))) → Vec (N * (160 * (2 * f) * (2 * f)))) (b11 : Vec (N * (160 * (2 * f) * (2 * f))) → Vec (N * (256 * f * f))) (b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 : Vec (N * (256 * f * f)) → Vec (N * (256 * f * f))) (x : Vec (N * (3 * (2 * (16 * f)) * (2 * (16 * f))))) (h_stem : StableHLO.Mnv4StemSmoothAtB N (16 * f) (16 * f) Ws bs εs γs βs x) (hfused : HasVJPDiffAt fused (opaqueA0 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) x)) (hb1 : HasVJPDiffAt b1 (opaqueA1 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused x)) (hb2 : HasVJPDiffAt b2 (opaqueA2 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 x)) (hb3 : HasVJPDiffAt b3 (opaqueA3 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 x)) (hb4 : HasVJPDiffAt b4 (opaqueA4 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 x)) (hb5 : HasVJPDiffAt b5 (opaqueA5 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 x)) (hb6 : HasVJPDiffAt b6 (opaqueA6 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 x)) (hb7 : HasVJPDiffAt b7 (opaqueA7 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 x)) (hb8 : HasVJPDiffAt b8 (opaqueA8 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 x)) (hb9 : HasVJPDiffAt b9 (opaqueA9 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 x)) (hb10 : HasVJPDiffAt b10 (opaqueA10 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 x)) (hb11 : HasVJPDiffAt b11 (opaqueA11 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 x)) (hb12 : HasVJPDiffAt b12 (opaqueA12 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 x)) (hb13 : HasVJPDiffAt b13 (opaqueA13 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 x)) (hb14 : HasVJPDiffAt b14 (opaqueA14 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 x)) (hb15 : HasVJPDiffAt b15 (opaqueA15 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 x)) (hb16 : HasVJPDiffAt b16 (opaqueA16 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 x)) (hb17 : HasVJPDiffAt b17 (opaqueA17 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 x)) (hb18 : HasVJPDiffAt b18 (opaqueA18 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 x)) (hb19 : HasVJPDiffAt b19 (opaqueA19 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 x)) (hb20 : HasVJPDiffAt b20 (opaqueA20 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 x)) (hb21 : HasVJPDiffAt b21 (opaqueA21 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 x)) (h_h1 : ∀ (k : Fin (N * (960 * f * f))), StableHLO.bnBatchLA N 960 f f εh1 γh1 βh1 (StableHLO.batchMap N (flatConv Wh1 bh1) (opaqueA22 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x)) k ≠ 0) (h_h2 : ∀ (k : Fin (N * (1280 * 1 * 1))), StableHLO.bnBatchLA N 1280 1 1 εh γh βh (StableHLO.batchMap N (flatConv Wh bh) (mnv4PoolB N f f (opaqueA23 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) x))) k ≠ 0) (dy : Vec (N * nCls)) (i : Fin (N * (3 * (2 * (16 * f)) * (2 * (16 * f))))) :
            mnv4InputGradB N f Ws Wh1 Wh Wd ((bnBatchLAHasVJP N 32 (16 * f) (16 * f) εs hεs γs βs).backward (StableHLO.batchMap N (flatConvStride2 Ws bs) x)) ((bnBatchLAHasVJP N 960 f f εh1 hεh1 γh1 βh1).backward (StableHLO.batchMap N (flatConv Wh1 bh1) (opaqueA22 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x))) ((bnBatchLAHasVJP N 1280 1 1 εh hεh γh βh).backward (StableHLO.batchMap N (flatConv Wh bh) (mnv4PoolB N f f (opaqueA23 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) x)))) hfused.fst.backward hb1.fst.backward hb2.fst.backward hb3.fst.backward hb4.fst.backward hb5.fst.backward hb6.fst.backward hb7.fst.backward hb8.fst.backward hb9.fst.backward hb10.fst.backward hb11.fst.backward hb12.fst.backward hb13.fst.backward hb14.fst.backward hb15.fst.backward hb16.fst.backward hb17.fst.backward hb18.fst.backward hb19.fst.backward hb20.fst.backward hb21.fst.backward (fun (i : Fin (N * (32 * (16 * f) * (16 * f)))) => StableHLO.bnBatchLA N 32 (16 * f) (16 * f) εs γs βs (StableHLO.batchMap N (flatConvStride2 Ws bs) x) i > 0) (fun (i : Fin (N * (960 * f * f))) => StableHLO.bnBatchLA N 960 f f εh1 γh1 βh1 (StableHLO.batchMap N (flatConv Wh1 bh1) (opaqueA22 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 x)) i > 0) (fun (i : Fin (N * (1280 * 1 * 1))) => StableHLO.bnBatchLA N 1280 1 1 εh γh βh (StableHLO.batchMap N (flatConv Wh bh) (mnv4PoolB N f f (opaqueA23 (StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) fused b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 (StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1) x))) i > 0) dy i = ∑ j : Fin (N * nCls), pdiv (mnv4ClsB N Wd bd ∘ (StableHLO.cbReluB N Wh bh εh γh βh ∘ mnv4PoolB N f f) ∘ StableHLO.cbReluB N Wh1 bh1 εh1 γh1 βh1 ∘ b21 ∘ b20 ∘ b19 ∘ b18 ∘ b17 ∘ b16 ∘ b15 ∘ b14 ∘ b13 ∘ b12 ∘ b11 ∘ b10 ∘ b9 ∘ b8 ∘ b7 ∘ b6 ∘ b5 ∘ b4 ∘ b3 ∘ b2 ∘ b1 ∘ fused ∘ StableHLO.mnv4StemB N (16 * f) (16 * f) Ws bs εs γs βs) x i j * dy j

            The chain is the pdiv-contracted Jacobian of the twenty-six-stage composition — at every batch size, class count and loss cotangent, and at every input where the stem and both head relu clauses hold (h_stem, h_h1, h_h2): the chain, with its fused-stage and twenty-one block slots filled by the supplied certified VJPs at the running activations (hfused, hb1 … hb21), is the Jacobian-transpose of the composition of those stages. The stages are variables here; mobilenetv4ForwardBFull_eq_slots identifies them with the committed forward.

            theorem Proofs.mobilenetv4ForwardBFull_eq_slots (N : ℕ) {nCls : ℕ} (w : StableHLO.Mnv4BWeights nCls) (x : Vec (N * (3 * 224 * 224))) :
            StableHLO.mobilenetv4ForwardBFull N w x = (mnv4ClsB N w.Wd w.bd ∘ (StableHLO.cbReluB N w.hW w.hb w.hE w.hg w.hbt ∘ mnv4PoolB N 7 7) ∘ StableHLO.cbReluB N w.h1W w.h1b w.h1E w.h1g w.h1bt ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row21 w.b21).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row20 w.b20).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row19 w.b19).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row18 w.b18).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row17 w.b17).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row16 w.b16).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row15 w.b15).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row14 w.b14).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row13 w.b13).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row12 w.b12).residual.fwd ∘ (StableHLO.mnv4StridedBodyOfRow N StableHLO.mnv4Row11 w.b11).fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row10 w.b10).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row9 w.b9).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row8 w.b8).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row7 w.b7).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row6 w.b6).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row5 w.b5).residual.fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row4 w.b4).residual.fwd ∘ (StableHLO.mnv4StridedBodyOfRow N StableHLO.mnv4Row3 w.b3).fwd ∘ (StableHLO.mnv4BodyOfRow N StableHLO.mnv4Row2 w.b2).residual.fwd ∘ (StableHLO.mnv4StridedBodyOfRow N StableHLO.mnv4Row1 w.b1).fwd ∘ (StableHLO.mnv4FusedStack N w).fwd ∘ StableHLO.mnv4StemB N 112 112 w.sW w.sb w.sE w.sg w.sbt) x

            The twenty-six slots the tie is about are mobilenetv4ForwardBFull. The committed forward, regrouped into exactly the twenty-six arguments mnv4BFullHasVJPAt takes: the symmetric stem, the fused stage, the three strided rows (1, 3, 11) as mnv4StridedBodyOfRow, the eighteen skip rows as CertLayer.residual of mnv4BodyOfRow at their own table rows, and the head's three stages (cn_960, the pool with conv_head, the relabelled classifier).

            The tie keeps its blocks opaque, so its subject is a chain of variables and nothing in it says which net they are; this theorem does. It also carries the block table into the tie: every slot names its row, so rows 4/5/7, 8/10, 12/18, 13/14 and 15/19/20 — shape-identical, hence interchangeable to every type and #guard — are pinned here by the row constant, as mnv4FwdGraphBFull's SSA names pin them in the graph.