ViT on CertLayer, folded image → logits #
ViT's whole-net backward graph vitNetBackGraph (patchEmbed → tower → final vec-LN →
classifier, at every depth) is derived here from the generic CertifiedChain fold:
vitTrunkV_graph proves the CertLayer chain produces the hand-written vitBodyBackGraphKMHV
term for term, and vitTrunkV_fwd proves its forward is the shipped vitBodyKVFlat. So the
bespoke tower induction in ViTBackB0.lean is an instance of the generic one.
Pluggable blocks #
ViTBackB0.lean threads an incoming-cotangent subgraph ecot : SHlo n through the vec-LN
production chain (transformerMlpBackGraph → mlpSublayerV* → attnSublayerV* →
transformerBlockV* → the tower), each faithfulness statement carrying den ecot = Mat.flatten dz;
every statement at a fixed Vec cotangent is the one at ecot := .operand "%d…" (Mat.flatten dz).
The two sublayers of a block compose as subgraphs, and so do successive blocks in the tower.
Note: attnSublayerVInnerBackGraphMH still passes den e into mhsaBackGraphMH, because that
MHSA graph takes a Vec cotangent. It is inside the attention arm, not between blocks, so it does
not block composition.
The fold runs image → logits #
ViT's stem is an affine patchify conv and its head is a CLS slice plus a dense — both linear, so
both backward graphs are activation-independent. So vitNetLayer = stem ∘ trunk ∘ finalLN ∘ head
is one CertLayer, assembled by comp alone, and vitNetBackGraph_faithful (the whole-net
capstone) follows from it: the hand-written vitNetBackGraph denotes
(vitForwardKVHasVJP …).backward. VJP witnesses of one map have one backward, so the last step
is HasVJPAt.backward_unique_of_eq along the forward equation vitNetLayer_fwd.
ok = True #
GELU and LayerNorm are smooth everywhere, so a ViT block has a global HasVJPMat, lifted
pointwise by .toHasVJPAt, and every layer's precondition is True. EfficientNet (swish) and
ConvNeXt (GELU) are the same; ResNet-34/50 (ReLU), MobileNetV2 (ReLU6) and MobileNetV4 (ReLU)
carry _at hypotheses because those activations have no derivative at their kinks.
Scope. This is a certified composition of backward graphs; it is not a proof that
verified_mlir/vit_train_step.mlir is this graph.
The depth-k ViT trunk as one CertLayer. Written in the shipped Fin k → BlockParamsV
shape and mirroring vitBodyKVFlat's recursion (block 0 runs first), so the two can be
compared term for term below. The only content is CertLayer.comp, which is already proven —
depth costs nothing.
Equations
- Proofs.StableHLO.vitTrunkV gf ε hε 0 x_2 = Proofs.StableHLO.CertLayer.id' (Np1 * ((hm1 + 1) * d))
- Proofs.StableHLO.vitTrunkV gf ε hε k.succ ps = (Proofs.StableHLO.vitBlockVLayer✝ gf ε hε (ps 0)).comp (Proofs.StableHLO.vitTrunkV gf ε hε k fun (i : Fin k) => ps i.succ)
Instances For
The trunk's forward is the shipped depth-k body. Without this the fold would be a
chain of blocks that merely resembles ViT's; with it, vitTrunkV is vitBodyKVFlat.
The generic fold reproduces the hand-written tower, term for term.
vitBodyBackGraphKMHV is ViTBackB0's bespoke depth-k reverse fold, proven faithful there
by an induction on k that re-does the chain-rule argument at every depth. This theorem says
the CertLayer chain's graph — built by comp, whose faithfulness was proven ONCE and for
all nets — is that same term. So the bespoke induction is not a second, parallel artifact to
keep in sync; it is an instance.
The proof is the two round-trips unflatten (flatten A) = A (the saved activation the block
graph differentiates at) and blockVFlat (flatten A) = flatten (blockV A) (the activation the
TAIL differentiates at) — which is exactly the fact CertLayer.comp encodes and the endo slip
would break.
ViT's stem is an affine patchify conv and its head is GAP-free (a CLS slice + dense), so both are linear and their backward graphs are activation-independent.
The patch-embedding stem as a CertLayer. Its graph ignores the saved activation
entirely — patchEmbed is affine, so the input-VJP is the same linear map everywhere.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The classifier head as a CertLayer — CLS-slice then dense, both linear, so the graph
ignores its activation for the same reason the stem's does.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The whole net as one CertLayer — stem, depth-k trunk, final LN, head, composed
by comp alone. Image in, logits out, and the backward graph and its faithfulness come with
it.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The whole-net layer's forward is the shipped vitForwardKV.
The whole-net chain's backward graph is vitNetBackGraph. The stem/trunk/LN/head
version of vitTrunkV_graph: ViTBackB0's hand-composed whole-net graph is what
CertLayer.comp produces, so vitNetBackGraph_faithful is a consequence of the shared
combinator rather than a parallel result. The saved activations comp threads
automatically are exactly the ones that theorem pins by hand.
The whole net is certified at every input — ok = True end to end, because every stage
is smooth (affine stem, GELU/LN blocks, LN, affine head). No side condition anywhere.
Whole-net backward-graph faithfulness. The reverse-composed backward graph
vitNetBackGraph denotes the proven whole-net VJP vitForwardKVHasVJP.backward at every
input image and output cotangent, at every depth k (multi-head, vector-LN). It falls out of
CertLayer.faithful at vitNetLayer plus vitNetLayer_graph — the composition argument is
comp's, proven once in CertifiedChain, and the only ViT-specific input is the forward
equality.
The peer of R34BWeights / R50BWeights / mnv4Blocks: the shipped config's shape
pinned in the types instead of stated in a docstring. ViT-Tiny is 12 identical-shaped blocks at
heads = 3, d_head = 64 (D = 192), mlpDim = 768, N + 1 = 197 tokens — so unlike the conv
nets there is no ladder to pin, only the depth and the widths, and every block has the same type
(which is why chain over a List.replicate-shaped index is the right form here and a
per-row-typed parameter record buys nothing).