Documentation

LeanMlir.Proofs.Nets.ResNet.ResNet50FullBVJP

ResNet-50's whole-net input-VJP at TRUE BATCH-NORM #

ResNet50FullB.lean states the batch-BN forward at the [3,4,6,3] bottleneck ladder. This file gives that forward a certified HasVJPAt.

No new mathematics, and nothing new one tier down #

Every block VJP is already proven at bnBatchLA: r50BottleneckBHasVJPAt, r50ProjBlockBHasVJPAt and r50DownBlockBHasVJPAt (ResNet50BackB0.lean) are exactly the three shapes r50IdB / r50ProjB / r50DownB unfold to. The bundle lemmas below are delegations in ResNet34FullBVJP.lean's style, and the whole net is those blocks' CertLayers composed.

No Foundation lemma of its own. ResNet-50 has ResNet-34's stem and reuses r34StemBHasVJPAt (which lifts the stem pool with batchMapHasVJPAt) verbatim. The head is ResNet-34's too (r34HeadBHasVJP, GLOBAL: GAP and dense are smooth and each is batchMap of a per-example op, so no hypothesis appears).

The hypothesis budget #

Pointwise (HasVJPAt), not global, and necessarily. relu is kinked. And a BOTTLENECK carries THREE kink clauses, where ResNet-34's basic block carries two: the two interior relus and the post-residual OUTER relu. Sixteen blocks give 48 clauses, plus the stem's relu and the stem pool's no-tie condition — bundled per block into R50IdSmoothAt / R50ProjSmoothAt / R50DownSmoothAt, and those 18 bundles into one R50SmoothAtB (the positivity bundles into R50PosB), so the apex binds two hypotheses, as MobileNetV2's does.

The pool's condition is per example (StemPoolSmoothAt, reused): a tie is a property of one image's 3×3 window, not of the batch.

No 0 < q is needed: the stem is certified as one layer (stemReluPoolLayer), whose VJP holds on an empty output grid too.

The running activations are named r50Pre0 … r50Pre16 so each bundle can be STATED at the activation entering its block without a sixteen-deep nested application inline; r50Pre16 doubles as the trunk, and resnet50ForwardBFull_eq_chain bridges it back to the committed nested-application forward.

N and q are both variables (the widths are literals), so ONE statement covers resnet50in_fwd (q = 7, 224 px) and resnet50in160_fwd (q = 5, 160 px) at every batch size.

structure Proofs.R50IdPos {mid oc : ℕ} (p : R50IdW mid oc) :

All three BatchNorm epsilons of an identity bottleneck are positive.

Instances For
    structure Proofs.R50ProjPos {ic mid oc : ℕ} (p : R50ProjW ic mid oc) :

    All four BatchNorm epsilons of a projection bottleneck are positive (body three, skip one). One bundle for BOTH projection forms, as R50ProjW is one record for both.

    Instances For
      structure Proofs.R50IdSmoothAt (N h w : ℕ) {mid oc : ℕ} (p : R50IdW mid oc) (v : Vec (N * (oc * h * w))) :

      The THREE relu sites of an identity bottleneck are away from the kink at v: the 1×1 reduce's BN output, the 3×3's BN output, and the post-residual sum. The 1×1 expand has no activation.

      Instances For
        structure Proofs.R50ProjSmoothAt (N h w : ℕ) {ic mid oc : ℕ} (p : R50ProjW ic mid oc) (v : Vec (N * (ic * h * w))) :

        The three relu sites of the STRIDE-1 projection bottleneck at v. Identical to the identity block's except that the outer relu sits at the PROJECTED residual — both paths nontrivial.

        Instances For
          structure Proofs.R50DownSmoothAt (N h w : ℕ) {ic mid oc : ℕ} (p : R50ProjW ic mid oc) (v : Vec (N * (ic * (2 * h) * (2 * w)))) :

          The three relu sites of the STRIDED projection bottleneck at v.

          v1.5: the FIRST relu is at the input resolution 2h × 2w and only the second is at h × w, because the stride is on the 3×3. Writing hm1 at h w typechecks nowhere, which is the one place a reader can get this shape wrong.

          Instances For
            noncomputable def Proofs.r50IdBHasVJPAt (N h w : ℕ) {mid oc : ℕ} (p : R50IdW mid oc) (hq : R50IdPos p) (v : Vec (N * (oc * h * w))) (hs : R50IdSmoothAt N h w p v) :
            HasVJPAt (r50IdB N h w p) v

            Identity bottleneck VJP — r50BottleneckBHasVJPAt at the bundle's fields.

            Equations
            Instances For
              noncomputable def Proofs.r50ProjBHasVJPAt (N h w : ℕ) {ic mid oc : ℕ} (p : R50ProjW ic mid oc) (hq : R50ProjPos p) (v : Vec (N * (ic * h * w))) (hs : R50ProjSmoothAt N h w p v) :
              HasVJPAt (r50ProjB N h w p) v

              Stride-1 projection bottleneck VJP — r50ProjBlockBHasVJPAt at the bundle's fields.

              Equations
              • One or more equations did not get rendered due to their size.
              Instances For
                noncomputable def Proofs.r50DownBHasVJPAt (N h w : ℕ) {ic mid oc : ℕ} (p : R50ProjW ic mid oc) (hq : R50ProjPos p) (v : Vec (N * (ic * (2 * h) * (2 * w)))) (hs : R50DownSmoothAt N h w p v) :
                HasVJPAt (r50DownB N h w p) v

                Strided projection bottleneck VJP — r50DownBlockBHasVJPAt at the bundle's fields.

                Equations
                • One or more equations did not get rendered due to their size.
                Instances For
                  noncomputable def Proofs.r50Pre0 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                  Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (64 * (2 * (2 * (2 * q))) * (2 * (2 * (2 * q)))))
                  Equations
                  Instances For
                    noncomputable def Proofs.r50Pre1 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                    Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (256 * (2 * (2 * (2 * q))) * (2 * (2 * (2 * q)))))
                    Equations
                    Instances For
                      noncomputable def Proofs.r50Pre2 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                      Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (256 * (2 * (2 * (2 * q))) * (2 * (2 * (2 * q)))))
                      Equations
                      Instances For
                        noncomputable def Proofs.r50Pre3 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                        Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (256 * (2 * (2 * (2 * q))) * (2 * (2 * (2 * q)))))
                        Equations
                        Instances For
                          noncomputable def Proofs.r50Pre4 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                          Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (512 * (2 * (2 * q)) * (2 * (2 * q))))
                          Equations
                          Instances For
                            noncomputable def Proofs.r50Pre5 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                            Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (512 * (2 * (2 * q)) * (2 * (2 * q))))
                            Equations
                            Instances For
                              noncomputable def Proofs.r50Pre6 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                              Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (512 * (2 * (2 * q)) * (2 * (2 * q))))
                              Equations
                              Instances For
                                noncomputable def Proofs.r50Pre7 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (512 * (2 * (2 * q)) * (2 * (2 * q))))
                                Equations
                                Instances For
                                  noncomputable def Proofs.r50Pre8 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                  Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (1024 * (2 * q) * (2 * q)))
                                  Equations
                                  Instances For
                                    noncomputable def Proofs.r50Pre9 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                    Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (1024 * (2 * q) * (2 * q)))
                                    Equations
                                    Instances For
                                      noncomputable def Proofs.r50Pre10 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                      Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (1024 * (2 * q) * (2 * q)))
                                      Equations
                                      Instances For
                                        noncomputable def Proofs.r50Pre11 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                        Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (1024 * (2 * q) * (2 * q)))
                                        Equations
                                        Instances For
                                          noncomputable def Proofs.r50Pre12 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                          Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (1024 * (2 * q) * (2 * q)))
                                          Equations
                                          Instances For
                                            noncomputable def Proofs.r50Pre13 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                            Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (1024 * (2 * q) * (2 * q)))
                                            Equations
                                            Instances For
                                              noncomputable def Proofs.r50Pre14 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                              Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (2048 * q * q))
                                              Equations
                                              Instances For
                                                noncomputable def Proofs.r50Pre15 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                                Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (2048 * q * q))
                                                Equations
                                                Instances For
                                                  noncomputable def Proofs.r50Pre16 (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) :
                                                  Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) → Vec (N * (2048 * q * q))
                                                  Equations
                                                  Instances For
                                                    structure Proofs.R50PosB {nCls : ℕ} (w : R50BWeights nCls) :

                                                    Every BatchNorm ε of the net is positive: the stem's and each bottleneck's bundle.

                                                    Instances For
                                                      structure Proofs.R50SmoothAtB (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :

                                                      Every relu is away from its kink and every stem-pool window is smooth or dead, each at the activation its block actually sees: the stem's clauses at the image, block k's at r50Pre(k-1). The head has none (GAP and dense are smooth).

                                                      Instances For
                                                        theorem Proofs.r50Pre0_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre0 N q w x = r34StemB N (2 * (2 * (2 * q))) (2 * (2 * (2 * q))) w.sW w.sb w.sε w.sγ w.sβ x
                                                        theorem Proofs.r50Pre1_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre1 N q w x = r50ProjB N (2 * (2 * (2 * q))) (2 * (2 * (2 * q))) w.s1b0 (r50Pre0 N q w x)
                                                        theorem Proofs.r50Pre2_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre2 N q w x = r50IdB N (2 * (2 * (2 * q))) (2 * (2 * (2 * q))) w.s1b1 (r50Pre1 N q w x)
                                                        theorem Proofs.r50Pre3_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre3 N q w x = r50IdB N (2 * (2 * (2 * q))) (2 * (2 * (2 * q))) w.s1b2 (r50Pre2 N q w x)
                                                        theorem Proofs.r50Pre4_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre4 N q w x = r50DownB N (2 * (2 * q)) (2 * (2 * q)) w.s2b0 (r50Pre3 N q w x)
                                                        theorem Proofs.r50Pre5_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre5 N q w x = r50IdB N (2 * (2 * q)) (2 * (2 * q)) w.s2b1 (r50Pre4 N q w x)
                                                        theorem Proofs.r50Pre6_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre6 N q w x = r50IdB N (2 * (2 * q)) (2 * (2 * q)) w.s2b2 (r50Pre5 N q w x)
                                                        theorem Proofs.r50Pre7_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre7 N q w x = r50IdB N (2 * (2 * q)) (2 * (2 * q)) w.s2b3 (r50Pre6 N q w x)
                                                        theorem Proofs.r50Pre8_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre8 N q w x = r50DownB N (2 * q) (2 * q) w.s3b0 (r50Pre7 N q w x)
                                                        theorem Proofs.r50Pre9_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre9 N q w x = r50IdB N (2 * q) (2 * q) w.s3b1 (r50Pre8 N q w x)
                                                        theorem Proofs.r50Pre10_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre10 N q w x = r50IdB N (2 * q) (2 * q) w.s3b2 (r50Pre9 N q w x)
                                                        theorem Proofs.r50Pre11_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre11 N q w x = r50IdB N (2 * q) (2 * q) w.s3b3 (r50Pre10 N q w x)
                                                        theorem Proofs.r50Pre12_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre12 N q w x = r50IdB N (2 * q) (2 * q) w.s3b4 (r50Pre11 N q w x)
                                                        theorem Proofs.r50Pre13_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre13 N q w x = r50IdB N (2 * q) (2 * q) w.s3b5 (r50Pre12 N q w x)
                                                        theorem Proofs.r50Pre14_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre14 N q w x = r50DownB N q q w.s4b0 (r50Pre13 N q w x)
                                                        theorem Proofs.r50Pre15_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre15 N q w x = r50IdB N q q w.s4b1 (r50Pre14 N q w x)
                                                        theorem Proofs.r50Pre16_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        r50Pre16 N q w x = r50IdB N q q w.s4b2 (r50Pre15 N q w x)
                                                        theorem Proofs.resnet50ForwardBFull_eq_chain (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                        resnet50ForwardBFull N q w x = (r34HeadB N q q w.Wd w.bd ∘ r50Pre16 N q w) x

                                                        The committed nested-application forward IS the layered chain the VJP is stated on — the ResNet-50 peer of resnet34ForwardBFull_eq_chain, and what lets the VJP be about resnet50ForwardBFull rather than about a re-spelling of it.

                                                        noncomputable def Proofs.r50NetLayer (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (hp : R50PosB w) :
                                                        StableHLO.CertLayer (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q))))))) (N * nCls)

                                                        ResNet-50 as one certified layer, at every batch size and resolution. Its .faithful is a whole-net backward graph, stem pool included, proven to denote the VJP.

                                                        Equations
                                                        • One or more equations did not get rendered due to their size.
                                                        Instances For
                                                          theorem Proofs.r50NetLayer_fwd_apply (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (hp : R50PosB w) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                          (r50NetLayer N q w hp).fwd x = resnet50ForwardBFull N q w x

                                                          The composed layer's forward IS the committed nested-application forward: peeled one comp at a time, then each layer's forward by its rfl lemma.

                                                          noncomputable def Proofs.resnet50ForwardBFullHasVJPAt (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (hp : R50PosB w) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) (hx : R50SmoothAtB N q w x) :
                                                          HasVJPAt (r34HeadB N q q w.Wd w.bd ∘ r50Pre16 N q w) x

                                                          ResNet-50 at TRUE BATCH-NORM has a certified input-VJP at a smooth point — all sixteen bottlenecks. r50NetLayer's .vjp, read at the layered chain, under two hypotheses: R50PosB (every ε > 0) and R50SmoothAtB (every relu clause and the stem pool's smooth-or-dead condition, each at its block's own input).

                                                          Pointwise, and necessarily: relu is kinked. Each block contributes THREE clauses — the two interior relus and the post-residual OUTER relu — where ResNet-34's basic block contributes two and EfficientNet's MBConv none.

                                                          The head takes no hypothesis at all, and N and q are both variables, so this covers the 224-px and 160-px artifacts at every batch size.

                                                          Equations
                                                          Instances For
                                                            theorem Proofs.resnet50ForwardBFullHasVJPAt_correct (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (hp : R50PosB w) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) (hx : R50SmoothAtB N q w x) (dy : Vec (N * nCls)) (i : Fin (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) :
                                                            (resnet50ForwardBFullHasVJPAt N q w hp x hx).backward dy i = ∑ j : Fin (N * nCls), pdiv (resnet50ForwardBFull N q w) x i j * dy j

                                                            Public correctness theorem: the sixteen-bottleneck batch-BN backward equals the pdiv-contracted Jacobian of resnet50ForwardBFull ITSELF — the committed nested-application forward ResNet50FullB.lean defines — not of the layered chain the VJP is assembled on. Tied back through resnet50ForwardBFull_eq_chain.

                                                            theorem Proofs.resnet50ForwardBFull_differentiableAt (N q : ℕ) {nCls : ℕ} (w : R50BWeights nCls) (hp : R50PosB w) (x : Vec (N * (3 * (2 * (2 * (2 * (2 * (2 * q))))) * (2 * (2 * (2 * (2 * (2 * q)))))))) (hx : R50SmoothAtB N q w x) :

                                                            The committed forward is differentiable at every smooth point — the layer's .diff. What the seal's seal_differentiableAt needs.