Documentation

LeanMlir.Proofs.Codegen.MobileNetV2RenderB

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:

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

    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.

    Instances For

      Backward result: code, the dx cotangent to the previous block, and the block's parameter gradients in func-arg order.

      Instances For
        def Proofs.StableHLO.mnv2SigList (nClasses : ) (convBias : Bool) :

        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
            def Proofs.StableHLO.mnv2AdamVariant (B replicas : ) (opt : OptKind := OptKind.adamw) (bf16 : Bool := false) :

            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.

              Instances For
                def Proofs.StableHLO.mnv2FwdChainB (B nClasses : ) (epsStr : String) (convBias bf16 : Bool := false) (replicas : := 1) (sync : Bool := false) :

                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
                  def Proofs.StableHLO.mobilenetv2FwdFaithfulB (B nClasses : ) (epsStr : String) (slug : String := "mobilenetv2") (convBias bf16 : Bool := false) :

                  @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
                    def Proofs.StableHLO.mobilenetv2AdamTrainStepFaithfulB (B nClasses : ) (epsStr : String) (replicas : := 1) (convBias : Bool := false) (slug : String := "mobilenetv2") (opt : OptKind := OptKind.adamw) (bf16 forceSync : Bool := false) :

                    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}var input 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 layout mobilenetv2Verified.bnChannels is listed in, which is how the driver packs runningBnStats. A misaligned slot is SILENT: the arities still match and the wrong layer's statistics simply flow into the wrong site (§2e).

                      Instances For

                        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.

                        Instances For
                          def Proofs.StableHLO.mnv2FwdEvalFaithfulV (B nClasses : ) (epsStr : String) (convBias : Bool := false) (slug : String := "mobilenetv2") :

                          @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.
                          Instances For