Documentation

LeanMlir.Proofs.Nets.ViT.ViTStepTie

ViT-Tiny step tie — the SGD-inline train step, all 200 parameters at the real backward chain #

What this file is. The tie of verified_mlir/vit_train_step.mlir — the SGD-inline step ViTRender.lean writes — at the fused θ − lr·g ops: vit_net_tied_certified (the last theorem) threads all 200 ViT-Tiny parameters through the committed multi-head (3 heads, d_head 64), depth-12, vector-LayerNorm forward and the loss-driven backward cotangent chain. The statement is per example, at one image and a hard label; the artifact runs a batch of 32, and that batch and its mean lie outside this statement. Its batched peer at the un-fused gradient node, the smoothed loss and a batch binder — the chain of the drop-free f32 vitin_* artifacts — is ViTTieGB.vit_net_tiedGB, built from this file's block ties by batchMap / batchMapAux.

The file has two layers:

Every conjunct delegates to a ViTFold.*_den fold lemma at the chain cotangent — zero new ops, zero new bridges. The vector-LN granularity that ships ([192] γ/β) is what is modelled.

Multi-head promotion (3 heads, d_head=64) — the committed-render block tie #

The committed vitTrainStepRenderV is multi-head: the SDPA-internal backward dAtt → dQ/dK/dV runs per head (vitCotD{Q,K,V}mh, ViTMultiHeadChain), so the Q/K/V dense cotangents are the multi-head …mh ones rather than the single-head vitCotD{Q,K,V}; everything else (the out-proj Wo, LN₂, the MLP) is head-agnostic. vitBlockTiedMHV states the block's 16 parameter ties with those cotangents (no separate ss/p saves — the per-head scores/weights are recomputed inside the …mh cots from the saved Q/K); every conjunct delegates to a head-agnostic fold generic ViTFold.*_den.

def Proofs.ViTTie.vitBlockTiedMHV (gf : GeluForm) {Np1 heads d mlpDim : ℕ} (xN wN bN gN epsStr lrStr cotN : String) (ε : ℝ) (γ1 β1 γ2 β2 : Vec (heads * d)) (Wq Wk Wv Wo : Mat (heads * d) (heads * d)) (bq bk bv bo : Vec (heads * d)) (Wfc1 : Mat (heads * d) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d)) (bfc2 : Vec (heads * d)) (xin ln1 q k v att h ln2 : Vec (Np1 * (heads * d))) (g m1 : Vec (Np1 * mlpDim)) (dyOut : Vec (Np1 * (heads * d))) (lr : ℝ) :
Equations
  • One or more equations did not get rendered due to their size.
Instances For
    theorem Proofs.ViTTie.vit_block_tiedMHV {gf : GeluForm} {Np1 heads d mlpDim : ℕ} (xN wN bN gN epsStr lrStr cotN : String) (ε : ℝ) (γ1 β1 γ2 β2 : Vec (heads * d)) (Wq Wk Wv Wo : Mat (heads * d) (heads * d)) (bq bk bv bo : Vec (heads * d)) (Wfc1 : Mat (heads * d) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d)) (bfc2 : Vec (heads * d)) (xin ln1 q k v att h ln2 : Vec (Np1 * (heads * d))) (g m1 : Vec (Np1 * mlpDim)) (dyOut : Vec (Np1 * (heads * d))) (lr : ℝ) :
    vitBlockTiedMHV gf xN wN bN gN epsStr lrStr cotN ε γ1 β1 γ2 β2 Wq Wk Wv Wo bq bk bv bo Wfc1 bfc1 Wfc2 bfc2 xin ln1 q k v att h ln2 g m1 dyOut lr

    Multi-head forward + cot-in + input-only block wrappers (the thread template) #

    noncomputable def Proofs.ViTTie.vitBlockFwdOMHV (gf : GeluForm) {Np1 heads d mlpDim : ℕ} (ε : ℝ) (γ1 β1 γ2 β2 : Vec (heads * d)) (Wq Wk Wv Wo : Mat (heads * d) (heads * d)) (bq bk bv bo : Vec (heads * d)) (Wfc1 : Mat (heads * d) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d)) (bfc2 : Vec (heads * d)) (xin : Vec (Np1 * (heads * d))) :
    Vec (Np1 * (heads * d))

    Multi-head forward block step (the committed render's block forward = vitBlockSpelledMHV, which IS transformerBlockV at general heads by vitBlockSpelledMHV_eq).

    Equations
    • One or more equations did not get rendered due to their size.
    Instances For
      noncomputable def Proofs.ViTTie.vitBlockCotInAtMHV (gf : GeluForm) {Np1 heads d mlpDim : ℕ} (ε : ℝ) (γ1 β1 γ2 β2 : Vec (heads * d)) (Wq Wk Wv Wo : Mat (heads * d) (heads * d)) (bq bk bv bo : Vec (heads * d)) (Wfc1 : Mat (heads * d) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d)) (xin dyOut : Vec (Np1 * (heads * d))) :
      Vec (Np1 * (heads * d))

      Multi-head attention-residual fan-in: the block-input cotangent the chain hands upstream (vitCotXinV at the multi-head Q/K/V dense cots — vitCotLn1 Wq Wk Wv dQmh dKmh dVmh IS the multi-head LN₁ fan-in vitCotLn1MH). Recomputes the saves from xin (the vitBlockSpelledMHV let-chain, multi-head att).

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For
        def Proofs.ViTTie.vitBlockTiedAtMHV (gf : GeluForm) {Np1 heads d mlpDim : ℕ} (xN wN bN gN epsStr lrStr cotN : String) (ε : ℝ) (γ1 β1 γ2 β2 : Vec (heads * d)) (Wq Wk Wv Wo : Mat (heads * d) (heads * d)) (bq bk bv bo : Vec (heads * d)) (Wfc1 : Mat (heads * d) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d)) (bfc2 : Vec (heads * d)) (xin dyOut : Vec (Np1 * (heads * d))) (lr : ℝ) :

        Multi-head input-only block tie — recompute the 9 saves from xin, then vit_block_tiedMHV.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          theorem Proofs.ViTTie.vit_block_tiedAtMHV {gf : GeluForm} {Np1 heads d mlpDim : ℕ} (xN wN bN gN epsStr lrStr cotN : String) (ε : ℝ) (γ1 β1 γ2 β2 : Vec (heads * d)) (Wq Wk Wv Wo : Mat (heads * d) (heads * d)) (bq bk bv bo : Vec (heads * d)) (Wfc1 : Mat (heads * d) mlpDim) (bfc1 : Vec mlpDim) (Wfc2 : Mat mlpDim (heads * d)) (bfc2 : Vec (heads * d)) (xin dyOut : Vec (Np1 * (heads * d))) (lr : ℝ) :
          vitBlockTiedAtMHV gf xN wN bN gN epsStr lrStr cotN ε γ1 β1 γ2 β2 Wq Wk Wv Wo bq bk bv bo Wfc1 bfc1 Wfc2 bfc2 xin dyOut lr

          The multi-head input-only block tie holds — unfold the saves, delegate to vit_block_tiedMHV.

          The non-block param bundle + the all-200-params capstone (committed ViT-Tiny config) #

          vitFinalLNTied/vitHeadTied/vitEmbedTied bundle the final vector-LN γ/β, the classifier Wcls/bcls, and the patch-embed wConv/bConv/cls/pos as den = certified at their chain cotangents — each a direct delegation to the fold generics (ViTFold.*_den), with the cls op (denseBiasSgdB N=1) folded by vit_cls_den (its row-0 batch slice IS clsTokenGrad, closed by clsToken_sgd_certified). Then vit_net_tied_certified threads the REAL forward + loss-driven backward and bundles all 200 params.

          theorem Proofs.ViTTie.vit_cls_den (clsN lrStr cotN : String) (Wc : Kernel4 192 3 16 16) (bc cls : Vec 192) (pos : Mat 197 192) (img : Vec (3 * 224 * 224)) (dyEmbed : Vec (197 * 192)) (lr : ℝ) (i : Fin 192) :
          StableHLO.den (StableHLO.SHlo.denseBiasSgdB clsN lrStr cls lr (StableHLO.SHlo.operand cotN (StableHLO.clsSliceFlat 196 192 dyEmbed))) i = cls i - lr * ∑ j : Fin (197 * 192), pdiv (fun (cl : Vec 192) => patchEmbedFlat 3 224 224 16 196 192 Wc bc cl pos img) cls i j * dyEmbed j
          def Proofs.ViTTie.vitFinalLNTied (gN xN bN epsStr lrStr cotN : String) (ε : ℝ) (γF βF : Vec 192) (Wcls : Mat 192 10) (b12out : Vec (197 * 192)) (g : Vec 10) (lr : ℝ) :

          Final vector-LN γF/βF tied at the classifier-back cot vitCotFl.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            theorem Proofs.ViTTie.vit_finalLN_tied (gN xN bN epsStr lrStr cotN : String) (ε : ℝ) (γF βF : Vec 192) (Wcls : Mat 192 10) (b12out : Vec (197 * 192)) (g : Vec 10) (lr : ℝ) :
            vitFinalLNTied gN xN bN epsStr lrStr cotN ε γF βF Wcls b12out g lr
            def Proofs.ViTTie.vitHeadTied (aN wN bN lrStr cotN : String) (hn : Vec 192) (Wcls : Mat 192 10) (bcls g : Vec 10) (lr : ℝ) :

            Classifier Wcls/bcls tied at the loss cotangent g.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              theorem Proofs.ViTTie.vit_head_tied (aN wN bN lrStr cotN : String) (hn : Vec 192) (Wcls : Mat 192 10) (bcls g : Vec 10) (lr : ℝ) :
              vitHeadTied aN wN bN lrStr cotN hn Wcls bcls g lr
              def Proofs.ViTTie.vitEmbedTied (wN xN bN clsN pN lrStr cotN : String) (Wc : Kernel4 192 3 16 16) (bc cls : Vec 192) (pos : Mat 197 192) (img : Vec (3 * 224 * 224)) (dyEmbed : Vec (197 * 192)) (lr : ℝ) :

              Patch embed wConv/bConv/cls/pos tied at the embed-output cot dyEmbed.

              Equations
              • One or more equations did not get rendered due to their size.
              Instances For
                theorem Proofs.ViTTie.vit_embed_tied (wN xN bN clsN pN lrStr cotN : String) (Wc : Kernel4 192 3 16 16) (bc cls : Vec 192) (pos : Mat 197 192) (img : Vec (3 * 224 * 224)) (dyEmbed : Vec (197 * 192)) (lr : ℝ) :
                vitEmbedTied wN xN bN clsN pN lrStr cotN Wc bc cls pos img dyEmbed lr

                The ties' weight records #

                Twelve blocks as BlockParamsV (ViTDepthK's bundle), plus the patch embed, final LN and head. The ties share ONE ε across every LN. The dot-notation wrappers are abbrevs over the constructors above: a statement over a record unfolds to the unpacked one.

                ViT-Tiny as the ties bind it.

                Instances For
                  @[reducible, inline]
                  noncomputable abbrev Proofs.BlockParamsV.fwdO (gf : GeluForm) {Np1 heads d mlpDim : ℕ} (p : BlockParamsV (heads * d) mlpDim) (ε : ℝ) :
                  Vec (Np1 * (heads * d)) → Vec (Np1 * (heads * d))

                  The block's forward (vitBlockFwdOMHV).

                  Equations
                  Instances For
                    @[reducible, inline]
                    noncomputable abbrev Proofs.BlockParamsV.cotIn (gf : GeluForm) {Np1 heads d mlpDim : ℕ} (p : BlockParamsV (heads * d) mlpDim) (ε : ℝ) :
                    Vec (Np1 * (heads * d)) → Vec (Np1 * (heads * d)) → Vec (Np1 * (heads * d))

                    The block's input cotangent (vitBlockCotInAtMHV).

                    Equations
                    Instances For
                      @[reducible, inline]
                      abbrev Proofs.BlockParamsV.TiedAt (gf : GeluForm) {Np1 heads d mlpDim : ℕ} (p : BlockParamsV (heads * d) mlpDim) (xN wN bN gN epsStr lrStr cotN : String) (ε : ℝ) (xin dyOut : Vec (Np1 * (heads * d))) (lr : ℝ) :

                      The block's per-example tie (vitBlockTiedAtMHV).

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        theorem Proofs.BlockParamsV.tied_at {gf : GeluForm} {Np1 heads d mlpDim : ℕ} (p : BlockParamsV (heads * d) mlpDim) (xN wN bN gN epsStr lrStr cotN : String) (ε : ℝ) (xin dyOut : Vec (Np1 * (heads * d))) (lr : ℝ) :
                        TiedAt gf p xN wN bN gN epsStr lrStr cotN ε xin dyOut lr
                        theorem Proofs.ViTTie.vit_net_tied_certified {gf : GeluForm} (xN wN bN gN aN clsN pN epsStr lrStr cotN : String) (ε : ℝ) (w : ViTTieWeights 10) (img : Vec (3 * 224 * 224)) (label : Fin 10) (lr : ℝ) :
                        have ib1 := patchEmbedFlat 3 224 224 16 196 192 w.Wc w.bc w.cls w.pos img; have ib2 := BlockParamsV.fwdO gf w.b1 ε ib1; have ib3 := BlockParamsV.fwdO gf w.b2 ε ib2; have ib4 := BlockParamsV.fwdO gf w.b3 ε ib3; have ib5 := BlockParamsV.fwdO gf w.b4 ε ib4; have ib6 := BlockParamsV.fwdO gf w.b5 ε ib5; have ib7 := BlockParamsV.fwdO gf w.b6 ε ib6; have ib8 := BlockParamsV.fwdO gf w.b7 ε ib7; have ib9 := BlockParamsV.fwdO gf w.b8 ε ib8; have ib10 := BlockParamsV.fwdO gf w.b9 ε ib9; have ib11 := BlockParamsV.fwdO gf w.b10 ε ib10; have ib12 := BlockParamsV.fwdO gf w.b11 ε ib11; have b12out := BlockParamsV.fwdO gf w.b12 ε ib12; have fl := Mat.flatten fun (r : Fin 197) => layerNormVec 192 ε w.γF w.βF (Mat.unflatten b12out r); have hn := StableHLO.clsSliceFlat 196 192 fl; have logits := dense w.Wcls w.bcls hn; have g := fun (c : Fin 10) => softmax 10 logits c - oneHot 10 label c; have dy12 := vitCotTowerOutV 196 192 10 ε w.γF w.Wcls b12out g; have dy11 := BlockParamsV.cotIn gf w.b12 ε ib12 dy12; have dy10 := BlockParamsV.cotIn gf w.b11 ε ib11 dy11; have dy9 := BlockParamsV.cotIn gf w.b10 ε ib10 dy10; have dy8 := BlockParamsV.cotIn gf w.b9 ε ib9 dy9; have dy7 := BlockParamsV.cotIn gf w.b8 ε ib8 dy8; have dy6 := BlockParamsV.cotIn gf w.b7 ε ib7 dy7; have dy5 := BlockParamsV.cotIn gf w.b6 ε ib6 dy6; have dy4 := BlockParamsV.cotIn gf w.b5 ε ib5 dy5; have dy3 := BlockParamsV.cotIn gf w.b4 ε ib4 dy4; have dy2 := BlockParamsV.cotIn gf w.b3 ε ib3 dy3; have dy1 := BlockParamsV.cotIn gf w.b2 ε ib2 dy2; have dyEmbed := BlockParamsV.cotIn gf w.b1 ε ib1 dy1; BlockParamsV.TiedAt gf w.b1 xN wN bN gN epsStr lrStr cotN ε ib1 dy1 lr ∧ BlockParamsV.TiedAt gf w.b2 xN wN bN gN epsStr lrStr cotN ε ib2 dy2 lr ∧ BlockParamsV.TiedAt gf w.b3 xN wN bN gN epsStr lrStr cotN ε ib3 dy3 lr ∧ BlockParamsV.TiedAt gf w.b4 xN wN bN gN epsStr lrStr cotN ε ib4 dy4 lr ∧ BlockParamsV.TiedAt gf w.b5 xN wN bN gN epsStr lrStr cotN ε ib5 dy5 lr ∧ BlockParamsV.TiedAt gf w.b6 xN wN bN gN epsStr lrStr cotN ε ib6 dy6 lr ∧ BlockParamsV.TiedAt gf w.b7 xN wN bN gN epsStr lrStr cotN ε ib7 dy7 lr ∧ BlockParamsV.TiedAt gf w.b8 xN wN bN gN epsStr lrStr cotN ε ib8 dy8 lr ∧ BlockParamsV.TiedAt gf w.b9 xN wN bN gN epsStr lrStr cotN ε ib9 dy9 lr ∧ BlockParamsV.TiedAt gf w.b10 xN wN bN gN epsStr lrStr cotN ε ib10 dy10 lr ∧ BlockParamsV.TiedAt gf w.b11 xN wN bN gN epsStr lrStr cotN ε ib11 dy11 lr ∧ BlockParamsV.TiedAt gf w.b12 xN wN bN gN epsStr lrStr cotN ε ib12 dy12 lr ∧ vitFinalLNTied gN xN bN epsStr lrStr cotN ε w.γF w.βF w.Wcls b12out g lr ∧ vitHeadTied aN wN bN lrStr cotN hn w.Wcls w.bcls g lr ∧ vitEmbedTied wN xN bN clsN pN lrStr cotN w.Wc w.bc w.cls w.pos img dyEmbed lr

                        The whole depth-12 multi-head ViT-Tiny train step, tied — all 200 params (the vit peer of convnext's cnx_net_tied_certified, at the committed config: 3 heads, d_head=64, D=192, N=196, mlpDim=768, 10 classes, 16×16 patches). The real forward patchEmbed → 12 multi-head vector-LN blocks → final vector-LN → CLS-slice → dense head and the loss-driven backward cotangent chain (the per-block multi-head fan-ins, the final-LN-back vitCotTowerOutV, the classifier-back vitCotFl, the embed-output cot = block-1's vitBlockCotInAtMHV output) are threaded, and EVERY param op denotes θ − lr·(certified per-layer Jacobian · the chain cotangent): the 12 blocks' 192 params (vitBlockTiedAtMHV), the final-LN γ/β, the classifier Wcls/bcls, and the patch-embed wConv/bConv/cls/pos — 200/200. Each chain cotangent is the certified VJP backward of the stages above it (vitBlockCotInAtMHV_eq_vjp, vitCotTowerOutV_eq_vjp, below). The statement is per example, at one image img and a hard label label; the artifact's batch of 32 and its mean lie outside it (the batched form is ViTTieGB.vit_net_tiedGB).

                        Every cotangent the capstone threads is a certified VJP backward #

                        vit_net_tied_certified threads two per-example constructors: the head's vitCotTowerOutV and each block's vitBlockCotInAtMHV. They are the render's spelling of the backward — per-head SDPA with pad and slice, LayerNorm as rowScaleFlat then rowLNBackFlat at γ = 1, separate dense backs — so tying them to the certified VJPs is a proof, not a definitional match: the lemmas below rewrite each spelling into the one the whole-net tie (ViTWholeBackCertifiedTie) is stated at. The only hypothesis is the LayerNorm's 0 < ε.

                        The render's per-token dense backward is perRowFlat of the transposed dense — the spelling mhsaBackFlat uses.

                        theorem Proofs.vitCotDQmh_eq_core {Np1 heads d : ℕ} (Q K V : Mat Np1 (heads * d)) (dA : Vec (Np1 * (heads * d))) :
                        vitCotDQmh Np1 heads d Q.flatten K.flatten V.flatten dA = coreQFlat Q K V dA

                        The rendered multi-head Q backward (per-head slice → SDPA back → pad, summed) is the certified concatenated core coreQFlat: vitCotDQmh_eq plus the pad-sum-is-concat lemma.

                        theorem Proofs.vitCotLn2_eq_perRowFlatPR {gf : GeluForm} {Np1 D mlpDim : ℕ} (W1 : Mat D mlpDim) (W2 : Mat mlpDim D) (m1 : Mat Np1 mlpDim) (dyOut : Vec (Np1 * D)) :
                        vitCotLn2 gf W1 W2 m1.flatten dyOut = perRowFlatPR Np1 D (fun (r : Fin Np1) => dense W1.transpose 0 ∘ (diagBack fun (c : Fin mlpDim) => gf.scalarDeriv (m1 r c)) ∘ dense W2.transpose 0) dyOut

                        The rendered MLP backward (fc2 back, GELU mask, fc1 back) is the per-row fold vitBlockBackV uses.

                        theorem Proofs.vitCotDKmh_eq_core {Np1 heads d : ℕ} (Q K V : Mat Np1 (heads * d)) (dA : Vec (Np1 * (heads * d))) :
                        vitCotDKmh Np1 heads d Q.flatten K.flatten V.flatten dA = coreKFlat Q K V dA

                        vitCotDQmh_eq_core for K.

                        theorem Proofs.vitCotDVmh_eq_core {Np1 heads d : ℕ} (Q K V : Mat Np1 (heads * d)) (dA : Vec (Np1 * (heads * d))) :
                        vitCotDVmh Np1 heads d Q.flatten K.flatten V.flatten dA = coreVFlat Q K V dA

                        vitCotDQmh_eq_core for V.

                        theorem Proofs.vitCotXin_eq_blockBack {gf : GeluForm} {Np1 heads d mlpDim : ℕ} (ε : ℝ) (γ1 γ2 : Vec (heads * d)) (Wq Wk Wv Wo : Mat (heads * d) (heads * d)) (Wfc1 : Mat (heads * d) mlpDim) (Wfc2 : Mat mlpDim (heads * d)) (Q K V H : Mat Np1 (heads * d)) (m1 : Mat Np1 mlpDim) (xin dyOut : Vec (Np1 * (heads * d))) :
                        vitCotXinV ε γ1 Wq Wk Wv xin (vitCotDQmh Np1 heads d Q.flatten K.flatten V.flatten (vitCotAttV gf ε γ2 Wo Wfc1 Wfc2 H.flatten m1.flatten dyOut)) (vitCotDKmh Np1 heads d Q.flatten K.flatten V.flatten (vitCotAttV gf ε γ2 Wo Wfc1 Wfc2 H.flatten m1.flatten dyOut)) (vitCotDVmh Np1 heads d Q.flatten K.flatten V.flatten (vitCotAttV gf ε γ2 Wo Wfc1 Wfc2 H.flatten m1.flatten dyOut)) (vitCotHV gf ε γ2 Wfc1 Wfc2 H.flatten m1.flatten dyOut) = vitBlockBackV Wq Wk Wv Wo Q K V ε γ1 xin Wfc1 Wfc2 (fun (r : Fin Np1) (c : Fin mlpDim) => gf.scalarDeriv (m1 r c)) γ2 H.flatten dyOut

                        The rendered block chain is vitBlockBackV, at any saved activations. The render's LayerNorm backward (rowScaleFlat γ then rowLNBackFlat at γ = 1) is rowLNVecFlatBack (rowLNBack_affine_eq); the per-head attention backward is the concatenated core; the MLP backward is the per-row fold; the Q/K/V fan-in and both residual adds reassociate.

                        theorem Proofs.vitBlockCotInAtMHV_eq_vjp {gf : GeluForm} {Np1 heads d mlpDim : ℕ} (ε : ℝ) (hε : 0 < ε) (p : BlockParamsV (heads * d) mlpDim) (xin dyOut : Vec (Np1 * (heads * d))) :
                        ViTTie.vitBlockCotInAtMHV gf ε p.γ1 p.β1 p.γ2 p.β2 p.Wq p.Wk p.Wv p.Wo p.bq p.bk p.bv p.bo p.Wfc1 p.bfc1 p.Wfc2 xin dyOut = (transformerBlockVHasVJPMat gf Np1 heads d mlpDim ε p.γ1 p.β1 hε p.Wq p.Wk p.Wv p.Wo p.bq p.bk p.bv p.bo p.γ2 p.β2 p.Wfc1 p.bfc1 p.Wfc2 p.bfc2).toHasVJP.backward xin dyOut

                        A ViT block's input cotangent is its certified VJP's backward. vitCotXin_eq_blockBack at the real saved activations, then vitBlockBackVAt_eq_vjp. The one forward fact needed is that the attention output the chain recomputes (per-head spelled) is transformerAttnSublayerV (mhsaLayer_spelled).

                        noncomputable def Proofs.vitHeadHasVJP (N D nC : ℕ) (ε : ℝ) (hε : 0 < ε) (γF βF : Vec D) (Wcls : Mat D nC) (bcls : Vec nC) :
                        HasVJP (classifierFlat N D nC Wcls bcls ∘ fun (v : Vec ((N + 1) * D)) => Mat.flatten fun (r : Fin (N + 1)) => layerNormVec D ε γF βF (Mat.unflatten v r))

                        The head classifier ∘ final LN as one certified VJP, at any class count.

                        Equations
                        • One or more equations did not get rendered due to their size.
                        Instances For
                          theorem Proofs.vitCotTowerOutV_eq_vjp (N D nC : ℕ) (ε : ℝ) (hε : 0 < ε) (γF βF : Vec D) (Wcls : Mat D nC) (bcls : Vec nC) (b : Vec ((N + 1) * D)) (g : Vec nC) :
                          vitCotTowerOutV N D nC ε γF Wcls b g = (vitHeadHasVJP N D nC ε hε γF βF Wcls bcls).backward b g

                          The head's input cotangent — the last block's dyOut — is its certified VJP's backward: the render's final-LN spelling is rowLNVecFlatBack (rowLNBack_affine_eq), then the classifier and final-LN leaf ties.