MobileNetV2 rendered from the verified AST, at the BATCHED index — the SOLE renderer #
⭐⭐ This file writes every MobileNetV2 artifact as of 2026-09-06, when leg 2 of
planning/archive/renderer_convergence.md retired MobileNetV2Render.lean. Before that the net had two
renderers and they were two different functions:
MobileNetV2Render.leanrendered PER-EXAMPLE BN (bnPerChannelF, reduce[2,3]) and wrote the SGD-inlinemobilenetv2_train_step.mlirand both train forwards, while every artifact in this file — includingmobilenetv2in_rmsdp64, whose accuracy the book quotes — is BATCH BN (reduce[0,2,3]).scripts/regen_verified_mlir.sh'scheck_adam_prefixcarried the split as its LASTKNOWN_SPLITentry.- That renderer's train step was reachable only from
mobilenetv2-verified, whose own header measured its accuracy at chance (387/3925, byte identical every epoch — running-statistic threading lives only intrainAdamSched) and said not to quote it. Both are retired.
What the convergence changed, and what it did not. @mobilenetv2_fwd and @mobilenetv2in_fwd
now come from mnv2FwdChainB, the ONE traversal every train step below differentiates, so the net
that scores and the net that trains are one graph by construction. ⚠ Their BatchNorm world and
their parameter names both change; the driver binds positionally, so the rename reaches nothing.
⚠ The EVAL forwards did NOT move: bnPerChannelEvalF reads frozen statistics and reduces nothing,
so they are BatchNorm-world-agnostic and re-render byte-identically from the per-example chain,
which came here with them. See that section's banner for the second reason not to move them.
The whole graph sits at N := B, so every batch-coupled den is honest: bnBatchF,
bnBatchBack and the whole *GradB family reduce over the batch, and at N = 1 each would
describe a one-example function while the emitted text reduces over all B (§2b).
The ops this net needed that no other did (§2f): BatchableOp.relu6 — mnv2 is the only ReLU6 net
in the kit, EfficientNet being all-swish — and selectMidB, its two-sided backward mask, which
reads the saved per-example pre-activation and therefore CANNOT be a BatchableOp descriptor. Plus
depthwise{,Strided}BiasGradB: enet's depthwise convs are followed by BN so their bias is folded
into it, mnv2's are not.
The optimizer is the proven adamMNextF/adamVNextF/adamWParamF triple applied to the un-fused
*GradB gradients. The cotangent is composed from kit ops (softmaxRow → subB → scaleB → addVB → shiftB → divConstB, α = 0.1, K = nClasses), so this render does NOT match the hand-written artifact
op-for-op and the tie against it must be numeric. %loss is report-only and stays outside the AST,
exactly as resnet34/cifar8's does (§5).
⭐ The Proofs tier this file's train steps are tied at is the batch-BN one:
MobileNetV2FullB.lean (T1 forward, T2), MobileNetV2FullBVJP.lean (T1's VJP),
MobileNetV2FoldPaperG.lean (T3 §1 fold, un-fused) and MobileNetV2StepTieB.lean (T3 §1a
tie) — §4.2 of planning/archive/proofs_tier_to_paper_nets.md, all 2026-09-06. The per-example
fold and tie were retired (2026-09-08 and 2026-09-19), since no committed bytes exercised them.
Render is value-independent (skel erases values), so placeholder zeros and ε := 0 are passed;
the emitted literals carry the real values.
A trainable parameter: emitted name (no %), its un-fused gradient SSA name, and its shape.
The AdamW tail is a fold over this list, so the θ/m/v output order cannot drift from the
signature order. (The ResNet34RenderB peer of the same name is private to that file.)
Instances For
Equations
Saved forward SSA names a block's backward + gradient passes reference. ec/en/er are the
block input for the no-expand block (b1), which has no expand conv.
- code : String
- o : String
- ec : String
- en : String
- er : String
- dc : String
- dn : String
- dr : String
- pc : String
- stE : String
- stD : String
- stP : String
Instances For
Equations
The 210 parameters of the 17-block paper-spec net, in func-arg order. stem (4) + b1
no-expand (8) + b2..b17 (16 × 12 = 192) + head (4) + dense (2) = 210 — the same decomposition
paperSig uses, at the names the committed AdamW artifact presents.
Instances For
The 104 BN running-statistic slots = 52 BN layers × (μ, var): stem 1, b1 two (no expand
BN), b2..b17 three each (48), head 1. Both an input (…i) and an output slot.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The driver's variant slug for a given (B, replicas): the artifact is
verified_mlir/mobilenetv2_<variant>_train_step.mlir, the entry point is
@mobilenetv2_<variant>_train_step, and LEAN_MLIR_VARIANT selects it. All three must agree —
the shim checks the entry name and refuses a mismatch outright ("entry mismatch") rather than
running the wrong graph. B = 32 is deliberately unsuffixed so the committed artifact keeps its
name. The #guards at the bottom pin the literal #eval paths against this.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The forward record mnv2FwdChainB hands to its two consumers: the emitted code, the stem's
three activations, the seventeen block records, the head's three, and the GAP/logits names.
- code : String
- stc : String
- stn : String
- str : String
- hc : String
- hn : String
- hr : String
- gap : String
- log : String
- sst : String
- hst : String
Instances For
Equations
The MobileNetV2 forward chain at the BATCHED index — one traversal, consumed by both
@mobilenetv2_fwd and every train step that differentiates it.
⭐⭐ This exists so @mobilenetv2_fwd and the batch-BN train steps cannot be different nets.
They were: the retired MobileNetV2Render.lean built its forward from the PER-EXAMPLE chain —
bnPerChannelF, reduce [2,3], divisor H·W — while every train step in this file is batch
BN, reduce [0,2,3], divisor B·H·W. scripts/regen_verified_mlir.sh's check_adam_prefix
carried the divergence as the LAST KNOWN_SPLIT entry for as long as both existed. This is
ResNet34RenderB.r34FwdChainB's shape, for ResNet50RenderB.r50FwdChainB's reason
(planning/archive/renderer_convergence.md, leg 2).
⚠ The EVAL forward is deliberately NOT moved onto this chain, exactly as ResNet-34's and
ResNet-50's are not: bnPerChannelEvalF reads frozen per-channel statistics and reduces
nothing, so mobilenetv2_fwd_eval.mlir is BatchNorm-world-agnostic and correct against both
chains. (Until 2026-09-08 there was a second reason: a whole-net float budget's provenance
claim named that artifact's SSA names line for line; the budget is deleted, and the eval
forward stays where it is only because moving it buys nothing.)
⭐ Extracting the traversal is byte-neutral for the train step: pretty's SSA counter follows
the call SEQUENCE, and the sequence is unchanged.
Equations
- One or more equations did not get rendered due to their size.
Instances For
@mobilenetv2_fwd rendered from the BATCHED chain — the same traversal every batch-BN
train step in this file differentiates, so the net that scores and the net that trains are one
graph by construction. Replaces the retired MobileNetV2Render.lean as the writer of
verified_mlir/mobilenetv2_fwd.mlir (2026-09-06, planning/archive/renderer_convergence.md leg 2).
Takes %x plus the parameters in mnv2SigList order — 159 inputs at the shipped
convBias := false — and returns logits [B, nClasses].
⚠ This CHANGES what @mobilenetv2_fwd computes, and that is the point. The retired render
normalised PER EXAMPLE while the AdamW and RMSProp steps whose accuracies the book quotes
normalise over the BATCH. ⚠ It also renames every parameter — %sW/%b2eW/%Wd where the
retired one said %Ws/%We2/%Wfc — because the names now come from mnv2SigList, this
file's single source. The driver binds positionally, so nothing downstream sees the rename.
Equations
- One or more equations did not get rendered due to their size.
Instances For
MobileNetV2 (17-block paper spec) AdamW train step, batch BN, rendered from the verified AST
at N := B. 739 inputs (%x, 210 θ, 210 m, 210 v, %lr/%bc1/%bc2, 104 running-stat
slots, %onehot) and 737 outputs (210 θ', 210 m', 210 v', %loss/%bc1/%bc2, 104 batch
stats) — the interface the committed hand-written artifact already presents, so the driver is
unchanged. Parameter ORDER comes from mnv2SigList and stat order from mnv2StatSigList, the
single sources, so the arity/order contract cannot drift.
Stem 3×3/s2 (3→32, 224→112, NO maxpool) → b1 (no-expand t=1, 32→16) → b2..b17 (4 stride-2
downsamples, 10 identity skips, 2 stage-first widenings) → 1×1 conv-BN-relu6 head (320→1280) →
GAP → dense (1280→nClasses).
Instances For
- code : String
- o : String
- ec : String
- en : String
- er : String
- dc : String
- dn : String
- dr : String
- pc : String
The block's BN layers in forward order,
(stat prefix, channels, spatial side). The eval forward turns each into a%{prefix}mu/%{prefix}varinput pair;MobileNetV2RenderB's AdamW step hands the matching batch μ/var back in the SAME order (it walks the same block list). Order is expand-BN → depthwise-BN → project-BN, with the expand entry ABSENT for the no-expand block b1 — the layoutmobilenetv2Verified.bnChannelsis listed in, which is how the driver packsrunningBnStats. A misaligned slot is SILENT: the arities still match and the wrong layer's statistics simply flow into the wrong site (§2e).
Instances For
Equations
Every SSA name the 17-block MobileNetV2 forward produces, plus the 52-entry BN stat layout.
mnv2Fwd{,Eval}FaithfulV return just logits; the train step additionally consumes the stem,
head and per-block names on the way back.
- code : String
- stc : String
- stn : String
- str : String
- hc : String
- hn : String
- hr : String
- gap : String
- logits : String
The 52 BN layers as
(stat prefix, channels, spatial side), stem -> blocks in forward order -> head. Single source for the eval signature and the eval BN sites.
Instances For
Equations
@mobilenetv2_fwd_eval rendered ENTIRELY from the verified AST — the inference forward,
every BN site consuming frozen per-channel running stats (bnPerChannelEvalF) instead of
reducing statistics out of its activation. Same 210 params in the same order, plus the 104 stat
inputs (52 BN layers × μ/var, interleaved per layer in bnChannels order): 315 inputs.
Its train-step partner is the batch-BN mobilenetv2_adam_train_step in MobileNetV2RenderB,
whose returned batch μ/var the driver EMAs into exactly these slots. Being frozen-stat affine,
this graph is the same in either BN world — which is why it can live beside the per-example
chain: bnPerChannelEvalF performs no reduction, so there is no batch to be honest about.
Equations
- One or more equations did not get rendered due to their size.