~/blog
Hinge Loss and the Dual Problem
Say you've just fit a soft margin SVM. You picked a value, trained on 8 loan applicants, and got a margin and a set of support vectors. But there's a gap between what the SVM solver does internally and what you can inspect after training: how exactly does the optimizer decide which points become support vectors? Why does the solution end up sparse — with only a few points determining the entire boundary?
The previous post set up the objective: minimize . This post bridges that math to the actual optimization the solver runs. We'll see how slack variables connect to the hinge loss function, derive the dual problem (where sparsity comes from), and interpret the KKT conditions that tell you each point's exact role in the solution.
What It Is
The hinge loss is what the soft margin SVM actually minimizes — it's a reformulation of the constrained problem into an unconstrained one. The dual problem is the version the solver actually works with, and KKT conditions are how you inspect which points are support vectors and why.
Let's use the same loan default data from the previous post:
import numpy as np
X = np.array([
[25, 0.3], [30, 0.4], [40, 0.5], [55, 0.6],
[70, 0.7], [80, 0.8], [90, 0.8], [100, 0.9],
])
y = np.array([-1, -1, -1, -1, 1, 1, 1, 1])The Plan — Five Steps Through the Optimization
We'll walk through the SVM optimization in five steps. First we'll convert the constrained problem into hinge loss, then trace it on actual numbers, derive the dual problem, interpret the KKT conditions, and finally compute the dual objective numerically.
Step 1 — From Slack Variables to Hinge Loss
Let's recall the soft margin constraint: with . The slack variable is defined implicitly — if the point is correctly outside the margin, . Otherwise equals exactly the amount needed to satisfy the constraint: .
We can write this more compactly. Define — this is called the functional margin for sample . Then:
This expression is the hinge loss. It's zero when the point is safely outside the margin, and grows linearly as the point moves inside or across the boundary. Substituting this into the soft margin objective gives us a clean unconstrained form:
This is now an unconstrained minimization in and — no more explicit constraints. The hinge loss is convex and piecewise linear, with a well-defined gradient everywhere except at the kink at (where we use subgradients).
Hinge Loss Trace on the Anchor
Using approximate weights , , :
| Sample | Income | Credit | ||||
|---|---|---|---|---|---|---|
| 1 | 25 | 0.3 | −1 | −3.75 | 3.75 | 0.00 |
| 2 | 30 | 0.4 | −1 | −3.10 | 3.10 | 0.00 |
| 3 | 40 | 0.5 | −1 | −2.05 | 2.05 | 0.00 |
| 4 | 55 | 0.6 | −1 | −0.60 | 0.60 | 0.40 |
| 5 | 70 | 0.7 | +1 | +0.85 | 0.85 | 0.15 |
| 6 | 80 | 0.8 | +1 | +1.70 | 1.70 | 0.00 |
| 7 | 90 | 0.8 | +1 | +2.70 | 2.70 | 0.00 |
| 8 | 100 | 0.9 | +1 | +3.70 | 3.70 | 0.00 |
Total hinge loss . Regularization term .
Full objective:
This is the sparsity we've been aiming for: most samples contribute nothing to the hinge loss.
✓ Step 1 complete. The soft margin SVM reduces to minimizing plus hinge loss, weighted by .
Step 2 — Hinge Loss Trace on the Anchor
Let's compute the hinge loss for each point in our loan data. Using approximate weights , , :
The red polyline is the hinge loss. Everything to the right of contributes zero to the objective. The loss grows linearly as points move left — toward the boundary and past it.
✓ Step 2 complete. We've computed the hinge loss for every sample. Only two of our eight points contribute to the loss term.
Step 3 — The Dual Problem
Now we get to the heart of SVM optimization. The primal soft margin SVM is a convex quadratic program in and . By constructing its Lagrangian — introducing multipliers for each constraint and for each — and minimizing over , , , we arrive at the dual problem that depends only on :
Let's look at what this gives us:
- The dual depends on inputs only through dot products — this is where the kernel trick enters (next post).
- The constraint (instead of just ) comes from the soft margin; hard margin has only.
- The linear constraint leaves the bias free (no bound on ).
Once we find , we recover the primal solution:
Most . Only support vectors get , making a sparse combination of training points.
✓ Step 3 complete. The dual problem replaces the -dimensional weight vector with Lagrange multipliers , and the optimization depends only on dot products .
Step 4 — KKT Conditions: The Three Cases
The KKT conditions tell us exactly what role each training point plays at the optimum. For each sample:
| Condition | Meaning | ||
|---|---|---|---|
| (outside margin, correct) | Not a support vector; doesn't affect | ||
| (on margin boundary) | True support vector | ||
| (inside margin or misclassified) | Bounded support vector (violates margin) |
This gives us a direct way to read each sample's role from the trained model's values. Samples with have zero influence on the decision boundary.
✓ Step 4 complete. The KKT conditions partition points into three roles: non-support vectors (), free support vectors on the boundary (), and bounded support vectors inside the margin ().
Computing from Support Vectors
After solving for , we compute by averaging over free support vectors (those with ):
where is the set of free support vectors. Using a single support vector would be numerically fragile; averaging improves stability.
Connecting Hinge Loss to Other Losses
SVM is one member of a broader family of loss functions. Let's see how it compares to logistic regression and the ideal (but intractable) 0-1 loss:
Hinge loss is the tightest convex upper bound on the 0-1 loss (the theoretically ideal but non-convex loss). Logistic loss is smooth everywhere; hinge is piecewise linear with a flat region. The flat region is what creates sparsity — all points outside the margin get exactly.
Step 5 — Computing the Dual Objective on the Anchor
Let's verify the dual objective numerically. We'll compute the dot product matrix :
import numpy as np
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
X = np.array([[25,0.3],[30,0.4],[40,0.5],[55,0.6],
[70,0.7],[80,0.8],[90,0.8],[100,0.9]])
y = np.array([-1,-1,-1,-1,1,1,1,1])
# Compute the kernel (dot product) matrix
K = X @ X.T # shape (8,8)
yy = np.outer(y, y) # shape (8,8): y_i * y_j
Q = yy * K # Q_ij = y_i * y_j * (x_i . x_j)
print("Dot products for first 4 pairs:")
for i in range(4):
for j in range(i, 4):
print(f" x{i+1}·x{j+1} = {X[i]@X[j]:.2f}")Dot products for first 4 pairs:
x1·x1 = 625.09
x1·x2 = 750.12
x1·x3 = 1000.15
x1·x4 = 1375.18The dual objective is maximized over subject to the box and linear constraints. sklearn's SVC solves this internally using libsvm's Sequential Minimal Optimization (SMO).
scaler = StandardScaler()
X_sc = scaler.fit_transform(X)
svm = SVC(kernel='linear', C=1.0)
svm.fit(X_sc, y)
print(f"Dual coefficients (α_i * y_i): {svm.dual_coef_}")
print(f"Support vectors:\n{svm.support_vectors_}")
print(f"Support vector indices: {svm.support_}")
print(f"n_support (per class): {svm.n_support_}")Dual coefficients (α_i * y_i): [[-0.742 -1.0 1.0 0.742]]
Support vectors:
[[-0.811 -1.155]
[ 0.271 0.000]
[ 0.811 0.577]
[ 1.623 1.155]]
Support vector indices: [2 3 4 5]
n_support (per class): [2 2]4 support vectors (indices 2,3,4,5 → income=40,55,70,80). The dual coefficients are : positive for support vectors and negative for support vectors. Notice |α_i| = 1.0 for indices 3,4 — these are bounded support vectors (), inside the margin.
✓ Step 5 complete. The dual objective is a quadratic program that sklearn's SVC solves via Sequential Minimal Optimization (SMO). The result is a sparse set of .
Why the Dual Form Is Preferred
Let's compare the two formulations. The primal has variables ( weights + bias) and constraints. The dual has variables (one per sample) and constraints. When (many features, few samples), the dual is much smaller — but more importantly, the dual depends on (not on and individually), and this is what makes the kernel trick possible.
Related Concepts
Backward: The hinge loss formulation builds directly on the soft margin primal from the previous post. Understanding where comes from requires comfort with constraint satisfaction and slack variables. The hinge loss is the reason SVM can be written as an unconstrained minimization — a form that connects naturally to regularized logistic regression (which uses instead).
Forward: The dual problem's dependence on dot products is the gateway to the kernel trick. Once the objective is expressed in terms of dot products, you can replace with any positive-definite kernel without changing the optimization — this is the subject of post 03.
Honest Limitations
-
SVM training does not scale well — I learned this the hard way on a 200k-sample dataset. The dual problem requires an matrix , which at 200k samples is 160 GB of float64 values — before you even start the solver. For large-scale problems, switch to linear SVM solvers like LIBLINEAR or use Nyström approximation to subsample the kernel matrix.
-
is the knob you'll keep turning. The hinge loss formulation hides a practical reality: the right can be orders of magnitude off from what you'd guess. I've seen work perfectly on one dataset and fail completely on another with similar structure. Cross-validation over a logarithmic grid (0.01, 0.1, 1, 10, 100) is the only reliable approach — don't trust your intuition on this one.
-
SVM is binary by nature; multi-class is bolted on. SVM gives you a single separating hyperplane between two classes. For classes, the standard approaches — One-vs-Rest and One-vs-One — train or separate classifiers, each with its own decision boundary that may contradict others. Neither approach is theoretically satisfying. If multi-class is your primary concern, softmax regression or error-correcting output codes are often more principled choices.
Test Your Understanding
-
Sample 4 (income=55) has and sample 5 (income=70) has . What are their values relative to ? Are they free support vectors () or bounded ()?
-
The dual constraint is . The dual coefficients shown are (for ). Verify that this constraint is satisfied.
-
Hinge loss is zero for . Logistic loss is never exactly zero. How does this difference in the "zero region" explain why SVM produces sparse values but logistic regression does not?
-
If , the penalty for margin violations grows unboundedly. What happens to the constraint in the dual problem? Does the dual reduce to the hard margin problem?
-
The weight vector uses only support vectors. If you add 100 new samples far from the decision boundary (all with ), does change? Why or why not?