MLP VJP Proofs #
Formal VJP correctness for the layers of a 3-layer MLP.
All definitions over ℝ, proofs use Mathlib's Finset.sum.
Dense Jacobian — ∂(W·x + b)_j/∂x_i = W_{ij}. Derived from the
foundation theorems (pdiv_add, pdiv_const, pdiv_finset_sum,
pdiv_mul, pdiv_reindex). The proof factors
dense W b into (∑ i', x i' * W i' j) + b j, distributes pdiv
over the outer sum and finset sum, applies the product rule per
summand, and collapses the Kronecker δ.
Jacobian of dense wrt W — ∂dense(W, b, x)_j/∂W_{i, j'} = x_i·δ(j, j').
Derived from foundation theorems (pdiv_add, pdiv_const,
pdiv_finset_sum, pdiv_mul, pdiv_reindex) over the flatten
bijection. Symmetric counterpart to pdiv_dense.
Dense VJP — proved.
Equations
- Proofs.dense_has_vjp W b = { backward := fun (_x : Proofs.Vec m) (dy : Proofs.Vec n) => W.mulVec dy, correct := ⋯ }
Instances For
The Chapter-1 demo model: a linear classifier is a single dense layer.
Equations
- Proofs.mnistLinear W b = Proofs.dense W b
Instances For
Dense is everywhere differentiable. dense W b is affine in
x, hence smooth; this is the underlying Differentiable ℝ
statement that vjp_comp_at needs when composing through dense
layers.
Dense weight gradient is the outer product — theorem (Phase 7).
Mat.outer x dy is the cotangent-contracted Jacobian of dense(W, b, x)
with respect to W, at every index. This promotes the previous vacuous
rfl about Mat.outer into a real theorem connecting the outer product
to the actual weight gradient of dense.
(Mat.outer x dy) i j = ∑ k, pdiv (…) (Mat.flatten W) (fPF (i, j)) k · dy k
Dense weight backward — named accessor.
dW = x ⊗ dy (outer product).
Equations
- Proofs.dense_weight_grad x dy = Proofs.Mat.outer x dy
Instances For
ReLU's local linear part at a smooth point — the diagonal
indicator CLM. At each coordinate k, projects to y k if
x k > 0, otherwise zero. Two smooth points with the same sign
pattern share this same CLM.
Equations
- Proofs.reluLinearPart n x = ContinuousLinearMap.pi fun (k : Fin n) => if x k > 0 then ContinuousLinearMap.proj k else 0
Instances For
ReLU is differentiable at smooth points. Within Metric.ball x r
for r := min |x k|, every coordinate keeps its sign — so relu n
agrees with reluLinearPart n x on a neighborhood. EventuallyEq
promotes the CLM's HasFDerivAt to ReLU's.
ReLU is DifferentiableAt at smooth points. Corollary of
relu_hasFDerivAt; lets vjp_comp_at chain through ReLU.
ReLU bundled VJP — canonical (junk-at-kink) witness.
HasVJP.correct is satisfied by the canonical pdiv-derived backward:
at smooth points it is the diagonal indicator (per pdiv_relu); at
points where some coordinate is zero, pdiv (relu n) x agrees with
fderiv's junk default of 0, so the canonical backward is 0
there too — and correct holds by rfl.
The codegen (MlirCodegen.lean) emits the standard subgradient
formula if x > 0 then dy else 0 instead, which agrees with the
canonical witness at smooth points and differs at the kinks (the
convention relu'(0) := 0 used by every ML framework). The
smooth-point agreement is formal: see
relu_codegen_matches_canonical below. The Lean-vs-codegen gap at
the kinks is the codegen trust boundary — see
LeanMlir/Proofs/README.md.
Equations
- Proofs.relu_has_vjp n = { backward := fun (x dy : Proofs.Vec n) (i : Fin n) => ∑ j : Fin n, Proofs.pdiv (Proofs.relu n) x i j * dy j, correct := ⋯ }
Instances For
Bridge: relu_has_vjp's canonical backward matches the codegen
formula at smooth points.
At any point where no coordinate of x is zero, the canonical
pdiv-derived backward ∑ j, pdiv (relu n) x i j * dy j collapses
to the framework subgradient if x i > 0 then dy i else 0 that
MlirCodegen.lean actually emits. Closes the smooth-point half of
the codegen trust boundary — what's left is just the kink
convention.
Diagonal-indicator restatement of the smooth-point bridge.
relu_has_vjp.backward x dy i = 1_{x i > 0} · dy i at smooth
points — same content as relu_codegen_matches_canonical,
factored as (indicator) · dy i for downstream use.
ReLU pointwise VJP — no canonical-witness escape.
Constructs HasVJPAt (relu n) x at a smooth point. The backward
is the codegen-shape if x i > 0 then dy i else 0 directly; the
correct field is a real proof via pdiv_relu (the smooth-point
Jacobian) + sum-collapse, not rfl.
Equations
- Proofs.relu_has_vjp_at n x h_smooth = { backward := fun (dy : Proofs.Vec n) (i : Fin n) => if x i > 0 then dy i else 0, correct := ⋯ }
Instances For
Equations
- Proofs.crossEntropy c logits label = -Real.log (Proofs.softmax c logits label)
Instances For
Equations
- Proofs.mlpForward W₀ b₀ W₁ b₁ W₂ b₂ = Proofs.dense W₂ b₂ ∘ Proofs.relu d₂ ∘ Proofs.dense W₁ b₁ ∘ Proofs.relu d₁ ∘ Proofs.dense W₀ b₀
Instances For
MLP composition VJP — canonical witness.
The MLP forward composes dense W b (everywhere Differentiable)
with relu (non-Differentiable at the kinks). vjp_comp would
require Differentiable ℝ (relu n), which doesn't hold globally,
so the chain-rule route is blocked. The canonical pdiv-derived
backward inhabits HasVJP.correct directly via rfl — the
codegen substitutes the subgradient formula at the kinks (see
LeanMlir/Proofs/README.md for the trust-boundary discussion).
Equations
- One or more equations did not get rendered due to their size.
Instances For
MLP pointwise VJP — no canonical-witness escape.
Constructs HasVJPAt (mlpForward …) x by chaining vjp_comp_at
through dense → relu_at → dense → relu_at → dense. Requires the
intermediate pre-activations dense W₀ b₀ x and dense W₁ b₁ z₀
to avoid zero (no coordinate ties the ReLU kink) — exactly the
"smooth input" condition. Replaces the vacuous
mlp_has_vjp.correct := rfl with a real chain-rule proof at
smooth inputs.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Public correctness theorems for the canonical-witness defs #
Each _has_vjp def above bundles a backward function with a .correct
field; these _correct theorems expose that field as a top-level
proposition so consumers (downstream code, tests/comparator/,
doc-gen4) can refer to the contract directly without reaching into
record internals.
Public correctness theorem for relu_has_vjp: the canonical
witness's backward equals the pdiv-contracted Jacobian by definition.
Public correctness theorem for mlp_has_vjp: same pattern as
relu_has_vjp_correct, lifted to the three-layer MLP forward.
Public correctness theorem for relu_has_vjp_at — the
pointwise (smooth-input) variant. Unlike relu_has_vjp_correct, this
wrapper's underlying .correct field is a real proof
(pdiv_relu + sum-collapse), not rfl; the wrapper exposes it as
a top-level proposition for tests/comparator/ re-verification.
Public correctness theorem for mlp_has_vjp_at — the
pointwise variant composed via vjp_comp_at through
dense → relu_at → dense → relu_at → dense. The underlying
.correct field chains real chain-rule proofs (no rfl escape at
the ReLU kinks).