Documentation

LeanMlir.Proofs.Architectures.ConvGrad

Convolution parameter-gradient bridges (the MNIST CNN train step's conv parameters) #

The MNIST CNN (conv → relu → conv → relu → maxpool → dense → relu → dense → relu → dense) train step has two kinds of parameters: the dense classifier head (whose grads reuse IR.weight_grad_bridge/IR.bias_grad_bridge) and the convolution kernels/biases, whose gradient is a correlation, not an outer product. This file supplies the conv analogue of the dense bridges.

As for the MLP, the cotangent the backward chain delivers at each conv layer's output flows through a backward graph — here the Tensor3-level IR.Back3 (convBackDenote, maxPoolBackDenote, with IR.denote_subst3 the chain rule), exactly as the MLP used IR.Back (mlpCotOut0/mlpCotOut1). Given that cotangent c, the conv kernel and bias gradients (the transpose-trick conv2dWeightGrad/conv2dBiasGrad) are the certified Jacobian of conv2d — as a function of the flattened kernel / of the bias — contracted with c. Both bridges are the .correct field of the proven conv parameter VJPs (conv2dWeightGradHasVJP/conv2dBiasGradHasVJP). The statements are about those witnesses' backwards; no rendered text appears in them. The link from a rendered conv gradient op to these witnesses is that op's den theorem (see CnnFold).

With the dense bridges in IR and the Back3 cotangent chain, this gives a bridge for every parameter of the CNN train step. (The SGD wrapping θ − lr·∇ is identical to the linear/MLP case.)

The next section adds the same bridges for the depthwise bias and the stride-2 conv kernel and bias, which the MobileNetV2, ResNet-34 and ConvNeXt fold ties use.

The rest are the conv's Jacobians in closed form and its drifts, read off the same certified VJPs: the kernel map (conv2d_weight_pdiv, the drift conv2d_kernel_drift_sum), the input map (the kernel tap convTap, conv2d_input_pdiv3, the locality bound convTap_out_l1 and the drift conv2d_input_l1_drift) and the bias map (conv2d_bias_pdiv, conv2d_flat_bias_drift_sum), with the weight and bias gradients as a flat dot and sum (convWeightGrad_eq_dot, convBiasGrad_eq_sum). The MNIST CNN descent rungs (SgdDescent.Cnn) consume them.

theorem Proofs.conv_weight_grad_bridge {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) (v : Vec (oc * ic * kH * kW)) (c : Vec (oc * h * w)) (idx : Fin (oc * ic * kH * kW)) :
(conv2dWeightGradHasVJP b x).backward v c idx = ∑ j : Fin (oc * h * w), pdiv (fun (v' : Vec (oc * ic * kH * kW)) => (conv2d (Kernel4.unflatten v') b x).flatten) v idx j * c j

Conv weight-gradient bridge. At any cotangent c at the conv layer's output (and any kernel point v = Kernel4.flatten W), the backward of conv2dWeightGradHasVJP (the transpose-trick kernel gradient) equals the certified Jacobian of conv2d viewed as a function of the flattened kernel, contracted with c. The convolution analogue of IR.weight_grad_bridge; it is the .correct field of conv2dWeightGradHasVJP.

theorem Proofs.conv_bias_grad_bridge {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (x : Tensor3 ic h w) (b : Vec oc) (c : Vec (oc * h * w)) (o : Fin oc) :
(conv2dBiasGradHasVJP W x).backward b c o = ∑ j : Fin (oc * h * w), pdiv (fun (b' : Vec oc) => (conv2d W b' x).flatten) b o j * c j

Conv bias-gradient bridge. Likewise the conv bias gradient (db[o] = Σ spatial c) is the certified Jacobian of conv2d wrt the bias, contracted with c — the .correct field of conv2dBiasGradHasVJP.

theorem Proofs.conv_weight_sgd_certified {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Tensor3 ic h w) (v : Vec (oc * ic * kH * kW)) (c : Vec (oc * h * w)) (lr : ℝ) (idx : Fin (oc * ic * kH * kW)) :
v idx - lr * (conv2dWeightGradHasVJP b x).backward v c idx = v idx - lr * ∑ j : Fin (oc * h * w), pdiv (fun (v' : Vec (oc * ic * kH * kW)) => (conv2d (Kernel4.unflatten v') b x).flatten) v idx j * c j

Conv weight SGD step — SGD form of conv_weight_grad_bridge. At the flattened kernel v, v − lr·(conv2dWeightGradHasVJP backward at c) equals v − lr·(certified ∂conv/∂kernel · c). A rewrite by the bridge; no rendered text appears in the statement.

theorem Proofs.conv_bias_sgd_certified {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (x : Tensor3 ic h w) (b : Vec oc) (c : Vec (oc * h * w)) (lr : ℝ) (o : Fin oc) :
b o - lr * (conv2dBiasGradHasVJP W x).backward b c o = b o - lr * ∑ j : Fin (oc * h * w), pdiv (fun (b' : Vec oc) => (conv2d W b' x).flatten) b o j * c j

Conv bias SGD step — SGD form of conv_bias_grad_bridge. Likewise b − lr·(conv2dBiasGradHasVJP backward at c) equals b − lr·(certified ∂conv/∂bias · c).

theorem Proofs.depthwise_bias_sgd_certified {c h w kH kW : ℕ} (W : DepthwiseKernel c kH kW) (x : Tensor3 c h w) (b : Vec c) (dy : Vec (c * h * w)) (lr : ℝ) (cc : Fin c) :
b cc - lr * (depthwiseBiasGradHasVJP W x).backward b dy cc = b cc - lr * ∑ j : Fin (c * h * w), pdiv (fun (b' : Vec c) => (depthwiseConv2d W b' x).flatten) b cc j * dy j

Depthwise bias output, certified. Likewise bⁿ = b − lr·(spatial reduce) denotes b − lr·(certified ∂(depthwiseConv2d)/∂b · cotangent).

theorem Proofs.convStride2_weight_sgd_certified {ic oc h w kH kW : ℕ} (b : Vec oc) (x : Vec (ic * (2 * h) * (2 * w))) (v : Vec (oc * ic * kH * kW)) (dy : Vec (oc * h * w)) (lr : ℝ) (i : Fin (oc * ic * kH * kW)) :
v i - lr * (flatConvStride2WeightGradHasVJP b x).backward v dy i = v i - lr * ∑ j : Fin (oc * h * w), pdiv (fun (v' : Vec (oc * ic * kH * kW)) => flatConvStride2 (Kernel4.unflatten v') b x) v i j * dy j

Stem conv weight output, certified. sWⁿ = sW − lr·(strided transpose-trick grad) denotes sW − lr·(certified ∂(flatConvStride2)/∂sW · cotangent), via flatConvStride2WeightGradHasVJP (the ch6 strided conv weight VJP).

theorem Proofs.convStride2_bias_sgd_certified {ic oc h w kH kW : ℕ} (W : Kernel4 oc ic kH kW) (x : Vec (ic * (2 * h) * (2 * w))) (b : Vec oc) (dy : Vec (oc * h * w)) (lr : ℝ) (o : Fin oc) :
b o - lr * (flatConvStride2BiasGradHasVJP W x).backward b dy o = b o - lr * ∑ j : Fin (oc * h * w), pdiv (fun (b' : Vec oc) => flatConvStride2 W b' x) b o j * dy j

Stem conv bias output, certified. sbⁿ = sb − lr·(spatial reduce) denotes sb − lr·(certified ∂(flatConvStride2)/∂sb · cotangent).

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.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.

      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.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.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.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.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.