TorchLean API

NN.Spec.Models.Svm

Support Vector Machines (spec models) #

This file provides a small linear SVM baseline with explicit gradients.

PyTorch analogue:

There are two "layers" in this file:

Classic SVM literature often uses C for the weight on the hinge term. This implementation instead uses the equivalent primal form with an explicit L2 coefficient named lambda.

References:

Implementation status #

No API builder implements this model, and no theorem is proved about it. It is a reference definition only.

Linear SVM (primal) #

structure LinearSVM (p : ) (α : Type) [TorchLean.Storage α] :

Linear SVM parameters: a weight vector w and bias b.

We intentionally keep "training hyperparameters" (regularization strength, learning rate, etc.) out of the parameter record; those are choices about an optimizer, not part of the model itself.

  • Normal vector of the separating hyperplane.

  • b : α

    Bias, or intercept, of the separating hyperplane.

Instances For
    def LinearSVM.decision {α : Type} [TorchLean.Storage α] [Context α] {p : } (m : LinearSVM p α) (x : TorchLean.Tensor α [p]) :
    α

    Decision function f(x) = w·x + b.

    Instances For

      Batch decision values for X : (n×p).

      Instances For
        def hingeLossPerExample {α : Type} [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] (score y : α) :
        α

        Hinge loss per example: ℓ_i = max(0, 1 - y_i * f(x_i)).

        We write it using if rather than max to make the "active-set" logic explicit.

        Instances For
          def hingeLossMean {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n : } (scores y : TorchLean.Tensor α [n]) :
          α

          Mean hinge loss over a dataset.

          Instances For
            def LinearSVM.objective {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n p : } (lambda : α) (m : LinearSVM p α) (X : TorchLean.Tensor α [n, p]) (y : TorchLean.Tensor α [n]) :
            α

            L2-regularized SVM objective (primal, soft-margin style).

            We use the common objective $\frac12\lambda\lVert w\rVert^2+\operatorname{mean}(\text{hinge loss})$.

            Instances For

              Backward pass #

              For the objective

              L(w,b) = ½λ‖w‖² + (1/n) Σ max(0, 1 - y_i (w·x_i + b))

              the gradients are:

              We also return ∂L/∂X because it is sometimes useful for sensitivity analysis.

              PyTorch analogy: this is what autograd would compute for 0.5*λ*||w||^2 + mean(relu(1 - y*(X@w+b))), except we write it out explicitly.

              def LinearSVM.backward {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n p : } (lambda : α) (m : LinearSVM p α) (X : TorchLean.Tensor α [n, p]) (y : TorchLean.Tensor α [n]) :

              Backward/VJP for the linear SVM objective.

              Returns (dw, db, dX) where:

              • dw : ∂L/∂w
              • db : ∂L/∂b
              • dX : ∂L/∂X (sometimes useful for sensitivity analysis)
              Instances For

                A Small Training Wrapper (Gradient Descent) #

                The LinearSVM definitions above are enough for "spec math". For examples/tests, it is convenient to package a trained parameter pair together with a simple predictor, so we provide:

                structure SVM (p n : ) (α : Type) [TorchLean.Storage α] :

                Small trained SVM bundle for examples/tests.

                This is not a full SMO-style solver; it is a deterministic gradient-descent baseline that is useful as a reference model in the TorchLean spec layer.

                • weights : TorchLean.Tensor α [p]

                  Normal vector w of the separating hyperplane.

                • bias : α

                  Bias/intercept term b.

                • supportVectorIndices : TorchLean.Tensor [n]

                  One entry per training row: its index when the margin is near 1, or the sentinel n otherwise. Filter out n before using entries to index the training data.

                Instances For
                  def findSupportVectorIndices {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n p : } (X : TorchLean.Tensor α [n, p]) (y : TorchLean.Tensor α [n]) (finalWeights : TorchLean.Tensor α [p]) (finalBias : α) :

                  Heuristic support-vector index extractor.

                  We mark an example as a "support vector" if its margin is close to 1. The output has one entry per training row, containing that row's index or the sentinel n for a non-support row. It is not a compact list of valid indices. This is only meant for introspection and examples (it is not used by the optimizer).

                  Instances For
                    inductive SVM.FitError :

                    A training label outside the signed encoding used by the hinge objective.

                    • invalidLabel (row : ) : FitError

                      The zero-based row whose label is neither -1 nor 1.

                    Instances For
                      @[instance_reducible]
                      @[instance_reducible]
                      def fitLinearSVM {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n p : } (X : TorchLean.Tensor α [n, p]) (y : TorchLean.Tensor α [n]) (learningRate lambda : α) (iterations : ) :

                      Fit a linear SVM after checking that every label is -1 or 1.

                      The check uses the scalar context's equality operation and precedes every optimization step, including a request for zero steps. Binary 0/1 labels therefore cannot silently change the hinge objective. LinearSVM.objective and LinearSVM.backward remain explicit formulas for mathematical work with a supplied parameter record.

                      Instances For
                        def fitLinearSVM.gradientDescent {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n p : } (X : TorchLean.Tensor α [n, p]) (y : TorchLean.Tensor α [n]) (learningRate lambda : α) (iter : ) (weights : TorchLean.Tensor α [p]) (bias : α) :
                        Instances For
                          def SVM.predict {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n batch p : } (model : SVM p n α) (X : TorchLean.Tensor α [batch, p]) :

                          Predict signed labels ±1 using the learned hyperplane.

                          The training size n indexes the stored support-vector information. Prediction only needs the weights and bias, so the inference batch has an independent size. A zero decision value gives label -1; an empty batch returns an empty label tensor.

                          Instances For
                            def SVM.predictOne {α : Type} [TorchLean.Storage α] [Context α] [DecidableRel fun (x1 x2 : α) => x1 > x2] {n p : } (model : SVM p n α) (x : TorchLean.Tensor α [p]) :
                            α

                            Predict a signed label for one feature vector using the batch predictor's arithmetic.

                            Instances For
                              def Kernel.linear {α : Type} [TorchLean.Storage α] [Context α] {p : } (x y : TorchLean.Tensor α [p]) :
                              α

                              Linear kernel: k(x, y) = x·y.

                              Instances For
                                def Kernel.polynomial {α : Type} [TorchLean.Storage α] [Context α] {p : } (degree : ) (c : α) (x y : TorchLean.Tensor α [p]) :
                                α

                                Polynomial kernel: k(x, y) = (x·y + c)^degree (naive power for generic α).

                                Instances For
                                  def Kernel.polynomial.powRec {α : Type} [Context α] (base : α) (exp : ) :
                                  α
                                  Instances For
                                    def Kernel.rbf {α : Type} [TorchLean.Storage α] [Context α] {p : } (gamma : α) (x y : TorchLean.Tensor α [p]) {h : p 0} :
                                    α

                                    RBF kernel: k(x, y) = exp(-gamma * ||x - y||^2).

                                    When the squared distance is finite, evaluate the usual distance-then-exponential expression. Finite feature differences can overflow that distance even when multiplication by a small gamma gives a representable exponent. In that case, multiply each difference by gamma before its second factor, then sum the weighted squares.

                                    Instances For