Documentation

LeanMlir.Proofs.Nets.Small.MlpFoldB

The MNIST-MLP train step at batch N — MlpFold with the batch stated #

MlpFold certifies the six parameter outputs of mlp_train_step.mlir for ONE example. tests/TestSmallNetsBatchedEmit.lean pins that same text as the print of a graph at the batched index — batchOp lifts of dense/relu/expe/softmaxDiv/dotOut, subB, selectPosB on the whole-batch pre-activations, and the denseWeightSgdB/denseBiasSgdB nodes — so every node's den can be read at a batch of N examples. This file does that reading:

The chain cotangents are node-local, as in MlpFold: each parameter node is stated with its cotangent input as an .operand leaf carrying the den of the batched backward subgraph, which the slice lemmas pin. Scope otherwise as MlpFold (per-op pretty lexing; ℝ → Float32).

Per-example shorthands, at example k of the batch #

@[reducible, inline]
noncomputable abbrev Proofs.MlpFoldB.xk {d₀ : ℕ} (N : ℕ) (xB : Vec (N * d₀)) (k : Fin N) :
Vec d₀

Example k's input.

Equations
Instances For
    @[reducible, inline]
    noncomputable abbrev Proofs.MlpFoldB.p0 {d₀ d₁ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (xB : Vec (N * d₀)) (k : Fin N) :
    Vec d₁

    Layer-0 pre-activation at example k.

    Equations
    Instances For
      @[reducible, inline]
      noncomputable abbrev Proofs.MlpFoldB.p1 {d₀ d₁ d₂ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (xB : Vec (N * d₀)) (k : Fin N) :
      Vec d₂

      Layer-1 pre-activation at example k.

      Equations
      Instances For
        @[reducible, inline]
        noncomputable abbrev Proofs.MlpFoldB.gk {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (k : Fin N) :
        Vec d₃

        The softmax-CE loss cotangent at example k: softmax(logitsₖ) − onehotₖ.

        Equations
        Instances For

          The batched graph, piece by piece (the pieces mlpTrainStepText renders) #

          def Proofs.MlpFoldB.preB0 {d₀ d₁ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (xB : Vec (N * d₀)) :
          StableHLO.SHlo (N * d₁)
          Equations
          Instances For
            def Proofs.MlpFoldB.actB0 {d₀ d₁ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (xB : Vec (N * d₀)) :
            StableHLO.SHlo (N * d₁)
            Equations
            Instances For
              def Proofs.MlpFoldB.preB1 {d₀ d₁ d₂ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (xB : Vec (N * d₀)) :
              StableHLO.SHlo (N * d₂)
              Equations
              Instances For
                def Proofs.MlpFoldB.actB1 {d₀ d₁ d₂ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (xB : Vec (N * d₀)) :
                StableHLO.SHlo (N * d₂)
                Equations
                Instances For
                  def Proofs.MlpFoldB.logitsB {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) :
                  StableHLO.SHlo (N * d₃)
                  Equations
                  Instances For
                    noncomputable def Proofs.MlpFoldB.cotB {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) :
                    StableHLO.SHlo (N * d₃)

                    The batched loss cotangent sub(softmaxDiv(expe(logits)), onehot).

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For
                      theorem Proofs.MlpFoldB.preB0_slice {d₀ d₁ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (xB : Vec (N * d₀)) (k : Fin N) :
                      StableHLO.batchSlice N d₁ (StableHLO.den (preB0 N W₀ b₀ xB)) k = p0 N W₀ b₀ xB k
                      theorem Proofs.MlpFoldB.actB0_slice {d₀ d₁ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (xB : Vec (N * d₀)) (k : Fin N) :
                      StableHLO.batchSlice N d₁ (StableHLO.den (actB0 N W₀ b₀ xB)) k = relu d₁ (p0 N W₀ b₀ xB k)
                      theorem Proofs.MlpFoldB.preB1_slice {d₀ d₁ d₂ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (xB : Vec (N * d₀)) (k : Fin N) :
                      StableHLO.batchSlice N d₂ (StableHLO.den (preB1 N W₀ b₀ W₁ b₁ xB)) k = p1 N W₀ b₀ W₁ b₁ xB k
                      theorem Proofs.MlpFoldB.actB1_slice {d₀ d₁ d₂ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (xB : Vec (N * d₀)) (k : Fin N) :
                      StableHLO.batchSlice N d₂ (StableHLO.den (actB1 N W₀ b₀ W₁ b₁ xB)) k = relu d₂ (p1 N W₀ b₀ W₁ b₁ xB k)
                      theorem Proofs.MlpFoldB.logitsB_slice {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (k : Fin N) :
                      StableHLO.batchSlice N d₃ (StableHLO.den (logitsB N W₀ b₀ W₁ b₁ W₂ b₂ xB)) k = mnistLinear W₂ b₂ (relu d₂ (p1 N W₀ b₀ W₁ b₁ xB k))
                      theorem Proofs.MlpFoldB.cotB_slice {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (k : Fin N) (j : Fin d₃) :
                      StableHLO.den (cotB N W₀ b₀ W₁ b₁ W₂ b₂ xB label) (finProdFinEquiv (k, j)) = gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k j

                      Example k's slice of the batched loss cotangent is softmax(logitsₖ) − onehotₖ.

                      theorem Proofs.MlpFoldB.batchSlice_cotB {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (k : Fin N) :
                      StableHLO.batchSlice N d₃ (StableHLO.den (cotB N W₀ b₀ W₁ b₁ W₂ b₂ xB label)) k = gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k

                      The backward chain: selectPosB on the whole-batch pre-activation over a dotOut lift #

                      noncomputable def Proofs.MlpFoldB.cot1B {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (p₁N dyN : String) :
                      StableHLO.SHlo (N * d₂)

                      Layer-1 batched chain cotangent selectPosB p₁ (dotOut W₂ dy), dy the batched loss cotangent as an operand leaf.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For
                        theorem Proofs.MlpFoldB.cot1B_slice {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (p₁N dyN : String) (k : Fin N) :
                        StableHLO.batchSlice N d₂ (StableHLO.den (cot1B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₁N dyN)) k = (IR.mlpCotOut1 W₂ (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k)

                        Its slice at example k is the per-example mlpCotOut1 at that example's cotangent.

                        noncomputable def Proofs.MlpFoldB.cot0B {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (p₀N p₁N dyN c₁N : String) :
                        StableHLO.SHlo (N * d₁)

                        Layer-0 batched chain cotangent selectPosB p₀ (dotOut W₁ c₁), c₁ the layer-1 chain cotangent as an operand leaf.

                        Equations
                        • One or more equations did not get rendered due to their size.
                        Instances For
                          theorem Proofs.MlpFoldB.cot0B_slice {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (p₀N p₁N dyN c₁N : String) (k : Fin N) :
                          StableHLO.batchSlice N d₁ (StableHLO.den (cot0B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₀N p₁N dyN c₁N)) k = (IR.mlpCotOut0 W₁ W₂ (p0 N W₀ b₀ xB k) (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k)

                          The six parameter nodes at batch N #

                          theorem Proofs.MlpFoldB.w2B_tied {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (aN lrStr dyN : String) (lr : ℝ) (i : Fin d₂) (j : Fin d₃) :
                          StableHLO.den (StableHLO.SHlo.denseWeightSgdB aN "%W2" lrStr (StableHLO.den (actB1 N W₀ b₀ W₁ b₁ xB)) W₂ lr (StableHLO.SHlo.operand dyN (StableHLO.den (cotB N W₀ b₀ W₁ b₁ W₂ b₂ xB label)))) (finProdFinEquiv (i, j)) = W₂ i j - lr * ∑ k : Fin N, pdiv (fun (v : Vec (d₂ * d₃)) (x : Fin 1) => crossEntropy d₃ (dense (Mat.unflatten v) b₂ (relu d₂ (p1 N W₀ b₀ W₁ b₁ xB k))) (label k)) W₂.flatten (finProdFinEquiv (i, j)) 0

                          Output weight, at the WHOLE loss, summed over the batch.

                          theorem Proofs.MlpFoldB.b2B_tied {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (lrStr dyN : String) (lr : ℝ) (j : Fin d₃) :
                          StableHLO.den (StableHLO.SHlo.denseBiasSgdB "%b2" lrStr b₂ lr (StableHLO.SHlo.operand dyN (StableHLO.den (cotB N W₀ b₀ W₁ b₁ W₂ b₂ xB label)))) j = b₂ j - lr * ∑ k : Fin N, ∑ i : Fin d₃, pdiv (fun (b' : Vec d₃) => dense W₂ b' (relu d₂ (p1 N W₀ b₀ W₁ b₁ xB k))) b₂ j i * gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k i

                          Output bias.

                          theorem Proofs.MlpFoldB.w1B_tied {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (aN lrStr p₁N dyN c₁N : String) (lr : ℝ) (i : Fin d₁) (j : Fin d₂) :
                          StableHLO.den (StableHLO.SHlo.denseWeightSgdB aN "%W1" lrStr (StableHLO.den (actB0 N W₀ b₀ xB)) W₁ lr (StableHLO.SHlo.operand c₁N (StableHLO.den (cot1B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₁N dyN)))) (finProdFinEquiv (i, j)) = W₁ i j - lr * ∑ k : Fin N, ∑ k' : Fin d₂, pdiv (fun (v : Vec (d₁ * d₂)) => dense (Mat.unflatten v) b₁ (relu d₁ (p0 N W₀ b₀ xB k))) W₁.flatten (finProdFinEquiv (i, j)) k' * (IR.mlpCotOut1 W₂ (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) k'

                          Hidden weight W₁, at the layer-1 chain cotangent.

                          theorem Proofs.MlpFoldB.b1B_tied {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (lrStr p₁N dyN c₁N : String) (lr : ℝ) (j : Fin d₂) :
                          StableHLO.den (StableHLO.SHlo.denseBiasSgdB "%b1" lrStr b₁ lr (StableHLO.SHlo.operand c₁N (StableHLO.den (cot1B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₁N dyN)))) j = b₁ j - lr * ∑ k : Fin N, ∑ i : Fin d₂, pdiv (fun (b' : Vec d₂) => dense W₁ b' (relu d₁ (p0 N W₀ b₀ xB k))) b₁ j i * (IR.mlpCotOut1 W₂ (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) i

                          Hidden bias b₁.

                          theorem Proofs.MlpFoldB.w0B_tied {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (lrStr p₀N p₁N dyN c₁N c₀N : String) (lr : ℝ) (i : Fin d₀) (j : Fin d₁) :
                          StableHLO.den (StableHLO.SHlo.denseWeightSgdB "%x" "%W0" lrStr xB W₀ lr (StableHLO.SHlo.operand c₀N (StableHLO.den (cot0B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₀N p₁N dyN c₁N)))) (finProdFinEquiv (i, j)) = W₀ i j - lr * ∑ k : Fin N, ∑ k' : Fin d₁, pdiv (fun (v : Vec (d₀ * d₁)) => dense (Mat.unflatten v) b₀ (xk N xB k)) W₀.flatten (finProdFinEquiv (i, j)) k' * (IR.mlpCotOut0 W₁ W₂ (p0 N W₀ b₀ xB k) (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) k'

                          Input weight W₀, at the layer-0 chain cotangent.

                          theorem Proofs.MlpFoldB.b0B_tied {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (lrStr p₀N p₁N dyN c₁N c₀N : String) (lr : ℝ) (j : Fin d₁) :
                          StableHLO.den (StableHLO.SHlo.denseBiasSgdB "%b0" lrStr b₀ lr (StableHLO.SHlo.operand c₀N (StableHLO.den (cot0B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₀N p₁N dyN c₁N)))) j = b₀ j - lr * ∑ k : Fin N, ∑ i : Fin d₁, pdiv (fun (b' : Vec d₁) => dense W₀ b' (xk N xB k)) b₀ j i * (IR.mlpCotOut0 W₁ W₂ (p0 N W₀ b₀ xB k) (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) i

                          Input bias b₀.

                          theorem Proofs.MlpFoldB.mlp_train_step_tiedB {d₀ d₁ d₂ d₃ : ℕ} (N : ℕ) (W₀ : Mat d₀ d₁) (b₀ : Vec d₁) (W₁ : Mat d₁ d₂) (b₁ : Vec d₂) (W₂ : Mat d₂ d₃) (b₂ : Vec d₃) (xB : Vec (N * d₀)) (label : Fin N → Fin d₃) (lrStr aN a₀N p₀N p₁N dyN c₁N c₀N : String) (lr : ℝ) :
                          (∀ (i : Fin d₂) (j : Fin d₃), StableHLO.den (StableHLO.SHlo.denseWeightSgdB aN "%W2" lrStr (StableHLO.den (actB1 N W₀ b₀ W₁ b₁ xB)) W₂ lr (StableHLO.SHlo.operand dyN (StableHLO.den (cotB N W₀ b₀ W₁ b₁ W₂ b₂ xB label)))) (finProdFinEquiv (i, j)) = W₂ i j - lr * ∑ k : Fin N, pdiv (fun (v : Vec (d₂ * d₃)) (x : Fin 1) => crossEntropy d₃ (dense (Mat.unflatten v) b₂ (relu d₂ (p1 N W₀ b₀ W₁ b₁ xB k))) (label k)) W₂.flatten (finProdFinEquiv (i, j)) 0) ∧ (∀ (j : Fin d₃), StableHLO.den (StableHLO.SHlo.denseBiasSgdB "%b2" lrStr b₂ lr (StableHLO.SHlo.operand dyN (StableHLO.den (cotB N W₀ b₀ W₁ b₁ W₂ b₂ xB label)))) j = b₂ j - lr * ∑ k : Fin N, ∑ i : Fin d₃, pdiv (fun (b' : Vec d₃) => dense W₂ b' (relu d₂ (p1 N W₀ b₀ W₁ b₁ xB k))) b₂ j i * gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k i) ∧ (∀ (i : Fin d₁) (j : Fin d₂), StableHLO.den (StableHLO.SHlo.denseWeightSgdB a₀N "%W1" lrStr (StableHLO.den (actB0 N W₀ b₀ xB)) W₁ lr (StableHLO.SHlo.operand c₁N (StableHLO.den (cot1B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₁N dyN)))) (finProdFinEquiv (i, j)) = W₁ i j - lr * ∑ k : Fin N, ∑ k' : Fin d₂, pdiv (fun (v : Vec (d₁ * d₂)) => dense (Mat.unflatten v) b₁ (relu d₁ (p0 N W₀ b₀ xB k))) W₁.flatten (finProdFinEquiv (i, j)) k' * (IR.mlpCotOut1 W₂ (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) k') ∧ (∀ (j : Fin d₂), StableHLO.den (StableHLO.SHlo.denseBiasSgdB "%b1" lrStr b₁ lr (StableHLO.SHlo.operand c₁N (StableHLO.den (cot1B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₁N dyN)))) j = b₁ j - lr * ∑ k : Fin N, ∑ i : Fin d₂, pdiv (fun (b' : Vec d₂) => dense W₁ b' (relu d₁ (p0 N W₀ b₀ xB k))) b₁ j i * (IR.mlpCotOut1 W₂ (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) i) ∧ (∀ (i : Fin d₀) (j : Fin d₁), StableHLO.den (StableHLO.SHlo.denseWeightSgdB "%x" "%W0" lrStr xB W₀ lr (StableHLO.SHlo.operand c₀N (StableHLO.den (cot0B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₀N p₁N dyN c₁N)))) (finProdFinEquiv (i, j)) = W₀ i j - lr * ∑ k : Fin N, ∑ k' : Fin d₁, pdiv (fun (v : Vec (d₀ * d₁)) => dense (Mat.unflatten v) b₀ (xk N xB k)) W₀.flatten (finProdFinEquiv (i, j)) k' * (IR.mlpCotOut0 W₁ W₂ (p0 N W₀ b₀ xB k) (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) k') ∧ ∀ (j : Fin d₁), StableHLO.den (StableHLO.SHlo.denseBiasSgdB "%b0" lrStr b₀ lr (StableHLO.SHlo.operand c₀N (StableHLO.den (cot0B N W₀ b₀ W₁ b₁ W₂ b₂ xB label p₀N p₁N dyN c₁N)))) j = b₀ j - lr * ∑ k : Fin N, ∑ i : Fin d₁, pdiv (fun (b' : Vec d₁) => dense W₀ b' (xk N xB k)) b₀ j i * (IR.mlpCotOut0 W₁ W₂ (p0 N W₀ b₀ xB k) (p1 N W₀ b₀ W₁ b₁ xB k)).denote (gk N W₀ b₀ W₁ b₁ W₂ b₂ xB label k) i

                          Whole MLP train step at batch N, tied. The output weight denotes W₂ − lr·Σₖ ∂CE/∂W₂ at the whole loss of each example; the other five denote θ − lr·Σₖ (certified per-layer Jacobian at example k · that example's rendered chain cotangent), the chain cotangents being the slices of the emitted selectPosB/dotOut subgraphs (cot1B_slice, cot0B_slice).