Documentation

LeanMlir.Proofs.Training.SgdDescent.Cnn

Lipschitz constants for the CNN softmax-CE loss — descent through the pool #

SgdDescent.Mlp discharged sgd_descends' smoothness hypothesis for every MLP weight layer; this file extends the program to the Chapter-3 MNIST CNN (conv → relu → conv → relu → maxpool → dense → relu → dense → relu → dense). What's genuinely new versus the MLP:

The capstone cnn_conv2_sgd_descends mirrors mlp_input_sgd_descends: under the four margins (relu₂, pool selection, relu₃, relu₄) at the step radius and the small-step condition, one inexact SGD step on the second conv kernel (one example, every other parameter fixed) decreases that example's cross-entropy loss by ≥ lr·‖∇L‖₂²/2, with the segment-Lipschitz constant explicit.

cnn_conv1_sgd_descends extends the program one layer deeper: the step now crosses conv2 AS A FUNCTION OF ITS INPUT. Conv is linear there, its Jacobian entry a single kernel tap (convTap, extracted point-free from the certified input-VJP), and its ℓ1 operator factor is LOCALITY — (channels)·kH·kW·w₂, not a spatial count. Under FIVE margins (relu₁ + the conv2 four, at conv1 radii) every routing decision freezes and the loss provably drops.

cnn_conv2_bias_sgd_descends / cnn_conv1_bias_sgd_descends close the biases: the bias-map Jacobian is a Kronecker channel indicator (conv2d_bias_pdiv, extracted from the certified bias VJP), the per-entry drift is exactly |e o| (no input bound a). Each conv layer's drift chain, margins and segment-Lipschitz gradient are stated once, for any parameter map with per-entry drift ρ·‖e‖₁ (Conv2Slot, Conv1Slot): the kernel rungs are ρ = a, the bias rungs ρ = 1 — the bare D radii and a² ↦ 1 in the constants. Both conv kernels, both conv biases and the dense-head weights of the Chapter-3 CNN (the latter via the MLP rungs, which omit bias columns) each have a single-layer, single-example descent statement, conditional on the margins above and the oracle-accuracy, small-step and dominance hypotheses. cnn_conv2_float_sgd_descends, cnn_conv1_float_sgd_descends, cnn_conv2_bias_float_sgd_descends and cnn_conv1_bias_float_sgd_descends replace the oracle accuracy by the proven accuracy of the FloatModel binary32 gradient; there the update is taken in ℝ and only the gradient is float-modelled.

The index plumbing and 2×2 max-pool window facts it reads tensors through are in ConvIndex; the conv as a weight-shared dense layer and its float forward (flatConvF_close) in ConvFloat.

noncomputable def Proofs.FloatModel.mnistCnnNoBnForwardF {ic c h w d1 nClasses kH kW : ℕ} (M : FloatModel) (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d1) (b₃ : Vec d1) (W₄ : Mat d1 d1) (b₄ : Vec d1) (W₅ : Mat d1 nClasses) (b₅ : Vec nClasses) :
Vec (ic * (2 * h) * (2 * w)) → Vec nClasses

The float MNIST-CNN (no BN) forward — the float peer of mnistCnnNoBnForward: rounded conv (flatConvF) and rounded dense (M.dense); relu and maxPoolFlat appear bare (exact in float).

Equations
  • One or more equations did not get rendered due to their size.
Instances For
    theorem Proofs.FloatModel.cnn_float_close {ic c h w d1 nClasses kH kW : ℕ} (M : FloatModel) (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d1) (b₃ : Vec d1) (W₄ : Mat d1 d1) (b₄ : Vec d1) (W₅ : Mat d1 nClasses) (b₅ : Vec nClasses) (x : Vec (ic * (2 * h) * (2 * w))) {w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ a : ℝ} (hw₁ : 0 ≤ w₁) (hβ₁ : 0 ≤ β₁) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (ha : 0 ≤ a) (hW₁ : ∀ (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW), |W₁ o cc kh kw| ≤ w₁) (hb₁ : ∀ (o : Fin c), |b₁ o| ≤ β₁) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d1), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d1), |b₃ j| ≤ β₃) (hW₄ : ∀ (i j : Fin d1), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d1), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d1) (j : Fin nClasses), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nClasses), |b₅ j| ≤ β₅) (hx : ∀ (i : Fin (ic * (2 * h) * (2 * w))), |x i| ≤ a) (k : Fin nClasses) :
    |M.mnistCnnNoBnForwardF W₁ b₁ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ x k - mnistCnnNoBnForward W₁ b₁ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ x k| ≤ layerBudget M.u d1 w₅ β₅ (layerAct d1 w₄ β₄ (layerAct (c * h * w) w₃ β₃ (layerAct (c * kH * kW) w₂ β₂ (layerAct (ic * kH * kW) w₁ β₁ a)))) (layerBudget M.u d1 w₄ β₄ (layerAct (c * h * w) w₃ β₃ (layerAct (c * kH * kW) w₂ β₂ (layerAct (ic * kH * kW) w₁ β₁ a))) (layerBudget M.u (c * h * w) w₃ β₃ (layerAct (c * kH * kW) w₂ β₂ (layerAct (ic * kH * kW) w₁ β₁ a)) (layerBudget M.u (c * kH * kW) w₂ β₂ (layerAct (ic * kH * kW) w₁ β₁ a) (layerBudget M.u (ic * kH * kW) w₁ β₁ a 0))))

    Whole-net MNIST-CNN forward rounding budget. The rounded forward is within an explicit closed-form layerBudget of the real conv→relu→conv→relu→maxpool→dense→relu→dense→relu→dense forward, per output logit — the binary32 forward-error bound for the Chapter-3 CNN.

    Each weight layer threads identically: conv layers as dense at their fan-in (ic·kH·kW, then c·kH·kW), the dense head at c·h·w / d1; relu and maxpool pass error through exactly (no rounding, no amplification). The budget is the mlp_float_close_uniform nest extended to the CNN's six layers — norm_num-evaluable at a concrete net and magnitude profile.

    theorem Proofs.conv2d_kernel_sub {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) (v e : Vec (oc * ic * kH * kW)) (o : Fin oc) (hi : Fin h) (wi : Fin w) :
    conv2d (Kernel4.unflatten (v + e)) b x o hi wi - conv2d (Kernel4.unflatten v) b x o hi wi = ∑ c : Fin ic, ∑ kh : Fin kH, ∑ kw : Fin kW, e (k4Idx o c kh kw) * convPad kH kW x c kh kw hi wi
    theorem Proofs.conv2d_kernel_drift {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) {a : ℝ} (ha : 0 ≤ a) (hx : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x c i j| ≤ a) (v e : Vec (oc * ic * kH * kW)) (o : Fin oc) (hi : Fin h) (wi : Fin w) :
    |conv2d (Kernel4.unflatten (v + e)) b x o hi wi - conv2d (Kernel4.unflatten v) b x o hi wi| ≤ a * ∑ c : Fin ic, ∑ kh : Fin kH, ∑ kw : Fin kW, |e (k4Idx o c kh kw)|

    Per-entry conv drift, slab-refined: a kernel perturbation moves the output entry (o, hi, wi) by at most a times the ℓ1 mass of the channel-o slab (each output reads only its own slab).

    theorem Proofs.conv2d_kernel_drift_total {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) {a : ℝ} (ha : 0 ≤ a) (hx : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x c i j| ≤ a) (v e : Vec (oc * ic * kH * kW)) (o : Fin oc) (hi : Fin h) (wi : Fin w) :
    |conv2d (Kernel4.unflatten (v + e)) b x o hi wi - conv2d (Kernel4.unflatten v) b x o hi wi| ≤ a * ∑ idx : Fin (oc * ic * kH * kW), |e idx|

    Per-entry conv drift against the TOTAL ℓ1 mass — the form the relu margins consume.

    theorem Proofs.conv2d_kernel_drift_sum {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) {a : ℝ} (ha : 0 ≤ a) (hx : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x c i j| ≤ a) (v e : Vec (oc * ic * kH * kW)) :
    ∑ o : Fin oc, ∑ hi : Fin h, ∑ wi : Fin w, |conv2d (Kernel4.unflatten (v + e)) b x o hi wi - conv2d (Kernel4.unflatten v) b x o hi wi| ≤ ↑(h * w) * (a * ∑ idx : Fin (oc * ic * kH * kW), |e idx|)

    ℓ1 conv drift: summed over all output entries, the drift is at most (h·w)·a·‖e‖₁ — the spatial multiplicity h·w is the price of weight sharing (each kernel entry touches every spatial position).

    theorem Proofs.MaxPool2MarginQ.poolBack_close {c h w : ℕ} {δ : ℝ} {x y : Tensor3 c (2 * h) (2 * w)} (hm : MaxPool2MarginQ δ x) (hclose : ∀ (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)), |y ci hi wi - x ci hi wi| ≤ δ) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) {ay ax e : ℝ} (ha : |ay - ax| ≤ e) :
    |(if MaxPool2IsArgmax y ci hi wi then ay else 0) - if MaxPool2IsArgmax x ci hi wi then ax else 0| ≤ e

    Float pool-backward closeness. Under the pool margin the float post-relu argmax matches the real one (isArgmax_iff), so the pool's backward selector 𝟙[(ci,hi,wi) is its window's argmax]·(pooled cotangent) differs from the certified one only through the pooled cotangent value — an indicator pass-through (indicator ∈ {0,1}), the pool peer of reluMask_close. The two cotangent values ay (float) / ax (real) enter only via their closeness |ay − ax| ≤ e.

    theorem Proofs.t3Idx_def {c h w : ℕ} (ci : Fin c) (hi : Fin h) (wi : Fin w) :

    Folds the raw finProdFinEquiv encoding back into t3Idx.

    theorem Proofs.ce_head3_differentiableAt {p d₃ d₄ nC : ℕ} (W₃ : Mat p d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (u : Vec p) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ u l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ u)) q ≠ 0) :
    DifferentiableAt ℝ (fun (y : Vec p) (x : Fin 1) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ y))))) label) u

    The 3-dense head CE ∘ d₅ ∘ relu ∘ d₄ ∘ relu ∘ d₃ is differentiable at any point whose two ReLU pre-activations are off the kinks.

    theorem Proofs.ce_head3_input_grad {p d₃ d₄ nC : ℕ} (W₃ : Mat p d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (u : Vec p) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ u l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ u)) q ≠ 0) (j : Fin p) :
    pdiv (fun (y : Vec p) (x : Fin 1) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ y))))) label) u j 0 = ∑ l : Fin d₃, W₃ j l * ((if dense W₃ b₃ u l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ u)) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ u))))) k - oneHot nC label k)))

    Loss input-gradient of the 3-dense head CE∘d₅∘relu∘d₄∘relu∘d₃ at the pooled vector — one pdiv_comp hop (peel dense W₃) on top of ce_head2_input_grad, exactly as ce_head2 was one hop on ce_head_relu. Note there is NO leading mask: the pool output feeds dense W₃ directly.

    theorem Proofs.pool_head_differentiableAt {c h w d₃ d₄ nC : ℕ} (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (z₂ : Vec (c * (2 * h) * (2 * w))) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), z₂ k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₂))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) z₂)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) z₂)))) q ≠ 0) :
    DifferentiableAt ℝ (fun (y : Vec (c * (2 * h) * (2 * w))) (x : Fin 1) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) y))))))) label) z₂

    The whole head above the conv output — CE∘head3∘maxPoolFlat∘relu — is differentiable at any point with the relu₂ pre-activation off the kinks, no pool ties (POST-relu), and the two head masks off the kinks.

    theorem Proofs.pool_relu_input_grad {c h w d₃ d₄ nC : ℕ} (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (z₂ : Vec (c * (2 * h) * (2 * w))) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), z₂ k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₂))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) z₂)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) z₂)))) q ≠ 0) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
    pdiv (fun (y : Vec (c * (2 * h) * (2 * w))) (x : Fin 1) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) y))))))) label) z₂ (t3Idx ci hi wi) 0 = (if z₂ (t3Idx ci hi wi) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₂)) ci hi wi then ∑ l : Fin d₃, W₃ (t3Idx ci (winRow hi) (winCol wi)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) z₂)) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) z₂)))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) z₂))))))) k - oneHot nC label k))) else 0

    Loss input-gradient at the conv output — the key glue of the conv rung. The chain pdivs through the relu (mask) and the pool (frozen selector): at a smooth point the sum over pooled coordinates collapses to the single argmax term, so

    ∂(CE∘head3∘pool∘relu)/∂z₂[ci,hi,wi] = relu'(z₂[ci,hi,wi]) · 𝟙[(ci,hi,wi) is its window's argmax] · head3grad(window(ci,hi,wi)).

    NB the pool acts on the POST-relu activation, so the smoothness and argmax conditions are stated on relu z₂, not z₂.

    theorem Proofs.conv2d_weight_pdiv {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) (v : Vec (oc * ic * kH * kW)) (o : Fin oc) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) (co : Fin oc) (hi : Fin h) (wi : Fin w) :
    pdiv (fun (v' : Vec (oc * ic * kH * kW)) => (conv2d (Kernel4.unflatten v') b x).flatten) v (k4Idx o cc kh kw) (t3Idx co hi wi) = if co = o then convPad kH kW x cc kh kw hi wi else 0

    Closed form of the conv weight-map pdiv — extracted from the certified VJP (conv2dWeightGradHasVJP) by contracting its .correct field against a basis vector. Kernel entry (o,cc,kh,kw) touches output (co,hi,wi) iff co = o, with coefficient the padded input read convPad. NB the right-hand side does not mention v: the weight map is affine, so its Jacobian is point-free — this is what lets the gradient difference along a step segment collapse to the head drift alone.

    noncomputable def Proofs.convPadWin {ic h w : ℕ} (kH kW : ℕ) (x : Tensor3 ic h w) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) :
    Vec (h * w)

    The padded-input window for a fixed kernel slot, flattened over the (hi, wi) spatial grid — the left operand of the conv weight-grad dot.

    Equations
    Instances For
      noncomputable def Proofs.cotWin {oc h w : ℕ} (cot : Tensor3 oc h w) (o : Fin oc) :
      Vec (h * w)

      The cotangent slab for a fixed output channel, flattened over (hi, wi).

      Equations
      Instances For
        @[simp]
        theorem Proofs.convPadWin_apply {ic h w : ℕ} (kH kW : ℕ) (x : Tensor3 ic h w) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) (hi : Fin h) (wi : Fin w) :
        convPadWin kH kW x cc kh kw (finProdFinEquiv (hi, wi)) = convPad kH kW x cc kh kw hi wi
        @[simp]
        theorem Proofs.cotWin_apply {oc h w : ℕ} (cot : Tensor3 oc h w) (o : Fin oc) (hi : Fin h) (wi : Fin w) :
        cotWin cot o (finProdFinEquiv (hi, wi)) = cot o hi wi
        theorem Proofs.convWeightGrad_eq_dot {ic oc h w kH kW : ℕ} (x : Tensor3 ic h w) (cot : Tensor3 oc h w) (o : Fin oc) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) :
        ∑ s : Fin (h * w), convPadWin kH kW x cc kh kw s * cotWin cot o s = ∑ hi : Fin h, ∑ wi : Fin w, convPad kH kW x cc kh kw hi wi * cot o hi wi

        The conv weight gradient is the spatial dot Σ_{hi,wi} convPad · cot (the contraction conv2d_weight_pdiv certifies as ∂L/∂W_{o,cc,kh,kw}), re-expressed as a flat Fin (h·w) dot of the padded-input window against the cotangent slab — the form the float dot rounds.

        theorem Proofs.convBiasGrad_eq_sum {oc h w : ℕ} (cot : Tensor3 oc h w) (o : Fin oc) :
        ∑ s : Fin (h * w), cotWin cot o s = ∑ hi : Fin h, ∑ wi : Fin w, cot o hi wi

        The conv bias gradient is the spatial sum Σ_{hi,wi} cot.

        theorem Proofs.FloatModel.cnn_convW_step_float_close {ic oc h w kH kW : ℕ} (M : FloatModel) (W : Kernel4 oc ic kH kW) (x : Tensor3 ic h w) (cot : Tensor3 oc h w) {lr G : ℝ} (o : Fin oc) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) (hG : |∑ s : Fin (h * w), convPadWin kH kW x cc kh kw s * cotWin cot o s| ≤ G) (hlr : 0 ≤ lr) :
        |M.sub (W o cc kh kw) (M.mul lr (M.dot (convPadWin kH kW x cc kh kw) (cotWin cot o))) - (W o cc kh kw - lr * ∑ s : Fin (h * w), convPadWin kH kW x cc kh kw s * cotWin cot o s)| ≤ sgdErr M.u lr |W o cc kh kw| G (((1 + M.u) ^ (h * w + 1) - 1) * ∑ s : Fin (h * w), |convPadWin kH kW x cc kh kw s * cotWin cot o s|)

        Rounded conv weight update. The float update fl(Wₒ,cc,kh,kw − fl(lr·fl(convPadWin · cotWin))) — the conv weight gradient is a correlation, a dot over the h·w spatial positions — is within sgdErr of the real step W − lr·(Σ_{hi,wi} convPad·cot), the dot's Higham γ (fan-in h·w) as the gradient-error slot. Reuses the generic dotSgd_step_close; the cotangent is supplied (the loss-head exp accuracy lives in cotErr).

        theorem Proofs.FloatModel.cnn_convb_step_float_close {oc h w : ℕ} (M : FloatModel) (b : Vec oc) (cot : Tensor3 oc h w) {lr G : ℝ} (o : Fin oc) (hG : |∑ s : Fin (h * w), cotWin cot o s| ≤ G) (hlr : 0 ≤ lr) :
        |M.sub (b o) (M.mul lr (M.sum (cotWin cot o))) - (b o - lr * ∑ s : Fin (h * w), cotWin cot o s)| ≤ sgdErr M.u lr |b o| G (((1 + M.u) ^ (h * w + 1) - 1) * ∑ s : Fin (h * w), |cotWin cot o s|)

        Rounded conv bias update — the bias gradient is the spatial sum Σ cot, so the rounded update reduces to sumSgd_step_close.

        theorem Proofs.FloatModel.mnist_cnn_convW_step_float_budget (M : FloatModel) (hMu : M.u ≤ u32) (W : Kernel4 32 32 3 3) (act cot : Tensor3 32 28 28) {a g : ℝ} (ha : 0 ≤ a) (hg : 0 ≤ g) (hW : ∀ (o cc : Fin 32) (kh kw : Fin 3), |W o cc kh kw| ≤ 3 / 5) (hact : ∀ (c : Fin 32) (i j : Fin 28), |act c i j| ≤ a) (hcot : ∀ (o : Fin 32) (i j : Fin 28), |cot o i j| ≤ g) (o cc : Fin 32) (kh kw : Fin 3) :
        |M.sub (W o cc kh kw) (M.mul (1 / 10) (M.dot (convPadWin 3 3 act cc kh kw) (cotWin cot o))) - (W o cc kh kw - 1 / 10 * ∑ s : Fin (28 * 28), convPadWin 3 3 act cc kh kw s * cotWin cot o s)| ≤ a * g / 250 + 1 / 10000000

        Numeric conv-weight-step capstone at the committed MNIST-CNN dims (Item C). The Chapter-3 conv2 is 32→32, 3×3, at 28×28 (the conv output grid, before maxpool), so the weight gradient is a dot over 28·28 = 784 spatial positions. At binary32 (u ≤ 2⁻²⁴), lr = 1/10, kernel |W| ≤ 3/5 (the trained-magnitude bound, matching the MLP capstone), every rounded conv2 weight SGD entry is within (a·g)/250 + 10⁻⁷ of the certified real step — where a bounds the conv2-input activation and g the conv2 cotangent magnitude.

        Both a and g are a-posteriori / measured quantities (the conv input and back-propagated cotangent are not intrinsically ≤ 1, unlike the softmax−onehot loss head), supplied as hypotheses — the same worst-case→ measured hand-off as the forward δ. The decimal rate 1/250 ≈ 0.4% is dominated by lr·γ₇₈₅ (the gradient's Higham error at learning-rate scale): the conv weight step is as accurate as the gradient itself, no worse.

        theorem Proofs.FloatModel.mnist_cnn_convb_step_float_budget (M : FloatModel) (hMu : M.u ≤ u32) (b : Vec 32) (cot : Tensor3 32 28 28) {g : ℝ} (hg : 0 ≤ g) (hb : ∀ (o : Fin 32), |b o| ≤ 3 / 5) (hcot : ∀ (o : Fin 32) (i j : Fin 28), |cot o i j| ≤ g) (o : Fin 32) :
        |M.sub (b o) (M.mul (1 / 10) (M.sum (cotWin cot o))) - (b o - 1 / 10 * ∑ s : Fin (28 * 28), cotWin cot o s)| ≤ g / 250 + 1 / 10000000

        Numeric conv-BIAS-step capstone at the committed MNIST-CNN dims — the bias peer of mnist_cnn_convW_step_float_budget. The conv2 bias gradient is the spatial SUM ∑ₛ cotWin cot o over the 28·28 = 784 conv-output positions (no input window, so no a factor — the bias Jacobian is the bare channel indicator). At binary32 (u ≤ 2⁻²⁴), lr = 1/10, |b| ≤ 3/5, every rounded conv2 bias SGD entry is within g/250 + 10⁻⁷ of the certified real step — where g bounds the conv2 cotangent magnitude. The same 1/250 rate as the weight step (it is lr·γ₇₈₅, the gradient's Higham error at learning-rate scale), with a·g ↦ g — the bias step is as accurate as the gradient, no worse.

        theorem Proofs.cnn_conv2_loss_differentiableAt {c h w d₃ d₄ nC kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (v : Vec (c * c * kH * kW)) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d (Kernel4.unflatten v) b₂ x₁).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q ≠ 0) :
        DifferentiableAt ℝ (fun (v' : Vec (c * c * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v') b₂ x₁).flatten))))))) label) v

        The loss-of-conv2-kernel map is differentiable wherever the relu₂ pre-activation is off the kinks, no pool window ties (POST-relu), and the two head pre-activations are off the kinks.

        theorem Proofs.gradAt_comp_t3 {P c h w : ℕ} (Z : Vec P → Vec (c * h * w)) (G : Vec (c * h * w) → ℝ) (v : Vec P) (hZ : DifferentiableAt ℝ Z v) (hG : DifferentiableAt ℝ (fun (y : Vec (c * h * w)) (x : Fin 1) => G y) (Z v)) (idx : Fin P) :
        gradAt (fun (v' : Vec P) => G (Z v')) v idx = ∑ ci : Fin c, ∑ hi : Fin h, ∑ wi : Fin w, pdiv Z v idx (t3Idx ci hi wi) * pdiv (fun (y : Vec (c * h * w)) (x : Fin 1) => G y) (Z v) (t3Idx ci hi wi) 0

        The loss gradient through a parameter map into a c×h×w activation — the chain rule (pdiv_comp) with the flat activation index split into its triple: Z's Jacobian row contracted with the head's input gradient. Each conv rung's gradAt closed form is this, the conv Jacobian (conv2d_weight_pdiv / conv2d_bias_pdiv) and the head gradient.

        theorem Proofs.cnn_conv2_loss_gradAt {c h w d₃ d₄ nC kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (v : Vec (c * c * kH * kW)) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d (Kernel4.unflatten v) b₂ x₁).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q ≠ 0) (o cc : Fin c) (kh : Fin kH) (kw : Fin kW) :
        gradAt (fun (v' : Vec (c * c * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v') b₂ x₁).flatten))))))) label) v (k4Idx o cc kh kw) = ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), (if ci = o then convPad kH kW x₁ cc kh kw hi wi else 0) * ((if (conv2d (Kernel4.unflatten v) b₂ x₁).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) ci hi wi then ∑ l : Fin d₃, W₃ (t3Idx ci (winRow hi) (winCol wi)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))))))) k - oneHot nC label k))) else 0)

        Closed form of the conv2 loss gradient at any four-margin point — the chain rule through the conv weight map (gradAt_comp_t3) with the pool-collapsed head gradient (pool_relu_input_grad) and the point-free conv weight Jacobian (conv2d_weight_pdiv). The conv-layer peer of mlp_input_loss_gradAt; the spatial triple sum (vs the MLP's Kronecker collapse) is weight sharing.

        theorem Proofs.dense_transpose_eq {p n : ℕ} (W : Mat p n) (c : Vec n) (l : Fin p) :
        ∑ k : Fin n, W l k * c k = dense (fun (j : Fin n) (i' : Fin p) => W i' j) (fun (x : Fin p) => 0) c l

        The unmasked peer of reluMask_dense_transpose_eq: a bare Wᵀ contraction ∑ₖ Wₗₖ·cₖ = dense (transpose W) 0 c l. The pool feeds dense W₃ with no leading ReLU mask, so the W₃ contraction in the certified conv-2 gradient collapses through this, where the masked W₄/W₅ contractions collapse through reluMask_dense_transpose_eq. NB this is generic in (W, c), so fire it only where the goal has no other matrix contraction (e.g. the spatial ∑ convPad·cot) — see head3_cot_reluMask.

        theorem Proofs.head3_cot_reluMask {p d₃ d₄ nC : ℕ} (W₃ : Mat p d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (u : Vec p) (j : Fin p) :
        ∑ l : Fin d₃, W₃ j l * ((if dense W₃ b₃ u l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ u)) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ u))))) k - oneHot nC label k))) = dense (fun (j' : Fin d₃) (i' : Fin p) => W₃ i' j') (fun (x : Fin p) => 0) (FloatModel.reluMask (dense W₃ b₃ u) (dense (fun (j' : Fin d₄) (i' : Fin d₃) => W₄ i' j') (fun (x : Fin d₃) => 0) (FloatModel.reluMask (dense W₄ b₄ (relu d₃ (dense W₃ b₃ u))) (dense (fun (j' : Fin nC) (i' : Fin d₄) => W₅ i' j') (fun (x : Fin d₄) => 0) fun (k : Fin nC) => softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ u))))) k - oneHot nC label k)))) j

        The 3-dense head cotangent in dense/reluMask form. The raw nested ∑ₗ W₃·(𝟙[z₃]·∑_q W₄·(𝟙[z₄]·∑_k W₅·(softmax−onehot))) that pool_relu_input_grad / cnn_conv2_loss_gradAt leave at the pooled vector u equals dense W₃ᵀ 0 (mask z₃ (dense W₄ᵀ 0 (mask z₄ (dense W₅ᵀ 0 (softmax−onehot))))) — the two masked contractions via reluMask_dense_transpose_eq, the unmasked W₃ via dense_transpose_eq. Stated head-locally (no spatial sum) so the generic dense_transpose_eq fires only on the W₃ row. The head peer the conv grad-close bounds against via dense_close (W₃) and cot_step_close (W₄/W₅).

        theorem Proofs.cnn_conv2_loss_gradAt_reluMask {c h w d₃ d₄ nC kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (v : Vec (c * c * kH * kW)) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d (Kernel4.unflatten v) b₂ x₁).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q ≠ 0) (o cc : Fin c) (kh : Fin kH) (kw : Fin kW) :
        gradAt (fun (v' : Vec (c * c * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v') b₂ x₁).flatten))))))) label) v (k4Idx o cc kh kw) = ∑ s : Fin (2 * h * (2 * w)), convPadWin kH kW x₁ cc kh kw s * cotWin (fun (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) => (if (conv2d (Kernel4.unflatten v) b₂ x₁).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) ci hi wi then dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (FloatModel.reluMask (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))) (dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (FloatModel.reluMask (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))))) (dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) fun (k : Fin nC) => softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))))))) k - oneHot nC label k)))) (t3Idx ci (winRow hi) (winCol wi)) else 0) o s

        The certified conv-2 loss gradient, head restated in dense/reluMask form — the conv peer of mlp_input_loss_gradAt_reluMask. The two head Wᵀ contractions (under the d₄/d₃ ReLU masks) collapse via reluMask_dense_transpose_eq, the unmasked W₃ contraction via dense_transpose_eq; the conv-output ReLU mask 𝟙[z₂>0] and the pool argmax selector are kept explicit (their float closeness is handled by reluMask_close and MaxPool2MarginQ.poolBack_close). The whole conv gradient is then packaged as the spatial dot ∑ₛ convPadWin·cotWin (convWeightGrad_eq_dot) — the exact quantity the FloatModel gradient's conv-weight dot rounds, so the conv grad-close bounds against this.

        theorem Proofs.mask_scalar_close {zt z xt x ez ex : ℝ} (hz : |zt - z| ≤ ez) (hm : ez < |z|) (hx : |xt - x| ≤ ex) (_hex : 0 ≤ ex) :
        |(if zt > 0 then 1 else 0) * xt - (if z > 0 then 1 else 0) * x| ≤ ex

        Scalar ReLU-mask freeze — the (if z>0 then 1 else 0)·x peer of reluMask_close. Under the sign margin ez < |z| the float and real masks agree, so the masked value is 1-Lipschitz in x. The conv-output ReLU mask 𝟙[z₂>0] in the conv-2 grad-close sits on a scalar cell (not a Vec), so it needs this rather than the vector reluMask_close.

        theorem Proofs.FloatModel.dot_perturbed_close {n : ℕ} (M : FloatModel) (A Bt B : Vec n) {a Ct eB : ℝ} (ha : 0 ≤ a) (hA : ∀ (i : Fin n), |A i| ≤ a) (hBt : ∀ (i : Fin n), |Bt i| ≤ Ct) (hB : ∀ (i : Fin n), |Bt i - B i| ≤ eB) :
        |M.dot A Bt - ∑ i : Fin n, A i * B i| ≤ ((1 + M.u) ^ (n + 1) - 1) * (↑n * (a * Ct)) + ↑n * (a * eB)

        Float dot against a perturbed cotangent — the conv-2 grad-close's final contraction (the conv peer of the MLP's scalar mul_close: a dot, because of weight sharing). M.dot A B̃ (exact left operand A, float cotangent B̃) vs the certified ∑ Aᵢ·Bᵢ splits into the Higham dot rounding on A·B̃ (dot_close, fan-in n) plus the per-entry cotangent drift |B̃ᵢ − Bᵢ| ≤ eB. With |Aᵢ| ≤ a and |B̃ᵢ| ≤ Ct, the bound is closed-form and norm_num-evaluable.

        noncomputable def Proofs.FloatModel.cnnConv2FloatGrad {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (fexp : ℝ → ℝ) (label : Fin nC) (v : Vec (c * c * kH * kW)) :
        Vec (c * c * kH * kW)

        The binary32 conv-2 weight gradient (FloatModel transcription of the per-example gradient) — the conv peer of mlpInputFloatGrad. At kernel entry (o,cc,kh,kw) it is the float dot of the (exact) padded-input window convPadWin against the float conv-output cotangent slab cotWin c̃Conv o, where the float cotangent c̃Conv rounds every step of the backward — conv-output ReLU mask 𝟙[z̃₂>0], pool argmax selector (read on the FLOAT post-relu), and the head W₃ᵀ·mask(z̃₃)·W₄ᵀ·mask(z̃₄)·W₅ᵀ·(float softmax−onehot) at the float pre-activations. The M-free reluMask/maxPoolFlat/relu are exact in float; M.convF/M.dense/M.softmaxCECotF carry the rounding.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          @[simp]
          theorem Proofs.FloatModel.cnnConv2FloatGrad_apply {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (fexp : ℝ → ℝ) (label : Fin nC) (v : Vec (c * c * kH * kW)) (o cc : Fin c) (kh : Fin kH) (kw : Fin kW) :
          M.cnnConv2FloatGrad b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ fexp label v (k4Idx o cc kh kw) = M.dot (convPadWin kH kW x₁ cc kh kw) (cotWin (fun (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) => (if (M.convF (Kernel4.unflatten v) b₂ x₁).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten v) b₂ x₁).flatten)) ci hi wi then M.dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (reluMask (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten v) b₂ x₁).flatten))) (M.dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (reluMask (M.dense W₄ b₄ (relu d₃ (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten v) b₂ x₁).flatten))))) (M.dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) (M.softmaxCECotF fexp (M.dense W₅ b₅ (relu d₄ (M.dense W₄ b₄ (relu d₃ (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten v) b₂ x₁).flatten))))))) label))))) (t3Idx ci (winRow hi) (winCol wi)) else 0) o)
          noncomputable def Proofs.FloatModel.cnnConv2GradBudget (M : FloatModel) (c h w d₃ d₄ nC kH kW : ℕ) (a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ) :

          The conv-2 float-backward grad-close budget — the closed-form η the rounded W₂ gradient stays within of the certified one. Bottom-up: the forward rounding nest (Econv → E₃ → E₄ → δlogit, conv at fan-in c·kH·kW, the dense head at c·h·w / d₃) feeds the head cotErr; the backward then rides two cot_step layerBudgets (W₅/W₄) and the unmasked W₃ layerBudget to econv; finally the spatial dot (fan-in (2h)·(2w)) contributes its Higham γ on the float-cotangent magnitude Ctilde plus the per-entry cotangent drift econv. The conv peer of the MLP's mulErr/layerBudget/cotErr nest, deeper by the pool + the dot.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            noncomputable def Proofs.FloatModel.cnnConv2CotBudget (M : FloatModel) (c h w d₃ d₄ nC kH kW : ℕ) (aX2 eX2 w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ) :

            The conv-2-output cotangent error budget, as a function of the conv-2 input magnitude aX2 and rounding eX2 — the e₂ of cnnConv2GradBudget (where aX2 = a, eX2 = 0) and the e₂ inside cnnConv1GradBudget (where aX2 = A₁, eX2 = E₁). Factored so the conv-1 rung reuses the conv-2 cotangent chain at a FLOAT conv-2 input.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              noncomputable def Proofs.FloatModel.cnnConv2CotMag (d₃ d₄ nC : ℕ) (w₃ w₄ w₅ : ℝ) :

              The real conv-2-output cotangent magnitude bound — aX2/eX2-independent (the head cotangent and the two masked Wᵀ steps are magnitude-frozen).

              Equations
              Instances For
                theorem Proofs.FloatModel.cnnConv2CotMag_nonneg {d₃ d₄ nC : ℕ} {w₃ w₄ w₅ : ℝ} (hw₃ : 0 ≤ w₃) (hw₄ : 0 ≤ w₄) (hw₅ : 0 ≤ w₅) :
                0 ≤ cnnConv2CotMag d₃ d₄ nC w₃ w₄ w₅

                cnnConv2CotMag is nonnegative.

                theorem Proofs.FloatModel.cnnConv2CotBudget_nonneg (M : FloatModel) {c h w d₃ d₄ nC kH kW : ℕ} {aX2 eX2 w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (haX2 : 0 ≤ aX2) (heX2 : 0 ≤ eX2) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (heexp0 : 0 ≤ eexp) (hρ1 : smRho M.u eexp nC < 1) :
                0 ≤ M.cnnConv2CotBudget c h w d₃ d₄ nC kH kW aX2 eX2 w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp

                cnnConv2CotBudget is nonnegative for nonnegative input magnitude/rounding and layer bounds.

                theorem Proofs.cnn_conv2_cot_close {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (X2 X2F : Tensor3 c (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) {aX2 eX2 w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (haX2 : 0 ≤ aX2) (heX2 : 0 ≤ eX2) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hX2 : ∀ (co : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |X2F co i j - X2 co i j| ≤ eX2) (hX2mag : ∀ (co : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |X2 co i j| ≤ aX2) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmarginConv : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ aX2 eX2 < |(conv2d W₂ b₂ X2).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ aX2 eX2) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ aX2) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ aX2 eX2) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ aX2)) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ aX2) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ aX2 eX2)) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten)))) q|) (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)) :
                |((if (M.convF W₂ b₂ X2F).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ X2F).flatten)) co ho wo then M.dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (FloatModel.reluMask (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ X2F).flatten))) (M.dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (FloatModel.reluMask (M.dense W₄ b₄ (relu d₃ (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ X2F).flatten))))) (M.dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) (M.softmaxCECotF fexp (M.dense W₅ b₅ (relu d₄ (M.dense W₄ b₄ (relu d₃ (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ X2F).flatten))))))) label))))) (t3Idx co (winRow ho) (winCol wo)) else 0) - (if (conv2d W₂ b₂ X2).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten)) co ho wo then dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (FloatModel.reluMask (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten))) (dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (FloatModel.reluMask (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten))))) (dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) fun (k : Fin nC) => softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten))))))) k - oneHot nC label k)))) (t3Idx co (winRow ho) (winCol wo)) else 0| ≤ M.cnnConv2CotBudget c h w d₃ d₄ nC kH kW aX2 eX2 w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp

                The conv-2-output cotangent is float-close at a float conv-2 input — the conv-2 cotangent chain of cnn_conv2_grad_close, factored to take the conv-2 input (X2, X2F) with |X2F − X2| ≤ eX2, |X2| ≤ aX2. The conv-2 rungs instantiate the exact input X2 = X2F = x₁, eX2 = 0; the conv-1 rung X2 = relu(z₁), X2F = relu(z̃₁), eX2 = E₁. The chain: float forward from X2 (convF_close → dense_close×3) → head (softmax_ce_cot_close) → cot_step_close×2 → unmasked W₃ dense_close → pool-back (poolBack_close) → conv-2 ReLU mask (mask_scalar_close).

                theorem Proofs.cnn_conv2_cot_real_abs_le {c h w d₃ d₄ nC kH kW : ℕ} (X2 : Tensor3 c (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) {w₃ w₄ w₅ : ℝ} (hw₃ : 0 ≤ w₃) (hw₄ : 0 ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)) :
                |(if (conv2d W₂ b₂ X2).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten)) co ho wo then dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (FloatModel.reluMask (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten))) (dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (FloatModel.reluMask (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten))))) (dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) fun (k : Fin nC) => softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ X2).flatten))))))) k - oneHot nC label k)))) (t3Idx co (winRow ho) (winCol wo)) else 0| ≤ FloatModel.cnnConv2CotMag d₃ d₄ nC w₃ w₄ w₅

                The real conv-2-output cotangent is magnitude-bounded by cnnConv2CotMag — the aX2/eX2-independent ℓ∞ bound (the conv-2 ReLU mask and pool selector only shrink, the head cotangent is in [−1,1], the two masked Wᵀ steps and the unmasked W₃ ride layerAct). Used to bound the real conv-1 cotangent ∑ convTap·c₂ in the conv-1 rung.

                theorem Proofs.abs_le_of_close {a b e C : ℝ} (h1 : |a - b| ≤ e) (h2 : |b| ≤ C) :
                |a| ≤ C + e

                |a| ≤ C + e from |a − b| ≤ e and |b| ≤ C — lifts a closeness + a base magnitude to a float magnitude (the float cotangent bound from the real bound plus the drift).

                theorem Proofs.cnn_conv2_grad_close {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) (v : Vec (c * c * kH * kW)) {a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx₁ : ∀ (ci : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ ci i j| ≤ a) (hv2 : ∀ (idx : Fin (c * c * kH * kW)), |v idx| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmarginConv : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0 < |(conv2d (Kernel4.unflatten v) b₂ x₁).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a)) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0)) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q|) (o cc : Fin c) (kh : Fin kH) (kw : Fin kW) :
                |M.cnnConv2FloatGrad b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ fexp label v (k4Idx o cc kh kw) - gradAt (fun (v' : Vec (c * c * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v') b₂ x₁).flatten))))))) label) v (k4Idx o cc kh kw)| ≤ M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp

                The binary32 conv-2 weight gradient is within an explicit budget of the certified one — the conv-layer peer of mlp_w0_grad_close. With the conv-2 input x₁ exact, the FloatModel W₂ gradient M.cnnConv2FloatGrad … stays within cnnConv2GradBudget of the certified gradAt. The chain: float forward (convF_close → dense_close×3, relu and pool error-transparent) ⟶ head (softmax_ce_cot_close) ⟶ two masked Wᵀ cot_step_close (W₅ under z̃₄, W₄ under z̃₃) ⟶ unmasked W₃ dense_close ⟶ pool-backward freeze (poolBack_close) ⟶ conv-output ReLU mask freeze (mask_scalar_close) ⟶ the spatial dot (dot_perturbed_close). Four quantitative margins are carried (conv-output Econv, pool Econv POST-relu, z̃₃ E₃, z̃₄ E₄); the bridge cnn_conv2_loss_gradAt_reluMask turns the gradAt into the dot the float gradient rounds. Everything up to the dot is cnn_conv2_cot_close at the exact conv-2 input.

                theorem Proofs.conv2d_flat_kernel_drift_total {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) {a : ℝ} (ha : 0 ≤ a) (hx : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x c i j| ≤ a) (v e : Vec (oc * ic * kH * kW)) (k : Fin (oc * h * w)) :
                |(conv2d (Kernel4.unflatten (v + e)) b x).flatten k - (conv2d (Kernel4.unflatten v) b x).flatten k| ≤ a * ∑ idx : Fin (oc * ic * kH * kW), |e idx|

                Per-entry conv drift, flat-index form of conv2d_kernel_drift_total.

                theorem Proofs.conv2d_flat_kernel_drift_sum {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) {a : ℝ} (ha : 0 ≤ a) (hx : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x c i j| ≤ a) (v e : Vec (oc * ic * kH * kW)) :
                ∑ k : Fin (oc * h * w), |(conv2d (Kernel4.unflatten (v + e)) b x).flatten k - (conv2d (Kernel4.unflatten v) b x).flatten k| ≤ ↑(h * w) * (a * ∑ idx : Fin (oc * ic * kH * kW), |e idx|)

                ℓ1 conv drift, flat-index form of conv2d_kernel_drift_sum.

                theorem Proofs.convPad_row_l1 {ic oc h w kH kW : ℕ} (x : Tensor3 ic h w) {a : ℝ} (ha : 0 ≤ a) (hx : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x c i j| ≤ a) (o : Fin oc) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) :
                ∑ ci : Fin oc, ∑ hi : Fin h, ∑ wi : Fin w, |if ci = o then convPad kH kW x cc kh kw hi wi else 0| ≤ ↑(h * w) * a

                Row mass of the conv kernel Jacobian: kernel tap (o,cc,kh,kw) reads output channel o only, through one bounded input read per output position.

                theorem Proofs.biasRow_l1 {oc h w : ℕ} (o : Fin oc) :
                ∑ ci : Fin oc, ∑ _hi : Fin h, ∑ _wi : Fin w, |if ci = o then 1 else 0| ≤ ↑(h * w) * 1

                Row mass of the conv bias Jacobian: bias entry o feeds output channel o at every position.

                theorem Proofs.Conv2Slot.pool_l1_drift {P c h w : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) {ρ : ℝ} (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (v e : Vec P) :
                ∑ q : Fin (c * h * w), |maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + e))) q - maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v)) q| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)

                Pooled ℓ1 drift: the conv2 output moves by (2h)·(2w)·ρ·‖e‖₁ in ℓ1 (hZ1); relu and the pool are ℓ1 contractions.

                theorem Proofs.Conv2Slot.postrelu_close {P c h w : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) {ρ : ℝ} (hZ : ∀ (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))), |Z (v + e) k - Z v k| ≤ ρ * ∑ idx : Fin P, |e idx|) (v e : Vec P) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                |Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + e))) ci hi wi - Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)) ci hi wi| ≤ ρ * ∑ idx : Fin P, |e idx|

                Per-entry POST-relu tensor drift — the form the pool margin (MaxPool2MarginQ) consumes.

                theorem Proofs.Conv2Slot.z3_drift {P c h w d₃ : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) {ρ w₃ : ℝ} (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (v e : Vec P) (l : Fin d₃) :
                |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + e)))) l - dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))) l| ≤ w₃ * (↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|))

                Per-entry drift of the relu₃ pre-activation.

                theorem Proofs.Conv2Slot.z4_drift {P c h w d₃ d₄ : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) {ρ w₃ w₄ : ℝ} (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (v e : Vec P) (q : Fin d₄) :
                |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + e)))))) q - dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))))) q| ≤ w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|))))

                Per-entry drift of the relu₄ pre-activation.

                theorem Proofs.Conv2Slot.logit_drift {P c h w d₃ d₄ nC : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) {ρ w₃ w₄ w₅ : ℝ} (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (v e : Vec P) (k : Fin nC) :
                |dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + e)))))))) k - dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))))))) k| ≤ w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|))))))

                Logit drift through the whole conv2 chain: parameter perturbation → conv2 output → relu → pool → d₃ → relu → d₄ → relu → d₅. Each dense crossing contributes its ℓ1→ℓ1 operator factor dᵢ·wᵢ; the conv output contributes the weight-sharing multiplicity (2h)·(2w).

                theorem Proofs.Conv2Slot.postrelu_close_seg {P c h w : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) {ρ D : ℝ} (hρ : 0 ≤ ρ) (hZ : ∀ (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))), |Z (v + e) k - Z v k| ≤ ρ * ∑ idx : Fin P, |e idx|) (v e : Vec P) (he : ∑ idx : Fin P, |e idx| ≤ D) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                |Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))) ci hi wi - Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)) ci hi wi| ≤ ρ * D

                The POST-relu tensor stays within the pool margin radius ρ·D along the whole step segment — what MaxPool2MarginQ.{smooth_of_close, isArgmax_iff} consume.

                theorem Proofs.Conv2Slot.margin3_keeps_offkink {P c h w d₃ : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) {ρ w₃ D : ℝ} (hρ : 0 ≤ ρ) (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (v e : Vec P) (he : ∑ idx : Fin P, |e idx| ≤ D) (hm : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * (ρ * D)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))) l|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (l : Fin d₃) :
                dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + t • e)))) l ≠ 0 ∧ (0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + t • e)))) l ↔ 0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))) l)

                The relu₃ margin keeps the first head pre-activation off the kink, same sign, along the whole step segment.

                theorem Proofs.Conv2Slot.margin4_keeps_offkink {P c h w d₃ d₄ : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) {ρ w₃ w₄ D : ℝ} (hρ : 0 ≤ ρ) (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (v e : Vec P) (he : ∑ idx : Fin P, |e idx| ≤ D) (hm : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (ρ * D)))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))))) q|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (q : Fin d₄) :
                dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + t • e)))))) q ≠ 0 ∧ (0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z (v + t • e)))))) q ↔ 0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))))) q)

                The relu₄ margin keeps the second head pre-activation off the kink, same sign, along the whole step segment.

                theorem Proofs.cnn_margin2_keeps_offkink {c h w kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) {a D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (v e : Vec (c * c * kH * kW)) (he : ∑ idx : Fin (c * c * kH * kW), |e idx| ≤ D) (hm : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * D < |(conv2d (Kernel4.unflatten v) b₂ x₁).flatten k|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (k : Fin (c * (2 * h) * (2 * w))) :
                (conv2d (Kernel4.unflatten (v + t • e)) b₂ x₁).flatten k ≠ 0 ∧ (0 < (conv2d (Kernel4.unflatten (v + t • e)) b₂ x₁).flatten k ↔ 0 < (conv2d (Kernel4.unflatten v) b₂ x₁).flatten k)

                The relu₂ margin keeps the conv pre-activation off the kink, same sign, along the whole step segment.

                theorem Proofs.cnn_postrelu_close_seg {c h w kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) {a D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (v e : Vec (c * c * kH * kW)) (he : ∑ idx : Fin (c * c * kH * kW), |e idx| ≤ D) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                |Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (v + t • e)) b₂ x₁).flatten) ci hi wi - Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten) ci hi wi| ≤ a * D

                The POST-relu tensor stays within the pool margin radius a·D along the whole step segment — what MaxPool2MarginQ.{smooth_of_close, isArgmax_iff} consume.

                theorem Proofs.cnn_margin3_keeps_offkink {c h w d₃ kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) {a w₃ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (v e : Vec (c * c * kH * kW)) (he : ∑ idx : Fin (c * c * kH * kW), |e idx| ≤ D) (hm : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * (a * D)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (l : Fin d₃) :
                dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (v + t • e)) b₂ x₁).flatten)) l ≠ 0 ∧ (0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (v + t • e)) b₂ x₁).flatten)) l ↔ 0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l)

                The relu₃ margin keeps the first head pre-activation off the kink, same sign, along the whole step segment.

                theorem Proofs.cnn_margin4_keeps_offkink {c h w d₃ d₄ kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) {a w₃ w₄ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (v e : Vec (c * c * kH * kW)) (he : ∑ idx : Fin (c * c * kH * kW), |e idx| ≤ D) (hm : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * D)))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (q : Fin d₄) :
                dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (v + t • e)) b₂ x₁).flatten)))) q ≠ 0 ∧ (0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (v + t • e)) b₂ x₁).flatten)))) q ↔ 0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q)

                The relu₄ margin keeps the second head pre-activation off the kink, same sign, along the whole step segment.

                theorem Proofs.head3_sum_drift {p d₃ d₄ nC : ℕ} (W₃ : Mat p d₃) (W₄ : Mat d₃ d₄) (W₅ : Mat d₄ nC) {w₃ w₄ w₅ Δ : ℝ} (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin p) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (m₃ : Fin d₃ → ℝ) (hm₃ : ∀ (l : Fin d₃), |m₃ l| ≤ 1) (m₄ : Fin d₄ → ℝ) (hm₄ : ∀ (r : Fin d₄), |m₄ r| ≤ 1) (s s' oh : Vec nC) (hs : ∀ (k : Fin nC), |s' k - s k| ≤ Δ) (q : Fin p) :
                |∑ l : Fin d₃, W₃ q l * (m₃ l * ∑ r : Fin d₄, W₄ l r * (m₄ r * ∑ k : Fin nC, W₅ r k * (s' k - oh k))) - ∑ l : Fin d₃, W₃ q l * (m₃ l * ∑ r : Fin d₄, W₄ l r * (m₄ r * ∑ k : Fin nC, W₅ r k * (s k - oh k)))| ≤ ↑d₃ * (w₃ * (↑d₄ * (w₄ * (↑nC * (w₅ * Δ)))))

                Frozen-mask head-gradient drift: with the two head masks frozen (0/1-valued, shared between the two points) and the softmax drifting by at most Δ, the head3 gradient closed form drifts by at most d₃·w₃·d₄·w₄·nC·w₅·Δ — the oneHot cancels in the difference.

                theorem Proofs.Conv2Slot.loss_grad_lipschitz {P c h w d₃ d₄ nC : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) {ρ w₃ w₄ w₅ D : ℝ} (hρ : 0 ≤ ρ) (hZ : ∀ (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))), |Z (v + e) k - Z v k| ≤ ρ * ∑ idx : Fin P, |e idx|) (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (J : Fin c → Fin (2 * h) → Fin (2 * w) → ℝ) (hJ : ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), |J ci hi wi| ≤ ↑(2 * h * (2 * w)) * ρ) (idx : Fin P) (Q : Vec P → Prop) (hgrad : ∀ (v' : Vec P), Q v' → (∀ (k : Fin (c * (2 * h) * (2 * w))), Z v' k ≠ 0) → MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v'))) → (∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v'))) l ≠ 0) → (∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v'))))) q ≠ 0) → gradAt (fun (v'' : Vec P) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v'')))))))) label) v' idx = ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), J ci hi wi * ((if Z v' (t3Idx ci hi wi) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v'))) ci hi wi then ∑ l : Fin d₃, W₃ (t3Idx ci (winRow hi) (winCol wi)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v'))) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v'))))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v')))))))) k - oneHot nC label k))) else 0)) (v d : Vec P) (hd : ∑ idx : Fin P, |d idx| ≤ D) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ρ * D < |Z v k|) (hmq : MaxPool2MarginQ (ρ * D) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * (ρ * D)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (ρ * D)))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v))))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (ρ * D))))))) < 1) (t : ℝ) (ht : t ∈ Set.Icc 0 1) (hQv : Q v) (hQt : Q (v + t • d)) :
                |gradAt (fun (v' : Vec P) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v')))))))) label) (v + t • d) idx - gradAt (fun (v' : Vec P) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (Z v')))))))) label) v idx| ≤ 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * ρ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (ρ * D)))))))) * (t * D)

                Segment-Lipschitz gradient for a conv2-slot loss, explicit constant. For a parameter map Z into conv2's pre-activation with per-entry drift ρ·‖e‖₁ (hZ) and ℓ1 drift (2h)·(2w)·ρ·‖e‖₁ (hZ1), whose loss gradient at every off-kink point is a fixed Jacobian row J (row mass ≤ (2h)·(2w)·ρ, hJ) contracted with the head's pre-activation gradient (hgrad): under the four margins at radius ρ·D every routing decision freezes along [v, v+d], the Jacobian factors out, and the difference collapses to the softmax drift. hgrad is needed only where Q holds, and Q only at the two ends of the segment (hQv, hQt). The conv2-kernel rung is the instance ρ = a, the conv2-bias rung ρ = 1, both at Q := True; the conv1 slot takes Q = relu₁'s signs frozen.

                theorem Proofs.cnn_conv2_loss_grad_lipschitz {c h w d₃ d₄ nC kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) {a w₃ w₄ w₅ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (v d : Vec (c * c * kH * kW)) (hd : ∑ idx : Fin (c * c * kH * kW), |d idx| ≤ D) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * D < |(conv2d (Kernel4.unflatten v) b₂ x₁).flatten k|) (hmq : MaxPool2MarginQ (a * D) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * (a * D)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * D)))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v) b₂ x₁).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * D))))))) < 1) (t : ℝ) (ht : t ∈ Set.Icc 0 1) (idx : Fin (c * c * kH * kW)) :
                |gradAt (fun (v' : Vec (c * c * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v') b₂ x₁).flatten))))))) label) (v + t • d) idx - gradAt (fun (v' : Vec (c * c * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten v') b₂ x₁).flatten))))))) label) v idx| ≤ 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * a ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * D)))))))) * (t * D)

                Segment-Lipschitz gradient for the conv2-kernel loss, explicit constant. Under the four margins at step radius D — relu₂ (a·D), pool selection (MaxPool2MarginQ (a·D) of the POST-relu tensor), relu₃ (w₃·4hw·a·D), relu₄ (w₄·d₃·w₃·4hw·a·D) — every routing decision (masks AND pool argmaxes) freezes along [v, v+d], the point-free conv Jacobian factors out, and the difference collapses to the softmax drift exactly as in mlp_input_loss_grad_lipschitz. The conv-layer peer of that theorem; the constant picks up the weight-sharing multiplicity ((2h)·(2w))². Conv2Slot.loss_grad_lipschitz at ρ = a.

                noncomputable def Proofs.cnnConv2KernelLoss {c h w d₃ d₄ nC kH kW : ℕ} (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) :
                Vec (c * c * kH * kW) → ℝ

                The loss as a function of the flattened second-conv kernel.

                Equations
                • One or more equations did not get rendered due to their size.
                Instances For
                  theorem Proofs.cnn_conv2_sgd_descends {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (gh : Vec (c * c * kH * kW)) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) {lr η a w₃ w₄ w₅ : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hlr : 0 ≤ lr) (hη : 0 ≤ η) (hgh : ∀ (idx : Fin (c * c * kH * kW)), |gh idx - gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx| ≤ η) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr η < |(conv2d W₂ b₂ x₁).flatten k|) (hmq : MaxPool2MarginQ (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr η) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr η)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr η)))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr η))))))) < 1) (h1 : lr * η * ∑ idx : Fin (c * c * kH * kW), |gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx| ≤ (lr * ∑ idx : Fin (c * c * kH * kW), gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * a ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr η)))))))) * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr η ^ 2 ≤ (lr * ∑ idx : Fin (c * c * kH * kW), gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx ^ 2) / 4) :
                  cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label (W₂.flatten - lr • gh) ≤ cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label W₂.flatten - (lr * ∑ idx : Fin (c * c * kH * kW), gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx ^ 2) / 2

                  One inexact SGD step on the CNN's second conv kernel decreases one example's cross-entropy loss (example (x₁, label) at the frozen conv-2 input, W₂ moving, every other parameter fixed). sgd_descends' smoothness hypotheses are discharged for the loss-of-conv2-kernel map: differentiability along the segment and the segment-Lipschitz constant both come from the FOUR margin hypotheses at the step radius D = lr·(‖∇L‖₁ + |kernel|·η) — relu₂, the pool-selection margin (POST-relu), relu₃, relu₄ — which freeze every mask and the pool's entire routing pattern along the step. Remaining hypotheses: the oracle accuracy η, the margins, the small-step condition, and the two dominance conditions. Conclusion: the loss drops by ≥ lr·‖∇L‖₂²/2. The conv-layer peer of mlp_input_sgd_descends; the descent program now reaches through weight sharing and max-pooling.

                  theorem Proofs.cnn_conv2_float_sgd_descends {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) {lr a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (hlr : 0 ≤ lr) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmarginConv : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0 < |(conv2d W₂ b₂ x₁).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a)) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0)) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)))) q|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr (M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) < |(conv2d W₂ b₂ x₁).flatten k|) (hmq : MaxPool2MarginQ (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr (M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr (M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr (M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr (M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)))))))) < 1) (h1 : lr * M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp * ∑ idx : Fin (c * c * kH * kW), |gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx| ≤ (lr * ∑ idx : Fin (c * c * kH * kW), gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * a ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr (M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))))))) * stepRadius (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten lr (M.cnnConv2GradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) ^ 2 ≤ (lr * ∑ idx : Fin (c * c * kH * kW), gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx ^ 2) / 4) :
                  cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label (W₂.flatten - lr • M.cnnConv2FloatGrad b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ fexp label W₂.flatten) ≤ cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label W₂.flatten - (lr * ∑ idx : Fin (c * c * kH * kW), gradAt (cnnConv2KernelLoss b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) W₂.flatten idx ^ 2) / 2

                  One SGD step with the FloatModel binary32 conv-2 kernel gradient decreases one example's cross-entropy loss; the gradient's accuracy is proven, not assumed. The conv peer of mlp_input_float_sgd_descends: the gradient is the FloatModel binary32 W₂ gradient M.cnnConv2FloatGrad …, and its accuracy is proven by cnn_conv2_grad_close (η := cnnConv2GradBudget, discharged per kernel entry via k4Idx_surj), not assumed. The two rounding-margin families are carried as hypotheses: the per-layer ROUND margins (hmarginConv/Pool/3/4, feeding the grad-close) and the gradient-radius STEP margins + hsmall/h1/h2 (feeding cnn_conv2_sgd_descends's drift-freeze and the descent geometry). The conv-2 input x₁ is exact.

                  Scope: one example, W₂ moving with every other parameter fixed, and the update taken in ℝ — only the gradient is float-modelled.

                  theorem Proofs.sum_swap_12_3 {α : Type u_1} {β : Type u_2} {γ : Type u_3} [Fintype α] [Fintype β] [Fintype γ] (f : α → β → γ → ℝ) :
                  ∑ a : α, ∑ b : β, ∑ c : γ, f a b c = ∑ c : γ, ∑ a : α, ∑ b : β, f a b c

                  Rotate the innermost summation index of a triple sum to the front.

                  theorem Proofs.sum_swap_pair_pair {α : Type u_1} {β : Type u_2} {γ : Type u_3} {δ : Type u_4} [Fintype α] [Fintype β] [Fintype γ] [Fintype δ] (f : α → β → γ → δ → ℝ) :
                  ∑ a : α, ∑ b : β, ∑ c : γ, ∑ d : δ, f a b c d = ∑ c : γ, ∑ d : δ, ∑ a : α, ∑ b : β, f a b c d

                  Swap the two index pairs of a quadruple sum.

                  theorem Proofs.sum_swap_triple_triple {α : Type u_1} {β : Type u_2} {γ : Type u_3} {δ : Type u_4} {ε : Type u_5} {ζ : Type u_6} [Fintype α] [Fintype β] [Fintype γ] [Fintype δ] [Fintype ε] [Fintype ζ] (f : α → β → γ → δ → ε → ζ → ℝ) :
                  ∑ a : α, ∑ b : β, ∑ c : γ, ∑ d : δ, ∑ e : ε, ∑ g : ζ, f a b c d e g = ∑ d : δ, ∑ e : ε, ∑ g : ζ, ∑ a : α, ∑ b : β, ∑ c : γ, f a b c d e g

                  Swap the two index triples of a six-fold sum.

                  noncomputable def Proofs.convTap {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (ci : Fin ic) (hi : Fin h) (wi : Fin w) (co : Fin oc) (ho : Fin h) (wo : Fin w) :

                  The kernel tap that multiplies input entry (ci,hi,wi) in output entry (co,ho,wo) — the input-side Jacobian entry of conv2d. Depends on the kernel only, never the input (conv is linear in its input). Deliberately let-free, like convPad.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    theorem Proofs.convTap_abs_le {ic oc h w kH kW : ℕ} {W : Kernel4 oc ic kH kW} {w' : ℝ} (hw' : 0 ≤ w') (hW : ∀ (o : Fin oc) (c : Fin ic) (kh : Fin kH) (kw : Fin kW), |W o c kh kw| ≤ w') (ci : Fin ic) (hi : Fin h) (wi : Fin w) (co : Fin oc) (ho : Fin h) (wo : Fin w) :
                    |convTap W ci hi wi co ho wo| ≤ w'

                    A single conv tap is bounded by the kernel magnitude (out-of-pad taps are zero) — the per-entry bound the conv-2 backward dot_perturbed_close uses.

                    theorem Proofs.abs_convTap_expand {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (ci : Fin ic) (hi : Fin h) (wi : Fin w) (co : Fin oc) (ho : Fin h) (wo : Fin w) :
                    |convTap W ci hi wi co ho wo| = ∑ kh : Fin kH, ∑ kw : Fin kW, if ↑kh + ↑ho = ↑hi + (kH - 1) / 2 ∧ ↑kw + ↑wo = ↑wi + (kW - 1) / 2 then |W co ci kh kw| else 0

                    The tap as a kernel-offset indicator sum: |convTap| is the sum over kernel offsets (kh,kw) of |W co ci kh kw| pinned to the unique offset aligning input (hi,wi) with output (ho,wo). The workhorse for both mass bounds: summing it over OUTPUTS pins (ho,wo) per offset, summing it over INPUTS pins (hi,wi).

                    theorem Proofs.convTap_out_l1 {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) {wK : ℝ} (hW : ∀ (o : Fin oc) (c : Fin ic) (kh : Fin kH) (kw : Fin kW), |W o c kh kw| ≤ wK) (ci : Fin ic) (hi : Fin h) (wi : Fin w) :
                    ∑ co : Fin oc, ∑ ho : Fin h, ∑ wo : Fin w, |convTap W ci hi wi co ho wo| ≤ ↑(oc * kH * kW) * wK

                    Output-side tap mass: one input entry feeds at most oc·kH·kW outputs, each through a tap bounded by wK — the ℓ1→ℓ1 operator factor of a conv crossing as a function of its input.

                    theorem Proofs.conv2d_input_pdiv3 {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (b : Vec oc) (x : Tensor3 ic h w) (ci : Fin ic) (hi : Fin h) (wi : Fin w) (co : Fin oc) (ho : Fin h) (wo : Fin w) :
                    pdiv3 (conv2d W b) x ci hi wi co ho wo = convTap W ci hi wi co ho wo

                    Closed form of the conv input-map pdiv3 — extracted from the certified input-VJP (conv2dHasVJP3) by contracting its .correct field against a basis cotangent. Point-free in x: conv is linear in its input.

                    theorem Proofs.conv2d_flat_input_pdiv {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (b : Vec oc) (y : Vec (ic * h * w)) (ci : Fin ic) (hi : Fin h) (wi : Fin w) (co : Fin oc) (ho : Fin h) (wo : Fin w) :
                    pdiv (fun (u : Vec (ic * h * w)) => (conv2d W b (Tensor3.unflatten u)).flatten) y (t3Idx ci hi wi) (t3Idx co ho wo) = convTap W ci hi wi co ho wo

                    Flat-coordinate form of conv2d_input_pdiv3 — the shape the chain rule through flatConv W₂ b₂ consumes.

                    theorem Proofs.abs_convPad_sub_le {ic h w kH kW : ℕ} (x x' : Tensor3 ic h w) {δ : ℝ} (hδ : 0 ≤ δ) (hclose : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x' c i j - x c i j| ≤ δ) (c : Fin ic) (kh : Fin kH) (kw : Fin kW) (hi : Fin h) (wi : Fin w) :
                    |convPad kH kW x' c kh kw hi wi - convPad kH kW x c kh kw hi wi| ≤ δ

                    Padded reads move no more than the input entries.

                    theorem Proofs.conv2d_input_sub {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (b : Vec oc) (x x' : Tensor3 ic h w) (o : Fin oc) (ho : Fin h) (wo : Fin w) :
                    conv2d W b x' o ho wo - conv2d W b x o ho wo = ∑ c : Fin ic, ∑ kh : Fin kH, ∑ kw : Fin kW, W o c kh kw * (convPad kH kW x' c kh kw ho wo - convPad kH kW x c kh kw ho wo)

                    The conv output difference under an input perturbation, exactly: the kernel taps contract the padded-input differences — conv2d is linear in its input (the input-side peer of conv2d_kernel_sub / conv2d_bias_sub).

                    theorem Proofs.conv2d_input_entry_drift {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (b : Vec oc) (x x' : Tensor3 ic h w) {wK δ : ℝ} (hwK : 0 ≤ wK) (hW : ∀ (o : Fin oc) (c : Fin ic) (kh : Fin kH) (kw : Fin kW), |W o c kh kw| ≤ wK) (hδ : 0 ≤ δ) (hclose : ∀ (c : Fin ic) (i : Fin h) (j : Fin w), |x' c i j - x c i j| ≤ δ) (o : Fin oc) (ho : Fin h) (wo : Fin w) :
                    |conv2d W b x' o ho wo - conv2d W b x o ho wo| ≤ ↑(ic * kH * kW) * (wK * δ)

                    Per-entry conv input drift: each output reads ic·kH·kW padded inputs through taps bounded by wK.

                    theorem Proofs.abs_convPad_sub_expand {ic h w kH kW : ℕ} (x x' : Tensor3 ic h w) (c : Fin ic) (kh : Fin kH) (kw : Fin kW) (ho : Fin h) (wo : Fin w) :
                    |convPad kH kW x' c kh kw ho wo - convPad kH kW x c kh kw ho wo| = ∑ i : Fin h, ∑ j : Fin w, if ↑kh + ↑ho = ↑i + (kH - 1) / 2 ∧ ↑kw + ↑wo = ↑j + (kW - 1) / 2 then |x' c i j - x c i j| else 0

                    The padded-read drift as a position-pinned indicator sum — the input-side peer of abs_convTap_expand, for the ℓ1 bound.

                    theorem Proofs.conv2d_input_l1_drift {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (b : Vec oc) (x x' : Tensor3 ic h w) {wK : ℝ} (hwK : 0 ≤ wK) (hW : ∀ (o : Fin oc) (c : Fin ic) (kh : Fin kH) (kw : Fin kW), |W o c kh kw| ≤ wK) :
                    ∑ o : Fin oc, ∑ ho : Fin h, ∑ wo : Fin w, |conv2d W b x' o ho wo - conv2d W b x o ho wo| ≤ ↑(oc * kH * kW) * (wK * ∑ c : Fin ic, ∑ i : Fin h, ∑ j : Fin w, |x' c i j - x c i j|)

                    ℓ1 conv input drift: each input entry feeds at most oc·kH·kW outputs, so the total output drift is at most oc·kH·kW·wK times the total input drift — locality, not a spatial count.

                    theorem Proofs.Conv1Slot.z2_entry_drift {P c h w kH kW : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {ρ w₂ : ℝ} (hρ : 0 ≤ ρ) (hZ : ∀ (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))), |Z (v + e) k - Z v k| ≤ ρ * ∑ idx : Fin P, |e idx|) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))) :
                    |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + e))))).flatten k - (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten k| ≤ ↑(c * kH * kW) * (w₂ * (ρ * ∑ idx : Fin P, |e idx|))

                    Per-entry conv2-preactivation drift: the conv1 pre-activation Z moves by ρ·‖e‖₁ per entry and crosses conv2 as a function of its INPUT, picking up the locality factor c·kH·kW·w₂.

                    theorem Proofs.Conv1Slot.z2_l1_drift {P c h w kH kW : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {ρ w₂ : ℝ} (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (v e : Vec P) :
                    ∑ k : Fin (c * (2 * h) * (2 * w)), |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + e))))).flatten k - (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten k| ≤ ↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)))

                    ℓ1 conv2-preactivation drift: conv1 (ℓ1, hZ1) → relu → conv2-as-input (ℓ1, locality multiplicity c·kH·kW).

                    theorem Proofs.Conv1Slot.margin2_keeps_offkink {P c h w kH kW : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {ρ w₂ D : ℝ} (hρ : 0 ≤ ρ) (hZ : ∀ (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))), |Z (v + e) k - Z v k| ≤ ρ * ∑ idx : Fin P, |e idx|) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (v e : Vec P) (he : ∑ idx : Fin P, |e idx| ≤ D) (hm : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (ρ * D)) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten k|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (k : Fin (c * (2 * h) * (2 * w))) :
                    (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))))).flatten k ≠ 0 ∧ (0 < (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))))).flatten k ↔ 0 < (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten k)

                    The relu₂ margin (at the conv1 radius) keeps the conv2 pre-activation off the kink.

                    theorem Proofs.Conv1Slot.postrelu2_close_seg {P c h w kH kW : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {ρ w₂ D : ℝ} (hρ : 0 ≤ ρ) (hZ : ∀ (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))), |Z (v + e) k - Z v k| ≤ ρ * ∑ idx : Fin P, |e idx|) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (v e : Vec P) (he : ∑ idx : Fin P, |e idx| ≤ D) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                    |Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))))).flatten) ci hi wi - Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten) ci hi wi| ≤ ↑(c * kH * kW) * (w₂ * (ρ * D))

                    The POST-relu₂ tensor stays within the conv1-slot pool margin radius along the whole step segment.

                    theorem Proofs.Conv1Slot.margin3_keeps_offkink {P c h w d₃ kH kW : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) {ρ w₂ w₃ D : ℝ} (hρ : 0 ≤ ρ) (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (v e : Vec P) (he : ∑ idx : Fin P, |e idx| ≤ D) (hm : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (ρ * D)))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten)) l|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (l : Fin d₃) :
                    dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))))).flatten)) l ≠ 0 ∧ (0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))))).flatten)) l ↔ 0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten)) l)

                    The relu₃ margin (at the conv1 radius) keeps the first head pre-activation off the kink.

                    theorem Proofs.Conv1Slot.margin4_keeps_offkink {P c h w d₃ d₄ kH kW : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) {ρ w₂ w₃ w₄ D : ℝ} (hρ : 0 ≤ ρ) (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (v e : Vec P) (he : ∑ idx : Fin P, |e idx| ≤ D) (hm : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (ρ * D)))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten)))) q|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (q : Fin d₄) :
                    dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))))).flatten)))) q ≠ 0 ∧ (0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z (v + t • e))))).flatten)))) q ↔ 0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten)))) q)

                    The relu₄ margin (at the conv1 radius) keeps the second head pre-activation off the kink.

                    theorem Proofs.Conv1Slot.loss_grad_lipschitz {P c h w d₃ d₄ nC kH kW : ℕ} (Z : Vec P → Vec (c * (2 * h) * (2 * w))) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) {ρ w₂ w₃ w₄ w₅ D : ℝ} (hρ : 0 ≤ ρ) (hZ : ∀ (v e : Vec P) (k : Fin (c * (2 * h) * (2 * w))), |Z (v + e) k - Z v k| ≤ ρ * ∑ idx : Fin P, |e idx|) (hZ1 : ∀ (v e : Vec P), ∑ k : Fin (c * (2 * h) * (2 * w)), |Z (v + e) k - Z v k| ≤ ↑(2 * h * (2 * w)) * (ρ * ∑ idx : Fin P, |e idx|)) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (J : Fin c → Fin (2 * h) → Fin (2 * w) → ℝ) (hJ : ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), |J ci hi wi| ≤ ↑(2 * h * (2 * w)) * ρ) (idx : Fin P) (hgrad : ∀ (v' : Vec P), (∀ (k : Fin (c * (2 * h) * (2 * w))), Z v' k ≠ 0) → (∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten k ≠ 0) → MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten)) → (∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten)) l ≠ 0) → (∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten)))) q ≠ 0) → gradAt (fun (v'' : Vec P) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v'')))).flatten))))))) label) v' idx = ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), J ci hi wi * ((if Z v' (t3Idx ci hi wi) > 0 then 1 else 0) * ∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * ((if (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten)) co ho wo then ∑ l : Fin d₃, W₃ (t3Idx co (winRow ho) (winCol wo)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten)) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten)))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten))))))) k - oneHot nC label k))) else 0))) (v d : Vec P) (hd : ∑ idx : Fin P, |d idx| ≤ D) (hm1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ρ * D < |Z v k|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (ρ * D)) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten k|) (hmq : MaxPool2MarginQ (↑(c * kH * kW) * (w₂ * (ρ * D))) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (ρ * D)))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (ρ * D)))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v)))).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (ρ * D))))))))) < 1) (t : ℝ) (ht : t ∈ Set.Icc 0 1) :
                    |gradAt (fun (v' : Vec P) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten))))))) label) (v + t • d) idx - gradAt (fun (v' : Vec P) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (Z v')))).flatten))))))) label) v idx| ≤ 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑(c * kH * kW) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₂ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * ρ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (ρ * D)))))))))) * (t * D)

                    Segment-Lipschitz gradient for a conv1-slot loss, explicit constant. For a parameter map Z into conv1's pre-activation with per-entry drift ρ·‖e‖₁ (hZ) and ℓ1 drift (2h)·(2w)·ρ·‖e‖₁ (hZ1), whose loss gradient at every off-kink point is a fixed conv1 Jacobian row J (row mass ≤ (2h)·(2w)·ρ) contracted with relu₁'s mask, conv2's point-free taps and the head (hgrad): the relu₁ margin freezes the mask along [v, v+d], so J, the mask and the taps collapse to one fixed row at the conv2 pre-activation, of row mass ≤ (2h)·(2w)·(c·kH·kW·w₂·ρ), and the rest is Conv2Slot.loss_grad_lipschitz at radius c·kH·kW·w₂·ρ. The conv1-kernel rung is the instance ρ = a, the conv1-bias rung ρ = 1.

                    theorem Proofs.cnn1_margin1_keeps_offkink {ic c h w kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) {a D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (u e : Vec (c * ic * kH * kW)) (he : ∑ idx : Fin (c * ic * kH * kW), |e idx| ≤ D) (hm : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * D < |(conv2d (Kernel4.unflatten u) b₁ x₀).flatten k|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (k : Fin (c * (2 * h) * (2 * w))) :
                    (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten k ≠ 0 ∧ (0 < (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten k ↔ 0 < (conv2d (Kernel4.unflatten u) b₁ x₀).flatten k)

                    The relu₁ margin keeps the conv1 pre-activation off the kink.

                    theorem Proofs.cnn1_margin2_keeps_offkink {ic c h w kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {a w₂ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (u e : Vec (c * ic * kH * kW)) (he : ∑ idx : Fin (c * ic * kH * kW), |e idx| ≤ D) (hm : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (a * D)) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten k|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (k : Fin (c * (2 * h) * (2 * w))) :
                    (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten))).flatten k ≠ 0 ∧ (0 < (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten))).flatten k ↔ 0 < (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten k)

                    The relu₂ margin (at the conv1 radius) keeps the conv2 pre-activation off the kink.

                    theorem Proofs.cnn1_postrelu2_close_seg {ic c h w kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {a w₂ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (u e : Vec (c * ic * kH * kW)) (he : ∑ idx : Fin (c * ic * kH * kW), |e idx| ≤ D) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                    |Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten))).flatten) ci hi wi - Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten) ci hi wi| ≤ ↑(c * kH * kW) * (w₂ * (a * D))

                    The POST-relu₂ tensor stays within the conv1-rung pool margin radius along the whole step segment.

                    theorem Proofs.cnn1_margin3_keeps_offkink {ic c h w d₃ kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) {a w₂ w₃ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (u e : Vec (c * ic * kH * kW)) (he : ∑ idx : Fin (c * ic * kH * kW), |e idx| ≤ D) (hm : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * D)))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (l : Fin d₃) :
                    dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten))).flatten)) l ≠ 0 ∧ (0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten))).flatten)) l ↔ 0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l)

                    The relu₃ margin (at the conv1 radius) keeps the first head pre-activation off the kink.

                    theorem Proofs.cnn1_margin4_keeps_offkink {ic c h w d₃ d₄ kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) {a w₂ w₃ w₄ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (u e : Vec (c * ic * kH * kW)) (he : ∑ idx : Fin (c * ic * kH * kW), |e idx| ≤ D) (hm : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * D)))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (q : Fin d₄) :
                    dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten))).flatten)))) q ≠ 0 ∧ (0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten (u + t • e)) b₁ x₀).flatten))).flatten)))) q ↔ 0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q)

                    The relu₄ margin (at the conv1 radius) keeps the second head pre-activation off the kink.

                    theorem Proofs.cnn1_pool_head_differentiableAt {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (z₁ : Vec (c * (2 * h) * (2 * w))) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), z₁ k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten)))) q ≠ 0) :
                    DifferentiableAt ℝ (fun (y : Vec (c * (2 * h) * (2 * w))) (x : Fin 1) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) y))).flatten))))))) label) z₁

                    The whole head above the conv1 output — CE∘head3∘pool∘relu∘ (flatConv W₂ b₂)∘relu — is differentiable at any five-condition point.

                    theorem Proofs.cnn1_pool_head_input_grad {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (z₁ : Vec (c * (2 * h) * (2 * w))) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), z₁ k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten)))) q ≠ 0) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                    pdiv (fun (y : Vec (c * (2 * h) * (2 * w))) (x : Fin 1) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) y))).flatten))))))) label) z₁ (t3Idx ci hi wi) 0 = (if z₁ (t3Idx ci hi wi) > 0 then 1 else 0) * ∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * ((if (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten)) co ho wo then ∑ l : Fin d₃, W₃ (t3Idx co (winRow ho) (winCol wo)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten)) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten)))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) z₁))).flatten))))))) k - oneHot nC label k))) else 0)

                    Loss input-gradient at the conv1 output — the conv1 peer of pool_relu_input_grad. One more relu mask and one conv-as-input crossing: the chain picks up relu'(z₁) and contracts the point-free tap Jacobian of conv2 with the pool-collapsed conv2-rung gradient.

                    theorem Proofs.cnn_conv1_loss_differentiableAt {ic c h w d₃ d₄ nC kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (u : Vec (c * ic * kH * kW)) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d (Kernel4.unflatten u) b₁ x₀).flatten k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q ≠ 0) :
                    DifferentiableAt ℝ (fun (u' : Vec (c * ic * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u') b₁ x₀).flatten))).flatten))))))) label) u

                    The loss-of-conv1-kernel map is differentiable at any five-condition point.

                    theorem Proofs.cnn_conv1_loss_gradAt {ic c h w d₃ d₄ nC kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (u : Vec (c * ic * kH * kW)) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d (Kernel4.unflatten u) b₁ x₀).flatten k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q ≠ 0) (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) :
                    gradAt (fun (u' : Vec (c * ic * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u') b₁ x₀).flatten))).flatten))))))) label) u (k4Idx o cc kh kw) = ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), (if ci = o then convPad kH kW x₀ cc kh kw hi wi else 0) * ((if (conv2d (Kernel4.unflatten u) b₁ x₀).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * ∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * ((if (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) co ho wo then ∑ l : Fin d₃, W₃ (t3Idx co (winRow ho) (winCol wo)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))))))) k - oneHot nC label k))) else 0))

                    Closed form of the conv1 loss gradient at any five-margin point — the same chain rule, contracted with the conv1 head gradient (cnn1_pool_head_input_grad): the conv1 weight Jacobian (convPad reads of the IMAGE) times relu₁'s mask times the point-free conv2 tap Jacobian times the pool-collapsed head. Two spatial triple-sums: weight sharing at conv1, locality at conv2.

                    theorem Proofs.cnn_conv1_loss_gradAt_reluMask {ic c h w d₃ d₄ nC kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (u : Vec (c * ic * kH * kW)) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d (Kernel4.unflatten u) b₁ x₀).flatten k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q ≠ 0) (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) :
                    gradAt (fun (u' : Vec (c * ic * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u') b₁ x₀).flatten))).flatten))))))) label) u (k4Idx o cc kh kw) = ∑ s : Fin (2 * h * (2 * w)), convPadWin kH kW x₀ cc kh kw s * cotWin (fun (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) => (if (conv2d (Kernel4.unflatten u) b₁ x₀).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * ∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * ((if (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) co ho wo then dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (FloatModel.reluMask (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))) (dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (FloatModel.reluMask (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))))) (dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) fun (k : Fin nC) => softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))))))) k - oneHot nC label k)))) (t3Idx co (winRow ho) (winCol wo)) else 0)) o s

                    The certified conv-1 loss gradient, head restated in dense/reluMask form — the conv-1 peer of cnn_conv2_loss_gradAt_reluMask. One conv-backward deeper than conv-2: the conv-1-output cotangent is 𝟙[z₁>0] · ∑_{co,ho,wo} convTap·(conv-2-output cotangent), with the 3-dense head collapsed by head3_cot_reluMask exactly as in conv-2. The conv-1 ReLU mask, the conv-2 backward tap (convTap, the point-free conv-2 input Jacobian), the conv-2 ReLU mask and the pool selector all stay explicit (their float closeness is mask_scalar_close / dot_perturbed_close / poolBack_close). Packaged as the spatial dot ∑ₛ convPadWin x₀·cotWin (convWeightGrad_eq_dot) the float conv-1 weight dot rounds.

                    noncomputable def Proofs.FloatModel.cnnConv1FloatGrad {ic c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (fexp : ℝ → ℝ) (label : Fin nC) (u : Vec (c * ic * kH * kW)) :
                    Vec (c * ic * kH * kW)

                    The binary32 conv-1 weight gradient (FloatModel transcription of the per-example gradient) — the conv-1 peer of cnnConv2FloatGrad, one conv-backward deeper. At kernel entry (o,cc,kh,kw) it is the float dot of the (exact) padded-input window convPadWin x₀ against the float conv-1-output cotangent slab; that cotangent is the conv-1 ReLU mask 𝟙[z̃₁>0] times the float conv-2 backward M.dot (convTap W₂ slab) (float conv-2-output cotangent slab), where the conv-2 cotangent is exactly cnnConv2FloatGrad's, but at the FLOAT conv-2 input relu(z̃₁) (a function of the conv-1 kernel u). All M-ops carry the rounding; reluMask/maxPoolFlat/relu/convTap are exact.

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For
                      @[simp]
                      theorem Proofs.FloatModel.cnnConv1FloatGrad_apply {ic c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (fexp : ℝ → ℝ) (label : Fin nC) (u : Vec (c * ic * kH * kW)) (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) :
                      M.cnnConv1FloatGrad b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ fexp label u (k4Idx o cc kh kw) = M.dot (convPadWin kH kW x₀ cc kh kw) (cotWin (fun (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) => (if (M.convF (Kernel4.unflatten u) b₁ x₀).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * M.dot (Tensor3.flatten fun (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)) => convTap W₂ ci hi wi co ho wo) (Tensor3.flatten fun (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)) => (if (M.convF W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten u) b₁ x₀).flatten))).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) co ho wo then M.dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (reluMask (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))) (M.dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (reluMask (M.dense W₄ b₄ (relu d₃ (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))))) (M.dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) (M.softmaxCECotF fexp (M.dense W₅ b₅ (relu d₄ (M.dense W₄ b₄ (relu d₃ (M.dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (M.convF W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (M.convF (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))))))) label))))) (t3Idx co (winRow ho) (winCol wo)) else 0)) o)
                      noncomputable def Proofs.FloatModel.cnnConv1GradBudget (M : FloatModel) (ic c h w d₃ d₄ nC kH kW : ℕ) (a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ) :

                      The conv-1 float-backward grad-close budget — the conv-2 budget (cnnConv2GradBudget-shaped) deepened by one conv layer at the bottom (the forward nest now starts at conv-1 fan-in ic·kH·kW, the conv-2 input carries the conv-1 rounding E₁) and one conv-backward at the top: the conv-2 backward Higham γ over the slab c·(2h)·(2w) against the float-cotangent magnitude C2t plus the per-entry conv-2-cotangent drift e₂ gives eback; the conv-1 spatial dot (fan-in (2h)·(2w)) then rides eback and the float conv-1-cotangent magnitude C1t.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        theorem Proofs.convTap_back_close {c h w kH kW : ℕ} (M : FloatModel) (W₂ : Kernel4 c c kH kW) (c2F c2R : Tensor3 c (2 * h) (2 * w)) {w₂ C2t e2 : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hc2F : ∀ (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)), |c2F co ho wo| ≤ C2t) (hc2close : ∀ (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)), |c2F co ho wo - c2R co ho wo| ≤ e2) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                        |M.dot (Tensor3.flatten fun (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)) => convTap W₂ ci hi wi co ho wo) c2F.flatten - ∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * c2R co ho wo| ≤ ((1 + M.u) ^ (c * (2 * h) * (2 * w) + 1) - 1) * (↑(c * (2 * h) * (2 * w)) * (w₂ * C2t)) + ↑(c * (2 * h) * (2 * w)) * (w₂ * e2)

                        The float conv-2 backward (transpose conv) against a perturbed cotangent. The rounded M.dot of the exact convTap slab against the float conv-2-output cotangent c2F, vs the certified ∑ convTap·c2R — the convTap-flattening (sum_t3) plus dot_perturbed_close (fan-in c·(2h)·(2w), per-entry tap bound w₂, float-cotangent magnitude C2t, drift e₂). Generic in (c2F, c2R) so the conv-1 rung passes the conv-2 cotangent tensors abstractly.

                        theorem Proofs.convTap_back_abs_le {c h w kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (c2R : Tensor3 c (2 * h) (2 * w)) {w₂ CP : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hc2R : ∀ (co : Fin c) (ho : Fin (2 * h)) (wo : Fin (2 * w)), |c2R co ho wo| ≤ CP) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                        |∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * c2R co ho wo| ≤ ↑(c * (2 * h) * (2 * w)) * (w₂ * CP)

                        The real conv-2 backward ∑ convTap·c2R is magnitude-bounded by the tap ℓ∞-mass (c·(2h)·(2w))·w₂ times the cotangent bound CP — the (loose, uniform) bound on the real conv-1 cotangent.

                        theorem Proofs.cnn_conv1_grad_close {ic c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) (u : Vec (c * ic * kH * kW)) {a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₁ : 0 ≤ w₁) (hβ₁ : 0 ≤ β₁) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx₀ : ∀ (ci : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ ci i j| ≤ a) (hu1 : ∀ (idx : Fin (c * ic * kH * kW)), |u idx| ≤ w₁) (hb₁ : ∀ (o : Fin c), |b₁ o| ≤ β₁) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmargin1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0 < |(conv2d (Kernel4.unflatten u) b₁ x₀).flatten k|) (hmargin2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a))) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q|) (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW) :
                        |M.cnnConv1FloatGrad b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ fexp label u (k4Idx o cc kh kw) - gradAt (fun (u' : Vec (c * ic * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u') b₁ x₀).flatten))).flatten))))))) label) u (k4Idx o cc kh kw)| ≤ M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp

                        The binary32 conv-1 weight gradient is within an explicit budget of the certified one — the conv-1 peer of cnn_conv2_grad_close, one conv-backward deeper. With x₀ exact, the FloatModel W₁ gradient M.cnnConv1FloatGrad … stays within cnnConv1GradBudget. The conv-2 cotangent chain is reused at a FLOAT conv-2 input relu(z̃₁) (cnn_conv2_cot_close); the conv-2 backward is a rounded dot of the (exact) convTap slab against the float conv-2 cotangent slab (dot_perturbed_close over c·(2h)·(2w)); the conv-1 ReLU mask freezes (mask_scalar_close); the conv-1 weight dot rounds it (dot_perturbed_close over (2h)·(2w)). Five quantitative margins are carried; the bridge cnn_conv1_loss_gradAt_reluMask turns the gradAt into the dot.

                        theorem Proofs.cnn_conv1_loss_grad_lipschitz {ic c h w d₃ d₄ nC kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) {a w₂ w₃ w₄ w₅ D : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (u d : Vec (c * ic * kH * kW)) (hd : ∑ idx : Fin (c * ic * kH * kW), |d idx| ≤ D) (hm1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * D < |(conv2d (Kernel4.unflatten u) b₁ x₀).flatten k|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (a * D)) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten k|) (hmq : MaxPool2MarginQ (↑(c * kH * kW) * (w₂ * (a * D))) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * D)))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * D)))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u) b₁ x₀).flatten))).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * D))))))))) < 1) (t : ℝ) (ht : t ∈ Set.Icc 0 1) (idx : Fin (c * ic * kH * kW)) :
                        |gradAt (fun (u' : Vec (c * ic * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u') b₁ x₀).flatten))).flatten))))))) label) (u + t • d) idx - gradAt (fun (u' : Vec (c * ic * kH * kW)) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d (Kernel4.unflatten u') b₁ x₀).flatten))).flatten))))))) label) u idx| ≤ 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑(c * kH * kW) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₂ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * a ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * D)))))))))) * (t * D)

                        Segment-Lipschitz gradient for the conv1-kernel loss, explicit constant. Under the FIVE margins at step radius D — relu₁ (a·D), relu₂ (c·kH·kW·w₂·a·D), pool selection (same radius, POST-relu₂), relu₃, relu₄ — every routing decision freezes along [u, u+d], BOTH conv Jacobians factor out point-free, and the difference collapses to the softmax drift. The constant picks up the conv1 weight-sharing multiplicity ((2h)·(2w))² AND the conv2 locality multiplicity (c·kH·kW)²·w₂². Conv1Slot.loss_grad_lipschitz at ρ = a.

                        noncomputable def Proofs.cnnConv1KernelLoss {ic c h w d₃ d₄ nC kH kW : ℕ} (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) :
                        Vec (c * ic * kH * kW) → ℝ

                        The loss as a function of the flattened first-conv kernel.

                        Equations
                        • One or more equations did not get rendered due to their size.
                        Instances For
                          theorem Proofs.cnn_conv1_sgd_descends {ic c h w d₃ d₄ nC kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (gh : Vec (c * ic * kH * kW)) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) {lr η a w₂ w₃ w₄ w₅ : ℝ} (ha : 0 ≤ a) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hlr : 0 ≤ lr) (hη : 0 ≤ η) (hgh : ∀ (idx : Fin (c * ic * kH * kW)), |gh idx - gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx| ≤ η) (hm1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η < |(conv2d W₁ b₁ x₀).flatten k|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η)) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten k|) (hmq : MaxPool2MarginQ (↑(c * kH * kW) * (w₂ * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η))) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η)))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η)))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η))))))))) < 1) (h1 : lr * η * ∑ idx : Fin (c * ic * kH * kW), |gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx| ≤ (lr * ∑ idx : Fin (c * ic * kH * kW), gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑(c * kH * kW) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₂ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * a ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η)))))))))) * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr η ^ 2 ≤ (lr * ∑ idx : Fin (c * ic * kH * kW), gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx ^ 2) / 4) :
                          cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label (W₁.flatten - lr • gh) ≤ cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label W₁.flatten - (lr * ∑ idx : Fin (c * ic * kH * kW), gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx ^ 2) / 2

                          One inexact SGD step on the CNN's FIRST conv kernel decreases one example's cross-entropy loss (W₁ moving, every other parameter fixed). The deepest rung: the step crosses relu₁, conv2 (as a function of its input — the point-free tap Jacobian with locality factor c·kH·kW·w₂), relu₂, the pool, and the 3-dense head. Under the FIVE margins at the step radius D = lr·(‖∇L‖₁ + |kernel|·η), every mask and the pool's routing pattern freeze along the step, and the loss drops by ≥ lr·‖∇L‖₂²/2. With this, both conv kernels of the Chapter-3 CNN have a single-layer, single-example descent statement.

                          theorem Proofs.cnn_conv1_float_sgd_descends {ic c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) {lr a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₁ : 0 ≤ w₁) (hβ₁ : 0 ≤ β₁) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (hlr : 0 ≤ lr) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx₀ : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hW₁ : ∀ (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW), |W₁ o cc kh kw| ≤ w₁) (hb₁ : ∀ (o : Fin c), |b₁ o| ≤ β₁) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hr1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0 < |(conv2d W₁ b₁ x₀).flatten k|) (hr2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten k|) (hrPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))) (hr3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)) l|) (hr4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a))) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)))) q|) (hm1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) < |(conv2d W₁ b₁ x₀).flatten k|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten k|) (hmq : MaxPool2MarginQ (↑(c * kH * kW) * (w₂ * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)))) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)))))))))) < 1) (h1 : lr * M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp * ∑ idx : Fin (c * ic * kH * kW), |gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx| ≤ (lr * ∑ idx : Fin (c * ic * kH * kW), gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑(c * kH * kW) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₂ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 * a ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (a * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))))))))) * stepRadius (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten lr (M.cnnConv1GradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) ^ 2 ≤ (lr * ∑ idx : Fin (c * ic * kH * kW), gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx ^ 2) / 4) :
                          cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label (W₁.flatten - lr • M.cnnConv1FloatGrad b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ fexp label W₁.flatten) ≤ cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label W₁.flatten - (lr * ∑ idx : Fin (c * ic * kH * kW), gradAt (cnnConv1KernelLoss b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) W₁.flatten idx ^ 2) / 2

                          One SGD step with the FloatModel binary32 conv-1 kernel gradient decreases one example's cross-entropy loss; the gradient's accuracy is proven, not assumed. The conv-1 peer of cnn_conv2_float_sgd_descends: the gradient is the FloatModel binary32 W₁ gradient M.cnnConv1FloatGrad …, accuracy proven by cnn_conv1_grad_close (η := cnnConv1GradBudget, discharged per kernel entry via k4Idx_surj), wired into the abstract cnn_conv1_sgd_descends. Five per-layer ROUND margins feed the grad-close; the gradient-radius STEP margins + hsmall/h1/h2 feed the drift-freeze and descent geometry. Both conv kernels of the Chapter-3 CNN now have a float-gradient descent statement.

                          Scope: one example, W₁ moving with every other parameter fixed, and the update taken in ℝ — only the gradient is float-modelled.

                          theorem Proofs.conv2d_bias_sub {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (x : Tensor3 ic h w) (b e : Vec oc) (o : Fin oc) (hi : Fin h) (wi : Fin w) :
                          conv2d W (b + e) x o hi wi - conv2d W b x o hi wi = e o

                          The conv output difference under a bias perturbation, exactly: output (o,hi,wi) moves by e o — conv2d is affine in the bias.

                          theorem Proofs.conv2d_flat_bias_drift_total {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (x : Tensor3 ic h w) (b e : Vec oc) (k : Fin (oc * h * w)) :
                          |(conv2d W (b + e) x).flatten k - (conv2d W b x).flatten k| ≤ ∑ idx : Fin oc, |e idx|

                          Per-entry conv drift under a bias perturbation: the perturbation's own entry — no a factor, no kernel mass. Flat-index form.

                          theorem Proofs.conv2d_flat_bias_drift_sum {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (x : Tensor3 ic h w) (b e : Vec oc) :
                          ∑ k : Fin (oc * h * w), |(conv2d W (b + e) x).flatten k - (conv2d W b x).flatten k| ≤ ↑(h * w) * ∑ idx : Fin oc, |e idx|

                          ℓ1 conv bias drift: summed over all output entries, at most (h·w)·‖e‖₁ — one bias entry feeds every spatial position of its channel.

                          theorem Proofs.conv2d_bias_pdiv {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (x : Tensor3 ic h w) (b : Vec oc) (o co : Fin oc) (hi : Fin h) (wi : Fin w) :
                          pdiv (fun (b' : Vec oc) => (conv2d W b' x).flatten) b o (t3Idx co hi wi) = if co = o then 1 else 0

                          Closed form of the conv bias-map pdiv — extracted from the certified VJP (conv2dBiasGradHasVJP) by contracting its .correct field against a basis vector, exactly as conv2d_weight_pdiv. Bias entry o touches output (co,hi,wi) iff co = o, with coefficient 1 — the Kronecker channel indicator. Point-free (the bias map is affine), so along a step segment only the head gradient moves.

                          theorem Proofs.cnnb2_margin2_keeps_offkink {c h w kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) {D : ℝ} (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (hm : ∀ (k : Fin (c * (2 * h) * (2 * w))), D < |(conv2d W₂ b x₁).flatten k|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (k : Fin (c * (2 * h) * (2 * w))) :
                          (conv2d W₂ (b + t • e) x₁).flatten k ≠ 0 ∧ (0 < (conv2d W₂ (b + t • e) x₁).flatten k ↔ 0 < (conv2d W₂ b x₁).flatten k)

                          The relu₂ margin (at the bias radius D) keeps the conv pre-activation off the kink along the whole step segment.

                          theorem Proofs.cnnb2_postrelu_close_seg {c h w kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) {D : ℝ} (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                          |Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ (b + t • e) x₁).flatten) ci hi wi - Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten) ci hi wi| ≤ D

                          The POST-relu tensor stays within the bias-rung pool margin radius D along the whole step segment.

                          theorem Proofs.cnnb2_margin3_keeps_offkink {c h w d₃ kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) {w₃ D : ℝ} (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (hm : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * D) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) l|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (l : Fin d₃) :
                          dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ (b + t • e) x₁).flatten)) l ≠ 0 ∧ (0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ (b + t • e) x₁).flatten)) l ↔ 0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) l)

                          The relu₃ margin (at the bias radius) keeps the first head pre-activation off the kink along the whole step segment.

                          theorem Proofs.cnnb2_margin4_keeps_offkink {c h w d₃ d₄ kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) {w₃ w₄ D : ℝ} (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (hm : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * D))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)))) q|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (q : Fin d₄) :
                          dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ (b + t • e) x₁).flatten)))) q ≠ 0 ∧ (0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ (b + t • e) x₁).flatten)))) q ↔ 0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)))) q)

                          The relu₄ margin (at the bias radius) keeps the second head pre-activation off the kink along the whole step segment.

                          theorem Proofs.cnn_conv2_bias_loss_differentiableAt {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (b : Vec c) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b x₁).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)))) q ≠ 0) :
                          DifferentiableAt ℝ (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b' x₁).flatten))))))) label) b

                          The loss-of-conv2-bias map is differentiable at any four-condition point.

                          theorem Proofs.cnn_conv2_bias_loss_gradAt {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (b : Vec c) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b x₁).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)))) q ≠ 0) (o : Fin c) :
                          gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b' x₁).flatten))))))) label) b o = ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), (if ci = o then 1 else 0) * ((if (conv2d W₂ b x₁).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) ci hi wi then ∑ l : Fin d₃, W₃ (t3Idx ci (winRow hi) (winCol wi)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))))))) k - oneHot nC label k))) else 0)

                          Closed form of the conv2 bias loss gradient at any four-margin point — the chain rule through the conv bias map (gradAt_comp_t3) with the pool-collapsed head gradient (pool_relu_input_grad, reused verbatim) and the Kronecker bias Jacobian (conv2d_bias_pdiv).

                          theorem Proofs.cnn_conv2_bias_loss_grad_lipschitz {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) {w₃ w₄ w₅ D : ℝ} (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (b d : Vec c) (hd : ∑ idx : Fin c, |d idx| ≤ D) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), D < |(conv2d W₂ b x₁).flatten k|) (hmq : MaxPool2MarginQ D (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * D) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * D))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * D)))))) < 1) (t : ℝ) (ht : t ∈ Set.Icc 0 1) (o : Fin c) :
                          |gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b' x₁).flatten))))))) label) (b + t • d) o - gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b' x₁).flatten))))))) label) b o| ≤ 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * D))))))) * (t * D)

                          Segment-Lipschitz gradient for the conv2-bias loss, explicit constant. Conv2Slot.loss_grad_lipschitz at ρ = 1: the bias Jacobian is a Kronecker indicator with row mass (2h)·(2w), no input bound, so the radius is the bare D and the constant is the kernel constant with a² ↦ 1.

                          noncomputable def Proofs.cnnConv2BiasLoss {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) :
                          Vec c → ℝ

                          The loss as a function of the second-conv bias.

                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For
                            theorem Proofs.cnn_conv2_bias_sgd_descends {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (gh : Vec c) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) {lr η w₃ w₄ w₅ : ℝ} (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hlr : 0 ≤ lr) (hη : 0 ≤ η) (hgh : ∀ (o : Fin c), |gh o - gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o| ≤ η) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr η < |(conv2d W₂ b₂ x₁).flatten k|) (hmq : MaxPool2MarginQ (stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr η) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr η) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr η))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr η)))))) < 1) (h1 : lr * η * ∑ o : Fin c, |gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o| ≤ (lr * ∑ o : Fin c, gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr η))))))) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr η ^ 2 ≤ (lr * ∑ o : Fin c, gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o ^ 2) / 4) :
                            cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label (b₂ - lr • gh) ≤ crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))))))) label - (lr * ∑ o : Fin c, gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o ^ 2) / 2

                            One inexact SGD step on the CNN's second conv BIAS decreases one example's cross-entropy loss (b₂ moving, every other parameter fixed). The conv2-kernel capstone with the bias-rung radii: the four margins at the step radius D = lr·(‖∇L‖₁ + c·η) carry no input bound a (the bias Jacobian is a Kronecker indicator), and the parameter needs no flatten/unflatten plumbing — the bias IS a vector.

                            theorem Proofs.cnnb1_margin1_keeps_offkink {ic c h w kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) {D : ℝ} (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (hm : ∀ (k : Fin (c * (2 * h) * (2 * w))), D < |(conv2d W₁ b x₀).flatten k|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (k : Fin (c * (2 * h) * (2 * w))) :
                            (conv2d W₁ (b + t • e) x₀).flatten k ≠ 0 ∧ (0 < (conv2d W₁ (b + t • e) x₀).flatten k ↔ 0 < (conv2d W₁ b x₀).flatten k)

                            The relu₁ margin (at the bias radius D) keeps the conv1 pre-activation off the kink.

                            theorem Proofs.cnnb1_margin2_keeps_offkink {ic c h w kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {w₂ D : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (hm : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * D) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten k|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (k : Fin (c * (2 * h) * (2 * w))) :
                            (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ (b + t • e) x₀).flatten))).flatten k ≠ 0 ∧ (0 < (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ (b + t • e) x₀).flatten))).flatten k ↔ 0 < (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten k)

                            The relu₂ margin (at the conv1-bias radius) keeps the conv2 pre-activation off the kink.

                            theorem Proofs.cnnb1_postrelu2_close_seg {ic c h w kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) {w₂ D : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) :
                            |Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ (b + t • e) x₀).flatten))).flatten) ci hi wi - Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten) ci hi wi| ≤ ↑(c * kH * kW) * (w₂ * D)

                            The POST-relu₂ tensor stays within the conv1-bias pool margin radius along the whole step segment.

                            theorem Proofs.cnnb1_margin3_keeps_offkink {ic c h w d₃ kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) {w₂ w₃ D : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (hm : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * D))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) l|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (l : Fin d₃) :
                            dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ (b + t • e) x₀).flatten))).flatten)) l ≠ 0 ∧ (0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ (b + t • e) x₀).flatten))).flatten)) l ↔ 0 < dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) l)

                            The relu₃ margin (at the conv1-bias radius) keeps the first head pre-activation off the kink.

                            theorem Proofs.cnnb1_margin4_keeps_offkink {ic c h w d₃ d₄ kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) {w₂ w₃ w₄ D : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (b e : Vec c) (he : ∑ idx : Fin c, |e idx| ≤ D) (hm : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * D))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)))) q|) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (q : Fin d₄) :
                            dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ (b + t • e) x₀).flatten))).flatten)))) q ≠ 0 ∧ (0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ (b + t • e) x₀).flatten))).flatten)))) q ↔ 0 < dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)))) q)

                            The relu₄ margin (at the conv1-bias radius) keeps the second head pre-activation off the kink.

                            theorem Proofs.cnn_conv1_bias_loss_differentiableAt {ic c h w d₃ d₄ nC kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (b : Vec c) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₁ b x₀).flatten k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)))) q ≠ 0) :
                            DifferentiableAt ℝ (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b' x₀).flatten))).flatten))))))) label) b

                            The loss-of-conv1-bias map is differentiable at any five-condition point.

                            theorem Proofs.cnn_conv1_bias_loss_gradAt {ic c h w d₃ d₄ nC kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (b : Vec c) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₁ b x₀).flatten k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)))) q ≠ 0) (o : Fin c) :
                            gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b' x₀).flatten))).flatten))))))) label) b o = ∑ ci : Fin c, ∑ hi : Fin (2 * h), ∑ wi : Fin (2 * w), (if ci = o then 1 else 0) * ((if (conv2d W₁ b x₀).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * ∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * ((if (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) co ho wo then ∑ l : Fin d₃, W₃ (t3Idx co (winRow ho) (winCol wo)) l * ((if dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) l > 0 then 1 else 0) * ∑ q : Fin d₄, W₄ l q * ((if dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)))) q > 0 then 1 else 0) * ∑ k : Fin nC, W₅ q k * (softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))))))) k - oneHot nC label k))) else 0))

                            Closed form of the conv1 bias loss gradient at any five-margin point — the chain rule through conv1's bias map, contracted with the conv1 head gradient (cnn1_pool_head_input_grad, reused verbatim): the Kronecker bias Jacobian times relu₁'s mask times the point-free conv2 tap Jacobian times the pool-collapsed head.

                            theorem Proofs.cnn_conv1_bias_loss_grad_lipschitz {ic c h w d₃ d₄ nC kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) {w₂ w₃ w₄ w₅ D : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (b d : Vec c) (hd : ∑ idx : Fin c, |d idx| ≤ D) (hm1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), D < |(conv2d W₁ b x₀).flatten k|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * D) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten k|) (hmq : MaxPool2MarginQ (↑(c * kH * kW) * (w₂ * D)) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * D))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * D))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * D)))))))) < 1) (t : ℝ) (ht : t ∈ Set.Icc 0 1) (o : Fin c) :
                            |gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b' x₀).flatten))).flatten))))))) label) (b + t • d) o - gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b' x₀).flatten))).flatten))))))) label) b o| ≤ 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑(c * kH * kW) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₂ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * D))))))))) * (t * D)

                            Segment-Lipschitz gradient for the conv1-bias loss, explicit constant. The conv1-kernel argument with the conv1 stage's a·D radii replaced by the bare D — the bias Jacobian is a Kronecker indicator with row mass (2h)·(2w). Constant: the conv1-kernel constant with a² ↦ 1. Conv1Slot.loss_grad_lipschitz at ρ = 1.

                            noncomputable def Proofs.cnnConv1BiasLoss {ic c h w d₃ d₄ nC kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) :
                            Vec c → ℝ

                            The loss as a function of the first-conv bias.

                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For
                              theorem Proofs.cnn_conv1_bias_sgd_descends {ic c h w d₃ d₄ nC kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (gh : Vec c) (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) {lr η w₂ w₃ w₄ w₅ : ℝ} (hw₂ : 0 ≤ w₂) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hw₃ : 0 ≤ w₃) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hw₄ : 0 ≤ w₄) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hw₅ : 0 ≤ w₅) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hlr : 0 ≤ lr) (hη : 0 ≤ η) (hgh : ∀ (idx : Fin c), |gh idx - gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| ≤ η) (hm1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * η) < |(conv2d W₁ b₁ x₀).flatten k|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * η))) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten k|) (hmq : MaxPool2MarginQ (↑(c * kH * kW) * (w₂ * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * η)))) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * η))))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * η))))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * η)))))))))) < 1) (h1 : lr * η * ∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| ≤ (lr * ∑ idx : Fin c, gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑(c * kH * kW) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₂ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * η))))))))))) * stepRadius (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ lr η ^ 2 ≤ (lr * ∑ idx : Fin c, gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx ^ 2) / 4) :
                              cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label (b₁ - lr • gh) ≤ crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))))))) label - (lr * ∑ idx : Fin c, gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx ^ 2) / 2

                              One inexact SGD step on the CNN's FIRST conv BIAS decreases one example's cross-entropy loss (b₁ moving, every other parameter fixed). The conv1-kernel capstone with the bias-rung radii: the FIVE margins at the step radius D = lr·(‖∇L‖₁ + c·η) carry no input bound a (the bias Jacobian is a Kronecker indicator) and the parameter needs no flatten/unflatten plumbing. With this theorem both conv kernels, both conv biases and the three dense-layer weight matrices (via the MLP rungs, which omit bias columns) of the Chapter-3 CNN each have a single-layer, single-example descent statement.

                              theorem Proofs.FloatModel.sum_perturbed_close {n : ℕ} (M : FloatModel) (Bt B : Vec n) {Ct eB : ℝ} (hBt : ∀ (i : Fin n), |Bt i| ≤ Ct) (hB : ∀ (i : Fin n), |Bt i - B i| ≤ eB) :
                              |M.sum Bt - ∑ i : Fin n, B i| ≤ ((1 + M.u) ^ (n + 1) - 1) * (↑n * Ct) + ↑n * eB

                              Float sum against a perturbed summand — the conv-BIAS grad-close's final reduction, the M.sum peer of dot_perturbed_close (no left operand A: the bias Jacobian is the bare channel indicator, so the contraction is a plain reduction, not a dot). M.sum B̃ vs the certified ∑ Bᵢ splits into the Higham sum rounding on B̃ (sum_close, fan-in n) plus the per-entry drift |B̃ᵢ − Bᵢ| ≤ eB. With |B̃ᵢ| ≤ Ct the bound is closed-form.

                              noncomputable def Proofs.FloatModel.cnnConv2BiasFloatGrad {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (fexp : ℝ → ℝ) (label : Fin nC) :
                              Vec c

                              The binary32 conv-2 bias gradient (FloatModel transcription of the per-example gradient) — the bias peer of cnnConv2FloatGrad: at output channel o it is the float SUM M.sum (cotWin c̃Conv o) of the same float conv-2-output cotangent slab (the bias Jacobian is the channel indicator, so there is no convPadWin left operand and no per-slot kernel index — one entry per channel).

                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                theorem Proofs.cnn_conv2_bias_loss_gradAt_reluMask {c h w d₃ d₄ nC kH kW : ℕ} (W₂ : Kernel4 c c kH kW) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (b : Vec c) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b x₁).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)))) q ≠ 0) (o : Fin c) :
                                gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b' x₁).flatten))))))) label) b o = ∑ s : Fin (2 * h * (2 * w)), cotWin (fun (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) => (if (conv2d W₂ b x₁).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten)) ci hi wi then dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (FloatModel.reluMask (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))) (dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (FloatModel.reluMask (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))))) (dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) fun (k : Fin nC) => softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b x₁).flatten))))))) k - oneHot nC label k)))) (t3Idx ci (winRow hi) (winCol wi)) else 0) o s

                                The certified conv-2 BIAS loss gradient, restated as the spatial SUM of the reluMask-form cotangent — the bias peer of cnn_conv2_loss_gradAt_reluMask. The 3-dense head collapses via head3_cot_reluMask; the channel-Kronecker Jacobian if ci = o collapses the ∑ ci to ci = o (Finset.sum_ite_eq'); the remaining spatial ∑ hi wi is packaged as ∑ s, cotWin c o s (convBiasGrad_eq_sum) — the quantity the FloatModel gradient's bias SUM rounds.

                                noncomputable def Proofs.FloatModel.cnnConv2BiasGradBudget (M : FloatModel) (c h w d₃ d₄ nC kH kW : ℕ) (a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ) :

                                The conv-2 bias-gradient grad-close budget — cnnConv2GradBudget with the a· input factor stripped (the bias Jacobian carries no input window): the spatial sum's Higham γ over (2h)·(2w) against the float-cotangent magnitude (cnnConv2CotMag + cnnConv2CotBudget) plus the per-entry cotangent drift cnnConv2CotBudget. The cotangent chain is the exact conv-2-input (aX2 = a, eX2 = 0) instance of the factored cnnConv2CotBudget / cnnConv2CotMag.

                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For
                                  theorem Proofs.cnn_conv2_bias_grad_close {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) {a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx₁ : ∀ (ci : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ ci i j| ≤ a) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmarginConv : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0 < |(conv2d W₂ b₂ x₁).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a)) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0)) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)))) q|) (o : Fin c) :
                                  |M.cnnConv2BiasFloatGrad W₂ b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ fexp label o - gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b' x₁).flatten))))))) label) b₂ o| ≤ M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp

                                  The binary32 conv-2 BIAS gradient is within an explicit budget of the certified one — the bias peer of cnn_conv2_grad_close, built on the factored conv-2 cotangent chain at the exact conv-2 input x₁ (cnn_conv2_cot_close with aX2 = a, eX2 = 0) and the spatial-SUM core sum_perturbed_close. The bridge cnn_conv2_bias_loss_gradAt_reluMask turns the gradAt into the sum the float bias gradient rounds. Four quantitative margins (conv-output, pool POST-relu, z̃₃, z̃₄) freeze the routing.

                                  theorem Proofs.cnn_conv2_bias_float_sgd_descends {c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (x₁ : Tensor3 c (2 * h) (2 * w)) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) {lr a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (hlr : 0 ≤ lr) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx : ∀ (cc : Fin c) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₁ cc i j| ≤ a) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmarginConv : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0 < |(conv2d W₂ b₂ x₁).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a)) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ a) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ a 0)) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)))) q|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr (M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) < |(conv2d W₂ b₂ x₁).flatten k|) (hmq : MaxPool2MarginQ (stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr (M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr (M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr (M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr (M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))))) < 1) (h1 : lr * M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp * ∑ o : Fin c, |gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o| ≤ (lr * ∑ o : Fin c, gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(2 * h * (2 * w)) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr (M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)))))))) * stepRadius (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ lr (M.cnnConv2BiasGradBudget c h w d₃ d₄ nC kH kW a w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) ^ 2 ≤ (lr * ∑ o : Fin c, gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o ^ 2) / 4) :
                                  cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label (b₂ - lr • M.cnnConv2BiasFloatGrad W₂ b₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ fexp label) ≤ crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ x₁).flatten))))))) label - (lr * ∑ o : Fin c, gradAt (cnnConv2BiasLoss W₂ x₁ W₃ b₃ W₄ b₄ W₅ b₅ label) b₂ o ^ 2) / 2

                                  One SGD step with the FloatModel binary32 conv-2 bias gradient decreases one example's cross-entropy loss; the gradient's accuracy is proven, not assumed — the bias peer of cnn_conv2_float_sgd_descends: the gradient is the FloatModel binary32 bias gradient M.cnnConv2BiasFloatGrad …, and its accuracy is proven by cnn_conv2_bias_grad_close (η := cnnConv2BiasGradBudget, discharged per output channel — the bias IS a vector, so no flatten/unflatten plumbing), not assumed. The two rounding-margin families are carried as hypotheses, exactly as in the weight rungs. Scope: one example, b₂ moving, update taken in ℝ.

                                  noncomputable def Proofs.FloatModel.cnnConv1BiasFloatGrad {ic c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (fexp : ℝ → ℝ) (label : Fin nC) :
                                  Vec c
                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For
                                    theorem Proofs.cnn_conv1_bias_loss_gradAt_reluMask {ic c h w d₃ d₄ nC kH kW : ℕ} (W₁ : Kernel4 c ic kH kW) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (hh : 0 < h) (hw : 0 < w) (b : Vec c) (hz1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₁ b x₀).flatten k ≠ 0) (hz2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten k ≠ 0) (hmp : MaxPool2Smooth (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))) (hz3 : ∀ (l : Fin d₃), dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) l ≠ 0) (hz4 : ∀ (q : Fin d₄), dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)))) q ≠ 0) (o : Fin c) :
                                    gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b' x₀).flatten))).flatten))))))) label) b o = ∑ s : Fin (2 * h * (2 * w)), cotWin (fun (ci : Fin c) (hi : Fin (2 * h)) (wi : Fin (2 * w)) => (if (conv2d W₁ b x₀).flatten (t3Idx ci hi wi) > 0 then 1 else 0) * ∑ co : Fin c, ∑ ho : Fin (2 * h), ∑ wo : Fin (2 * w), convTap W₂ ci hi wi co ho wo * ((if (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten (t3Idx co ho wo) > 0 then 1 else 0) * if MaxPool2IsArgmax (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten)) co ho wo then dense (fun (j : Fin d₃) (i' : Fin (c * h * w)) => W₃ i' j) (fun (x : Fin (c * h * w)) => 0) (FloatModel.reluMask (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))) (dense (fun (j : Fin d₄) (i' : Fin d₃) => W₄ i' j) (fun (x : Fin d₃) => 0) (FloatModel.reluMask (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))))) (dense (fun (j : Fin nC) (i' : Fin d₄) => W₅ i' j) (fun (x : Fin d₄) => 0) fun (k : Fin nC) => softmax nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b x₀).flatten))).flatten))))))) k - oneHot nC label k)))) (t3Idx co (winRow ho) (winCol wo)) else 0)) o s

                                    The certified conv-1 BIAS loss gradient, restated as the spatial SUM of the reluMask-form cotangent — the bias peer of cnn_conv1_loss_gradAt_reluMask, one conv-backward deeper. The head collapses via head3_cot_reluMask, the conv-2 backward stays the explicit ∑ convTap·c₂, and the channel-Kronecker conv-1 Jacobian collapses the ∑ ci (Finset.sum_ite_eq' + convBiasGrad_eq_sum) to the spatial SUM the float bias gradient rounds.

                                    noncomputable def Proofs.FloatModel.cnnConv1BiasGradBudget (M : FloatModel) (ic c h w d₃ d₄ nC kH kW : ℕ) (a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ) :

                                    The conv-1 bias-gradient grad-close budget — cnnConv1GradBudget with the a· input factors stripped (the bias Jacobian carries no input window): the spatial sum's Higham γ over (2h)·(2w) against the float conv-1 cotangent magnitude C1t = c(2h)(2w)·w₂·CP + eback plus the per-entry drift eback (the conv-2 backward budget). Reuses the factored cnnConv2CotMag /cnnConv2CotBudget at the FLOAT conv-2 input (aX2 = A₁, eX2 = E₁).

                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For
                                      theorem Proofs.cnn_conv1_bias_grad_close {ic c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) {a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₁ : 0 ≤ w₁) (hβ₁ : 0 ≤ β₁) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx₀ : ∀ (ci : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ ci i j| ≤ a) (hW₁ : ∀ (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW), |W₁ o cc kh kw| ≤ w₁) (hb₁ : ∀ (o : Fin c), |b₁ o| ≤ β₁) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmargin1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0 < |(conv2d W₁ b₁ x₀).flatten k|) (hmargin2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a))) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)))) q|) (o : Fin c) :
                                      |M.cnnConv1BiasFloatGrad W₁ b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ fexp label o - gradAt (fun (b' : Vec c) => crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b' x₀).flatten))).flatten))))))) label) b₁ o| ≤ M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp

                                      The binary32 conv-1 BIAS gradient is within an explicit budget of the certified one — the bias peer of cnn_conv1_grad_close, built on the factored conv-2 cotangent chain at the FLOAT conv-2 input relu(z̃₁) (cnn_conv2_cot_close), the conv-2 backward convTap_back_close, the conv-1 ReLU-mask freeze (mask_scalar_close), and the spatial-SUM core sum_perturbed_close. Five quantitative margins freeze the routing; the bridge cnn_conv1_bias_loss_gradAt_reluMask turns the gradAt into the sum.

                                      theorem Proofs.cnn_conv1_bias_float_sgd_descends {ic c h w d₃ d₄ nC kH kW : ℕ} (M : FloatModel) (W₁ : Kernel4 c ic kH kW) (b₁ : Vec c) (x₀ : Tensor3 ic (2 * h) (2 * w)) (W₂ : Kernel4 c c kH kW) (b₂ : Vec c) (W₃ : Mat (c * h * w) d₃) (b₃ : Vec d₃) (W₄ : Mat d₃ d₄) (b₄ : Vec d₄) (W₅ : Mat d₄ nC) (b₅ : Vec nC) (label : Fin nC) (fexp : ℝ → ℝ) {lr a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp : ℝ} (hc : 0 < c) (hh : 0 < h) (hw : 0 < w) (ha : 0 ≤ a) (hw₁ : 0 ≤ w₁) (hβ₁ : 0 ≤ β₁) (hw₂ : 0 ≤ w₂) (hβ₂ : 0 ≤ β₂) (hw₃ : 0 ≤ w₃) (hβ₃ : 0 ≤ β₃) (hw₄ : 0 ≤ w₄) (hβ₄ : 0 ≤ β₄) (hw₅ : 0 ≤ w₅) (hβ₅ : 0 ≤ β₅) (hlr : 0 ≤ lr) (heexp0 : 0 ≤ eexp) (heexp1 : eexp ≤ 1) (hfexp : ∀ (t : ℝ), |fexp t - Real.exp t| ≤ eexp * Real.exp t) (hρ1 : FloatModel.smRho M.u eexp nC < 1) (hx : ∀ (cc : Fin ic) (i : Fin (2 * h)) (j : Fin (2 * w)), |x₀ cc i j| ≤ a) (hW₁ : ∀ (o : Fin c) (cc : Fin ic) (kh : Fin kH) (kw : Fin kW), |W₁ o cc kh kw| ≤ w₁) (hb₁ : ∀ (o : Fin c), |b₁ o| ≤ β₁) (hW₂ : ∀ (o cc : Fin c) (kh : Fin kH) (kw : Fin kW), |W₂ o cc kh kw| ≤ w₂) (hb₂ : ∀ (o : Fin c), |b₂ o| ≤ β₂) (hW₃ : ∀ (i : Fin (c * h * w)) (j : Fin d₃), |W₃ i j| ≤ w₃) (hb₃ : ∀ (j : Fin d₃), |b₃ j| ≤ β₃) (hW₄ : ∀ (i : Fin d₃) (j : Fin d₄), |W₄ i j| ≤ w₄) (hb₄ : ∀ (j : Fin d₄), |b₄ j| ≤ β₄) (hW₅ : ∀ (i : Fin d₄) (j : Fin nC), |W₅ i j| ≤ w₅) (hb₅ : ∀ (j : Fin nC), |b₅ j| ≤ β₅) (hmargin1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0 < |(conv2d W₁ b₁ x₀).flatten k|) (hmargin2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten k|) (hmarginPool : MaxPool2MarginQ (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))) (hmargin3 : ∀ (l : Fin d₃), FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0)) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)) l|) (hmargin4 : ∀ (q : Fin d₄), FloatModel.layerBudget M.u d₃ w₄ β₄ (FloatModel.layerAct (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a))) (FloatModel.layerBudget M.u (c * h * w) w₃ β₃ (FloatModel.layerAct (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a)) (FloatModel.layerBudget M.u (c * kH * kW) w₂ β₂ (FloatModel.layerAct (ic * kH * kW) w₁ β₁ a) (FloatModel.layerBudget M.u (ic * kH * kW) w₁ β₁ a 0))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)))) q|) (hm1 : ∀ (k : Fin (c * (2 * h) * (2 * w))), lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) < |(conv2d W₁ b₁ x₀).flatten k|) (hm2 : ∀ (k : Fin (c * (2 * h) * (2 * w))), ↑(c * kH * kW) * (w₂ * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))) < |(conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten k|) (hmq : MaxPool2MarginQ (↑(c * kH * kW) * (w₂ * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)))) (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))) (hm3 : ∀ (l : Fin d₃), w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))) < |dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)) l|) (hm4 : ∀ (q : Fin d₄), w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))))) < |dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten)))) q|) (hsmall : 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp)))))))))) < 1) (h1 : lr * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp * ∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| ≤ (lr * ∑ idx : Fin c, gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx ^ 2) / 4) (h2 : 2 * ↑nC * ↑(2 * h * (2 * w)) ^ 2 * ↑(c * kH * kW) ^ 2 * ↑d₃ ^ 2 * ↑d₄ ^ 2 * w₂ ^ 2 * w₃ ^ 2 * w₄ ^ 2 * w₅ ^ 2 / (1 - 2 * (w₅ * (↑d₄ * (w₄ * (↑d₃ * (w₃ * (↑(c * kH * kW) * (w₂ * (↑(2 * h * (2 * w)) * (lr * (∑ idx : Fin c, |gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx| + ↑c * M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp))))))))))) * stepRadius (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ lr (M.cnnConv1BiasGradBudget ic c h w d₃ d₄ nC kH kW a w₁ β₁ w₂ β₂ w₃ β₃ w₄ β₄ w₅ β₅ eexp) ^ 2 ≤ (lr * ∑ idx : Fin c, gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx ^ 2) / 4) :
                                      cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label (b₁ - lr • M.cnnConv1BiasFloatGrad W₁ b₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ fexp label) ≤ crossEntropy nC (dense W₅ b₅ (relu d₄ (dense W₄ b₄ (relu d₃ (dense W₃ b₃ (maxPoolFlat c h w (relu (c * (2 * h) * (2 * w)) (conv2d W₂ b₂ (Tensor3.unflatten (relu (c * (2 * h) * (2 * w)) (conv2d W₁ b₁ x₀).flatten))).flatten))))))) label - (lr * ∑ idx : Fin c, gradAt (cnnConv1BiasLoss W₁ x₀ W₂ b₂ W₃ b₃ W₄ b₄ W₅ b₅ label) b₁ idx ^ 2) / 2

                                      One SGD step with the FloatModel binary32 conv-1 bias gradient decreases one example's cross-entropy loss; the gradient's accuracy is proven, not assumed — the bias peer of cnn_conv1_float_sgd_descends, the deepest descent rung: the gradient is the FloatModel binary32 bias gradient M.cnnConv1BiasFloatGrad …, accuracy proven by cnn_conv1_bias_grad_close (η := cnnConv1BiasGradBudget, discharged per output channel — the bias IS a vector), not assumed. With this, both conv kernels and both conv biases of the Chapter-3 CNN have a float-gradient descent statement. Scope: one example, b₁ moving, update taken in ℝ.