PoC: the FULL [3,3,9,3] ConvNeXt-T §1a TIE — the whole net tied through the real forward #
The Chapter-7 §1a tie: mnv2's whole-net thread (now MobileNetV2TieB.mnv2_net_tiedB; the
per-example original was deleted 2026-09-08) for the
ConvNeXt-T schedule. The §1 fold (ConvNeXtFold + M2/M3/ViT) already makes
every rendered param op den = certified ∀ cotangent; this file feeds each consumer the real
forward activations of the convNextTrainStepFaithfulV render and the loss-driven
backward-chain cotangent that net delivers — so the whole 18-block train step is den-composed
forward → loss → backward, no free activations, no symbolic cotangent.
The net this is about #
verified_mlir/convnext_train_step.mlir, measured, not assumed:
| convention | this file | read from |
|---|---|---|
| depth / widths | [3,3,9,3], 96 → 192 → 384 → 768 | ConvNeXtRender.cnxTiny |
| stem | 4×4/s4 patchify conv then channel-LN | convNextFwdChain |
| normalisation | chanLNTensor3 (per-channel [c] affine, h·w statistics per example) at all 22 spatial sites: 1 stem + 18 block + 3 downsample | ConvNeXtRender.lnFwdSite |
| head | GAP → vector-LN at one row (rowLNVecFlat 1 768) → dense | headLnFwdSite, restored 2026-08-30 |
| activation | GELU (smooth — no kink mask anywhere) | fwdBlock |
| layer scale | per-channel Vec c, broadcast by chanIdx | layerScaleChF |
| padding | symmetric; ConvNeXt is a PyTorch-origin net and has no XLA-SAME site | — |
| params | 182 | allParams, and the artifact's 184 func args (%x + 182 + %onehot) |
Superseded scope note. Until 2026-09-05 this file tied the scalar-LN ConvNeXt-T — the retired whole-map
bnForwardspelling, with no stem LN and a scalarVec 1head LN. §2m flipped the renderer to the real per-channelchannel_layer_normand added the stem LN, §2n deleted the flag that had selected the old spelling, and 2026-08-30 restored the head LN. Every theorem in the old file was true and none of them was about the committed bytes. These are: the 22 spatial LN sites arechanLNTensor3withVec cγ/β, the head is ViT's vector-LN atN = 1, and the stem LN is here.
What is new against the scalar-LN version #
- channel-LN γ/β (
Vec c) at every spatial site, throughCnxPoC.chanLn{Gamma,Beta}Sgd_den— the render re-emits the[h·w, c]transposes and runs ViT'sveclnGammaSgd/rowDenseBiasSgdon that view, so the op operands here arechanLNRowsof the saved LN input and of the chain cotangent, while the certified Jacobian ischanLNTensor3's in thec·h·wactivation layout (ConvNeXtChannelLN's permutation argument bridges the two). - the channel-LN input-VJP in the cotangent chain:
chanLNTensor3Backwhere the scalar version hadbn_grad_input. It is the certified VJP —ConvNeXtBackCertifiedTie.chanLNTensor3Back_eq_chanLN_vjp. - the stem LN, which the scalar version did not have at all:
psng/psnbttie at the stem-LN output cotangent, and the stem conv's own gradients now see the LN input-VJP of it. - the head at the vector LN:
hng/hnbt : Vec 768throughViTPoC.veclnGammaSgd_den/rowDenseBiasSgd_den_lnbetaatN = 1. Stated at the literal 768 because1 * mdoes not reduce at a variablem— the render's own documented trap, in the proof this time. - the four even-kernel weight grads are no longer a gap. The three downsample 2×2/s2 weights
are
convStridedWeightSgd(ResNet34PoC.convStridedW_denis kernel-generic), and the stem 4×4/s4 weight isconvStride4WeightGrad, whosedenisflatConvStride4_weight_grad_has_vjp.
Coverage / honest residual #
All 182 parameters are tied. 181 of them at the full θ − lr·(certified ∂Loss/∂θ) step; the
stem weight psW at its gradient, because the render emits convStride4WeightGrad and wraps
it in the hand-written sgd text (a declared §5 carve-out — there is no fused
convStride4WeightSgd op to be the den of). What remains outside: the block backward is
rendered hand-written, so the cotangent SSA ↔ chain-cot correspondence is the per-op trust the
whole suite carries; plus per-op pretty lexing; LN 0 < ε smoothness; ℝ → Float32 — the
boundary every prior fold carries.
ConvNeXt block — all 9 params tied (depthwise → channel-LN → expand → GELU → project → layer-scale → +skip) #
Forward: out = addV( layerScaleCh lg (conv₁ₓ₁ₚᵣ( gelu( conv₁ₓ₁ₑₓ( chanLN( dw₇ₓ₇(xin) ))))), xin ).
Backward from the block-output cotangent dyOut (the residual addV is the outermost op and there
is no post-add activation, so it passes dyOut straight to the layer-scale output): layer-scale-back
(cnxCotP) → project-conv-back → GELU mask (cnxCotE) → expand-conv-back (cnxCotN) → the
channel-LN input-VJP (chanLNTensor3Back) → depthwise-back. Only that last-but-one step differs
from the scalar-LN thread; cnxCotP/cnxCotE/cnxCotN are LN-form-agnostic and are reused
verbatim from ConvNeXtChainClose.
ConvNeXt block, tied. All 9 params (depthwise 7×7 W+b, channel-LN γ/β at Vec c,
expand/project 1×1 conv W+b, per-channel layer-scale γ) denote the certified loss-descent
step at the real block forward activations + the chain cotangents driven by dyOut.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Downsample — channel-LN → 2×2/s2 conv (all 4 params tied) #
Forward: o = convˢ²(chanLN(xin)) (LN over the block-input grid 2h×2w with a Vec ci affine,
then a 2×2/s2 conv ci → co). No skip. Backward from dyOut: strided-conv-back (cotN') →
channel-LN-back. The strided weight is no longer a gap: convStridedWeightSgd is emitted at
2×2 since sWGradGeom split the odd/even padding cases, and ResNet34PoC.convStridedW_den is
kernel-generic.
Downsample, tied. Channel-LN γ/β at the ci·(2h)·(2w) input grid, plus the strided conv's
weight and bias, at the real forward + the chain cotangents.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Stem — 4×4/s4 patchify conv → channel-LN (all 4 params) #
psng/psnbt tie at dyStem, the cotangent block 1 delivers at the stem-LN output; the conv's
own two parameters then see cotPatch, the LN input-VJP of it. The bias grad is a pure cotangent
reduce, so the render emits it as a stride-1 convBiasSgd at the OUTPUT resolution and the
carried W/x are generic — the same modelling the mnv2/r34 stems use. The weight is the
convStride4WeightGrad op, and it ties at the gradient: its SGD wrap is hand-written text.
Stem, tied. Channel-LN γ/β, the conv bias, and the conv weight's gradient.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Head — GAP → vector-LN at one row → dense #
After GAP the tensor is a single [768] row, so "normalise each spatial row over its channels"
and "normalise the feature vector" are the same function at m = 1: the head is ViT's per-token
LN with one token, and headLnFwdSite is lnFwdSite with the two transposes deleted. Stated at
the LITERAL 768 — 1 * m does not reduce at a variable m (Nat.mul recurses on its second
argument), which is the annotation trap the render carries in its own comment.
Head LN + dense bias, tied. The head-LN γ/β (at the pooled row gap, cot = the dense-back
cotHn) and the dense bias (cot = the loss g) at the real forward.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dense head weight Wd, tied to the WHOLE softmax-CE loss — Wd − lr·∂(CE ∘ dense)/∂Wd.
The emitted loss-cotangent graph denotes the softmax-CE gradient at the logits.
Forward aliases (@[irreducible]) — thread block inputs through the real forward #
@[irreducible] so the 18-deep nested composition stays opaque during the capstone's dimension
inference (the r34/mnv2 heartbeat lesson).
The stem output: patchify conv then channel-LN (§2m — the pre-§2m render had no stem LN).
Equations
- Proofs.CnxTiePoC.cnxStemFwdO ε Wst bst psng psnbt x = Proofs.chanLNTensor3 c h w ε psng psnbt (Proofs.flatConvStride4 Wst bst x)
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Proofs.CnxTiePoC.cnxBlockFwdChO ε Wdw bdw ng nbt Wex bex Wpr bpr lg xin i = Proofs.CnxTiePoC.cnxBlockBodyChO ε Wdw bdw ng nbt Wex bex Wpr bpr lg xin i + xin i
Instances For
Equations
- Proofs.CnxTiePoC.cnxDownFwdChO ε dng dnbt Wd bd xin = Proofs.flatConvStride2 Wd bd (Proofs.chanLNTensor3 ci (2 * h) (2 * w) ε dng dnbt xin)
Instances For
Backward cot-in constructors (@[irreducible]) — thread block dyOuts (the residual fan-in) #
ConvNeXt block input cotangent: depthwise-back(cotD) + dyOut (the identity-skip fan-in),
with cotD through the channel-LN input-VJP.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Downsample input cotangent (at ci·(2h)·(2w)): the channel-LN input-VJP of the
strided-conv-back. No skip.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The cotangent at the last block output xhead (= s3b2's dyOut): gap-back(headLN-back( dense-back(g))). The head LN's input-VJP is the render's rowScaleF γ then lnRowBack at
γ = 1, which is rowLNVecFlatBack (ConvNeXtBackB0.rowLNBack_affine_eq).
Equations
- One or more equations did not get rendered due to their size.
Instances For
Input-only *TiedAt wrappers (@[irreducible]) — compute internals from a block's input #
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
The whole-net capstone — all 182 params through the REAL forward + composed cotangent #
The convNextTrainStepFaithfulV forward threaded: block inputs are the forward prefixes
(cnxStemFwdO / cnxBlockFwdChO / cnxDownFwdChO), and the backward cotangents are composed
from the loss g = softmax(logits) − onehot down through dense (dense_has_vjp) + the head LN +
GAP (globalAvgPoolFlat_has_vjp) + every block's backward, with the residual fan-in + dyOut at
each of the eighteen identity-skip merges, the channel-LN-back at each of the three downsamples,
and the stem LN's own back before the patchify conv's gradients. Each stem / block / down / head
tie then holds at its real input + threaded cotangent. The full §1a tie: the whole [3,3,9,3]
182-parameter ConvNeXt-T train step is den-composed forward → loss → backward, no free
activations, no symbolic cotangent.
The whole [3,3,9,3] ConvNeXt-T train step, tied. Threading the real (channel-LN,
per-channel layer-scale) forward and the loss-driven backward cotangent chain (GELU masks, the
residual fan-in at every identity skip, the channel-LN-back at every downsample and at the
stem), the 18 ConvNeXt blocks, the 3 downsamples, the 4×4/s4 stem with its LN, the
GAP → LN → dense head, and the dense total-loss fold + loss-cotangent graph all denote the
certified loss-descent step. All 182 parameters; psW at its gradient (§5 carve-out).