T3 §1a tie for MobileNetV4-Conv-M — every gradient node at its CHAIN cotangent #
Every parameter gradient node MNv4's batched train step emits denotes the certified gradient
for an arbitrary cotangent, by a leaf lemma it shares with ResNet-34 or EfficientNet-B0 (the
table below). This file removes that freedom: each node is stated at the cotangent the render's own
backward chain delivers, driven by a loss cotangent g at the logits.
⚠⚠ No accuracy is quoted for this net. Conv-M has no Imagenette run and no verified ImageNet run; the ties that pin these statements to the reference's function are the 2026-09-07 pair.
⭐ The UIB bottleneck is LINEAR, and that makes MNv4's chain shorter than ResNet's #
uibFwdSkipB emits addVB (project-BN out) (block input) with no activation after the add and
none after the project's BatchNorm. So the block-output cotangent dyOut reaches the project BN's
γ and β directly — where ResNet-50's r50IdCotA must first pass through the post-residual relu's
mask, and where its skip branch carries the masked cotangent. Here the skip fan-in is
addVB (body dx) dyOut, unmasked.
⭐⭐ And every block's *CotIn_eq_vjp is its block layer's .faithful, not a new derivation. The
UIB bodies are CertLayers, so den (graph x e) = vjp.backward (den e) is already a theorem one
tier down — the very fact 4.2a/4.2c/§3.5c re-derive per block for r34, mnv2 and R50. This file
composes certified VJPs; it does not re-prove them.
⭐⭐ Zero new fp32 op-kind lemmas — MNv4's nine kinds are three other nets', verbatim #
| op kind | sites | certificate |
|---|---|---|
bnGammaGradB / bnBetaGradB | 77 BN layers | ResNet34PoCB.bnGammaGradB_den / bnBetaGradB_den |
convWeightGradB | expands, projects, both head convs, the fused project | ResNet34PoCB.convWGradB_den |
convStridedWeightGradB (SYMMETRIC) | the fused stage's 3×3/s2 | ResNet34PoCB.convStridedWGradB_den |
convStridedXlaWeightGradB (XLA-SAME) | the stem, and only the stem | EnetPoCG.convStridedXlaWGradB_den |
depthwiseWeightGradB | every stride-1 depthwise | EnetPoCG.depthwiseWGradB_den |
depthwiseStridedWeightGradB | rows 1, 3, 11's leading depthwise | EnetPoCG.depthwiseStridedWGradB_den |
denseWeightGradB / denseBiasGradB | the classifier | ResNet34PoCB.denseWGradB_den / denseBGradB_den |
⚠⚠ TWO padding phases, and the two strided conv kinds are NOT interchangeable. The stem is
XLA-SAME (flatConvStride2Xla, EfficientNet-B0's op) and the fused stage is SYMMETRIC
(flatConvStride2, ResNet's). Identical types, identical emitted shapes, different certificates —
scripts/convention_audit.py is what reads them apart, and swapping one for the other is the
6.16e-2-vs-1.79e-6 forward-tie defect planning/archive/mnv4_verified.md §3b measured.
⛔ MNv4 emits no conv BIAS gradient at all. MobileNetV4RenderB has no convBias flag — every
bias is folded into its BatchNorm and bound to %zb{c} — so convBiasGradB and its strided peers
are never emitted and there is nothing to state. Same situation as ResNet-50. The five
*GradBBf16 kinds the bf16 artifacts emit are folded in
Foundation/Bf16GradNodes.lean.
⚠⚠ Everything here is GENERIC IN THE ROW, and that is load-bearing #
Every definition and theorem below takes a UibSpec binder s and reads its widths off it, so
s.ic, s.h and s.ic * s.expand are VARIABLES. That is not a convenience: MNv4's resolutions
are literals, and MobileNetV4FullB.lean records four separate kernel blow-ups caused by letting
den and width-indexed rfls actually RUN at 224/112/56/28/14/7. Stated at a row binder they stay
stuck; the capstone then instantiates at the 21 concrete rows, which is application and is free.
The chain, node for node from uibBackSkipGradB #
| cotangent | at | feeds |
|---|---|---|
dyOut | the block output — and the project BN's output, the add being linear | %u{p}pg, %u{p}pbt |
CotPc | project conv's output (bnBatchBack) | %u{p}pW |
CotDn | post-DW BN's output (convBackBatched, then the post-DW relu's selectPos mask) | %u{p}dg, %u{p}dbt |
CotDc | post-DW conv's output | %u{p}dW |
CotEn | expand BN's output (depthwiseBackBatched, then the expand relu's mask) | %u{p}eg, %u{p}ebt |
CotEc | expand conv's output | %u{p}eW |
CotQn | pre-DW BN's output | %u{p}qg, %u{p}qbt |
CotQc | pre-DW conv's output | %u{p}qW |
CotIn | the block input — addVB (depthwiseBackBatched dQc) dyOut | the previous block |
⛔ A cotangent one step off is a silently wrong gradient, not a type error: %u{p}eg reads the
cotangent at the expand BN's OUTPUT and %u{p}eW the one at the expand CONV's output, and both
have the same type.
⛔ One replica. Under mnv4in_adamdp64* every node named here feeds allReduceMeanF
(DataParallelNode.lean, §4d); this is the per-replica gradient.
Cotangent at the project CONV's output — dyOut through the project BN's backward.
⭐ dyOut itself is the cotangent at the project BN's output: the bottleneck is linear, so
nothing masks it. Feeds %u{p}pW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the post-DW BN's output — the project conv's input-VJP, masked by the post-DW
relu. Feeds %u{p}dg and %u{p}dbt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the post-DW CONV's output — through the post-DW BN's backward. Feeds %u{p}dW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the expand BN's output — masked by the expand relu. Feeds %u{p}eg/%u{p}ebt.
⭐⭐ This is where the chain DISPATCHES on the table, exactly as mnv4PostDWSlot does and
off the same row: with a post-depthwise the incoming cotangent is that depthwise's input-VJP;
without one (postDWk = 0, the ConvNeXt-like and FFN rows) the project conv's input-VJP
arrives here directly, because the render emits no post-DW nodes at all. One chain, three
stride-1 profiles, and the if reduces at every concrete row.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the expand CONV's output — through the expand BN's backward. Feeds %u{p}eW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the pre-DW BN's output — the expand conv's input-VJP, masked by the pre-DW relu.
Feeds %u{p}qg and %u{p}qbt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the pre-DW CONV's output — through the pre-DW BN's backward. Feeds %u{p}qW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
⚠⚠ A near-copy of the stride-1 chain, and it has to be. Only two things differ — the
leading depthwise is depthwiseStride2Flat rather than depthwiseFlat, and the block input sits
at 2h — but those two changes run through every type in the chain, so the whole thing is
re-stated rather than instantiated. ⭐ Everything from the expand down is the same composition at
the reduced resolution; the stride is entirely consumed by the first op, which is what
mnv4UibPreStridedBody means one tier up.
⛔ And there is no skip: all three stride-2 rows change channels (ic ≠ oc), so the block IS
the body, dx is the strided depthwise's input-VJP alone, and there is no addVB fan-in.
Cotangent at the project CONV's output — dyOut through the project BN's backward.
⭐ dyOut itself is the cotangent at the project BN's output: the bottleneck is linear, so
nothing masks it. Feeds %u{p}pW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the post-DW BN's output — the project conv's input-VJP, masked by the post-DW
relu. Feeds %u{p}dg and %u{p}dbt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the post-DW CONV's output — through the post-DW BN's backward. Feeds %u{p}dW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the expand BN's output — masked by the expand relu. Feeds %u{p}eg/%u{p}ebt.
⚠ No dispatch here, unlike the stride-1 chain: all three of Conv-M's stride-2 rows have
postDWk > 0, so the post-depthwise is always present on this path.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the expand CONV's output — through the expand BN's backward. Feeds %u{p}eW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the STRIDED pre-DW BN's output — the expand conv's input-VJP, masked by the pre-DW relu.
Feeds %u{p}qg and %u{p}qbt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the STRIDED pre-DW conv's output — through the pre-DW BN's backward. Feeds %u{p}qW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The pre-strided block's input cotangent — the STRIDED depthwise's input-VJP, landing at
2h. No fan-in: ic ≠ oc, so the block has no skip.
Equations
- Proofs.Mnv4TieB.mnv4SBodyCotIn N s p xin dyOut = Proofs.EnetTiePoC.dStridedInB N p.Wq p.bq (Proofs.Mnv4TieB.mnv4SCotQc N s p xin dyOut)
Instances For
The BODY's input cotangent — what the render's dx carries before the skip fan-in.
⭐ Dispatches on s.preDWk the way mnv4PreDWSlot does: with a pre-depthwise the body's dx
is that depthwise's input-VJP, without one it is the expand conv's.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The skip fan-in itself: body dx + dyOut, at the block-input shape.
⚠ Split from mnv4BodyCotIn for the same reason mnv4SkipGraphB is split from the body graph
builders: the add needs s.oc and s.ic to be the SAME type, which they are at every stride-1
row and are not at a row binder. The body's cotangent is row-generic; the add is applied at the
concrete row, where s.oc = s.ic is rfl.
Equations
- Proofs.Mnv4TieB.mnv4SkipCotIn bodyDx dyOut i = bodyDx i + dyOut i
Instances For
⭐ ExtraDW block, tied. All twelve parameter nodes — four conv/depthwise weights and four
BatchNorm γ/β pairs — denote the certified batched Σ_n gradient at the real forward
activations and the real backward-chain cotangent driven by dyOut.
⚠ Each BatchNorm's γ/β reads the cotangent at THAT BatchNorm's output (CotQn, CotEn,
CotDn, and dyOut itself for the project) while its conv reads the one at the conv's output
(CotQc, CotEc, CotDc, CotPc). Off by one and the gradient is silently wrong — the two
have the same type. ⭐ The project BN's pair reads dyOut UNMASKED: the bottleneck is linear.
⛔ There are no conv-bias conjuncts: MobileNetV4RenderB has no convBias flag, so those ops
are never emitted and every slot here is exercised by the artifact.
Equations
- One or more equations did not get rendered due to their size.
Instances For
⭐⭐ And it holds — twelve instantiations of the shared ∀ cot leaf folds with
the freedom removed. Nothing here is new mathematics; what is new is that the cotangents are
the chain's, not free.
⭐⭐ And it holds — nine instantiations of the §1 fold at the chain's cotangents.
⭐⭐ And it holds — six instantiations of the §1 fold at the chain's cotangents.
⭐ Pre-strided block, tied — rows 1, 3 and 11. All twelve parameter nodes — four conv/depthwise weights and four
BatchNorm γ/β pairs — denote the certified batched Σ_n gradient at the real forward
activations and the real backward-chain cotangent driven by dyOut.
⚠ Each BatchNorm's γ/β reads the cotangent at THAT BatchNorm's output (CotQn, CotEn,
CotDn, and dyOut itself for the project) while its conv reads the one at the conv's output
(CotQc, CotEc, CotDc, CotPc). Off by one and the gradient is silently wrong — the two
have the same type. ⭐ The project BN's pair reads dyOut UNMASKED: the bottleneck is linear.
⚠⚠ The leading node is depthwiseStridedWeightGradB — depthwiseStride2Flat, SYMMETRIC
padding, reading its input at 2h. Every other node is the stride-1 profile's at the reduced
resolution, because the stride is consumed entirely by that first depthwise.
⛔ No skip and no addVB: ic ≠ oc at all three rows, so the block IS its body.
Equations
- One or more equations did not get rendered due to their size.
Instances For
⭐⭐ And it holds — twelve instantiations (the first at the STRIDED depthwise) of the shared ∀ cot leaf folds with
the freedom removed. Nothing here is new mathematics; what is new is that the cotangents are
the chain's, not free.
⚠ All three are GENERIC IN THEIR WIDTHS, for the reason MobileNetV4FullB.lean's stem-graph
docstring records at length: pinning MNv4's literal resolutions here lets den and the
width-indexed rfls actually run, and the kernel gives up. The capstone instantiates.
Cotangent at the stem BN's output — the fused stage's dx, masked by the stem relu.
Feeds %sg and %sbt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the stem CONV's output — through the stem BN's backward. Feeds %sW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Stem, tied. Its three nodes at the chain's cotangents.
⛔⛔ And the chain STOPS here. There is no convStridedXlaBackBatched node: no render emits
a gradient into %x, so the artifact's backward ends at this weight gradient. That is why the
stem sits outside MobileNetV4FullB.lean's CertLayer trunk, and it is B0's situation
exactly.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the fused stage's project CONV output. ⭐ dyF reaches the project BN's γ/β
unmasked — the fused stage ends in a BatchNorm with no activation. Feeds %f0pW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the fused BN's output — the project conv's input-VJP through swish's
backward. ⭐ No mask: swish is smooth, which is why this stage carries no kink hypothesis
anywhere. Feeds %f0cg and %f0cbt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the fused CONV's output — through the fused BN's backward. Feeds %f0cW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The fused stage's input cotangent — the SYMMETRIC strided conv's input-VJP, landing at 2h.
Equations
- Proofs.Mnv4TieB.mnv4FusedCotIn N h w Wc bc εc γc βc Wp bp εp γp βp xin dyF = Proofs.ResNet34TieB.cStridedInB N Wc bc (Proofs.Mnv4TieB.mnv4FusedCotC N h w Wc bc εc γc βc Wp bp εp γp βp xin dyF)
Instances For
⭐ Fused stage, tied — its six parameter nodes. ⚠ %f0cW is convStridedWeightGradB,
SYMMETRIC padding, where the stem's is the XLA-SAME twin: two phases in one net. ⭐ And the
fused BN's γ/β read the cotangent that came through SWISH's backward, not through a relu mask —
this is the one stage in MNv4 with no kink anywhere.
Equations
- One or more equations did not get rendered due to their size.
Instances For
⭐ The head's GAP-and-dense tail is ResNet-34's, reused: r34HeadCotBlk is its certified
input cotangent and r34HeadTiedB its two parameter nodes. What is MNv4's own is the pair of
1×1 conv-BN-relu stages in front of it — Conv-M's head has TWO convs where mnv4Head models
one.
Cotangent at the SECOND head BN's output — the GAP/dense tail's input cotangent, masked by
that stage's relu. Feeds %hg and %hbt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the second head CONV's output. Feeds %hW.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the FIRST head BN's output. Feeds %h1g and %h1bt.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cotangent at the first head CONV's output. Feeds %h1W.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The head's input cotangent — what block 21 receives as its dyOut.
Equations
- Proofs.Mnv4TieB.mnv4HeadCotIn N h w W1 b1 ε1 γ1 β1 W2 b2 ε2 γ2 β2 Wd bd xin g = Proofs.EnetTiePoC.cInB N W1 b1 (Proofs.Mnv4TieB.mnv4HeadCotH1c N h w W1 b1 ε1 γ1 β1 W2 b2 ε2 γ2 β2 Wd bd xin g)
Instances For
⭐ Head, tied — all EIGHT nodes: two conv weights, two BatchNorm γ/β pairs, and the
classifier's weight and bias. ⭐ The last two are r34HeadTiedB, reused verbatim: MNv4's
GAP-and-dense tail IS ResNet-34's at a different width.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The per-BLOCK forward prefixes: mnv4Blk0 is the fused stage's output — block 1's input —
and mnv4Blk{k} is the activation entering block k+1.
⚠ MobileNetV4FullB.lean's mnv4Pre0 … mnv4Pre6 are the RESOLUTION-GROUP prefixes, which is
the granularity T1 and T2 need; the tie needs one per BLOCK, so these 22 name the finer chain.
mnv4Blk0 is definitionally mnv4Pre1.
Equations
- Proofs.Mnv4TieB.mnv4Blk0 N w x = Proofs.StableHLO.mnv4Pre1 N w x
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
⭐⭐ The whole batch-BN MobileNetV4-Conv-M train step, tied. Threading the net's own forward
prefixes as the block inputs and an arbitrary loss cotangent g down through the certified
head backward, the 21 certified UIB block backwards and the fused stage, every parameter
GRADIENT node of the net — stem 3, fused 6, thirteen ExtraDW-profile blocks × 12, four
ConvNeXt-like × 9, four FFN × 6, head 8 — denotes the certified batched Σ_n gradient. That is
233, the render's own census and mnv4_fwd.mlir's signature minus %x. No free activation
and no symbolic cotangent below the loss.
⭐⭐ g IS A BINDER. The loss chain is not part of this statement; mnv4_lossCot_is_smoothedCE_grad
instantiates it at the label-smoothed softmax cotangent the artifacts actually emit.
⭐ No smoothness hypothesis and no 0 < ε, and N and nCls are both binders. The folds
are ∀ cot statements at explicitly constructed cotangents; the kink and positivity conditions
live one tier down, in the CertLayers whose .ok MobileNetV4FullBVJP.lean binds. ⚠ MNv4
ships a single resolution, so unlike ResNet-50 there is no q.
⛔ One replica. Under mnv4in_adamdp64* every node named here feeds allReduceMeanF
(DataParallelNode.lean, §4d), and the AdamW tail sits downstream of all of them.
⭐ And the loss cotangent g is instantiated: MNv4's is the label-smoothed softmax chain.
Row by row, the six-op chain MobileNetV4RenderB emits (softmaxRow → subB → scaleB → addVB → shiftB → divConstB, α = 0.1) is (1/B)·∂/∂logits of soft-target cross-entropy against the
SMOOTHED target, at that example's real logits.
⚠ softmaxRow at m := 1 — the rowB/unrowB spelling ResNet-34 and ResNet-50 use, NOT
ConvNeXt's and ViT's expe → softmaxDiv at the plain N·K width. Read off the render's own
lines rather than assumed: those two take different lemmas (smoothedLossCotGraph here,
smoothedLossCotGraphDiv there) and nothing in the types tells them apart.
⭐ MNv4 ships ONE loss — there is no BCE twin to state, where ResNet-50 needed both. The only hypothesis is that the example's target sums to 1: a one-hot, or mixup's convex combination.