AI Knowledge Tree

Soft-margin SVM and hinge loss

Relax separability with slack variables, get the hinge-loss primal, and tune the regularization C.

⏱ 28 minPrerequisites:Hard-margin SVM

Hard-margin SVM is infeasible on nonseparable data and brittle near outliers. The soft-margin SVM relaxes the constraints with slack variables, charging a penalty for every margin violation[1]. Rewriting the slack penalty as a loss gives the hinge loss, which is what production SVMs actually minimize.

Slack variables

For each example, introduce a nonnegative slack ξi≥0\xi_i \ge 0 that absorbs any margin shortfall:

yi(w⊤xi+b)≥1−ξi.y_i(w^\top x_i + b) \ge 1 - \xi_i.

Three regimes:

  • ξi=0\xi_i = 0: the constraint holds with room to spare; the point sits outside or on the margin.
  • 0<ξi≤10 < \xi_i \le 1: the point is inside the margin band but on the correct side.
  • ξi>1\xi_i > 1: the point is misclassified.

The total violation ∑iξi\sum_i \xi_i should be small.

The slack is the margin shortfall, so its size reads off directly from the signed margin zi=yi(w⊤xi+b)z_i = y_i(w^\top x_i + b), which is ξi=max⁡(0,1−zi)\xi_i = \max(0, 1 - z_i). Several points spanning the range, to fix what a unit of slack means:

  • A confidently correct point at z=2.0z = 2.0 sits well outside the margin: ξ=0\xi = 0. No penalty.
  • A point right on the margin, z=1.0z = 1.0: ξ=0\xi = 0. The constraint binds but is not violated.
  • A point inside the margin band but still on the correct side, z=0.4z = 0.4: ξ=0.6\xi = 0.6.
  • A point on the decision boundary, z=0z = 0: ξ=1.0\xi = 1.0. Slack of exactly one marks the boundary between "inside the margin" and "misclassified".
  • A point misclassified with room, z=−1.5z = -1.5: ξ=2.5\xi = 2.5. Slack grows without bound as a point moves deeper onto the wrong side.

The C∑iξiC\sum_i \xi_i term sums these, so the objective pays CC per unit of this shortfall.

The QP

min⁡w,b,ξ  12∥w∥2+C∑iξis.t.yi(w⊤xi+b)≥1−ξi,  ξi≥0.\min_{w, b, \boldsymbol\xi}\; \tfrac{1}{2}\lVert w\rVert^2 + C\sum_i \xi_i \quad \text{s.t.}\quad y_i(w^\top x_i + b) \ge 1 - \xi_i,\ \ \xi_i \ge 0.

The regularization knob C>0C > 0 trades margin width against constraint violation:

  • Large CC: heavy penalty on violations, narrow margin, close to hard-margin.
  • Small CC: tolerates violations, wider margin, more bias.

The problem is convex (quadratic objective + affine constraints).

Hinge loss: same problem, no slacks

Minimize over ξi\xi_i for fixed (w,b)(w, b). The optimal slack is ξi=max⁡(0,1−yi(w⊤xi+b))\xi_i = \max(0, 1 - y_i(w^\top x_i + b)): just enough to satisfy the constraint, zero if not needed. Substituting,

min⁡w,b  12∥w∥2+C∑imax⁡(0, 1−yi(w⊤xi+b)).\min_{w, b}\; \tfrac{1}{2}\lVert w\rVert^2 + C \sum_i \max\big(0,\ 1 - y_i(w^\top x_i + b)\big).

The per-example loss

ℓhinge(z)=max⁡(0,1−z),z=y(w⊤x+b),\ell_{\text{hinge}}(z) = \max(0, 1 - z), \qquad z = y(w^\top x + b),

is the hinge loss. It is zero on correctly classified points outside the margin (z≥1z \ge 1), and grows linearly inside the margin and across the boundary.

The soft-margin SVM is regularized hinge-loss minimization, the same shape as L2-regularized logistic regression but with hinge instead of cross-entropy[2].

Convex but not differentiable

The hinge is not differentiable at z=1z = 1 (the kink). Standard remedies:

  • Subgradient descent: replace the derivative at the kink with any value in the subdifferential (typically −yx-y x if z<1z < 1 else 00).
  • Proximal / smoothing: replace the hinge with a smoothed version (e.g. squared hinge).
  • Dual / SMO: solve the dual QP, as in the original SVM literature.

For small to medium problems, the dual is standard; for large ones, stochastic subgradient descent on the primal (Pegasos) is the workhorse.

Choosing C

CC is the central hyperparameter. Cross-validate over C∈{10−3,…,103}C \in \{10^{-3}, \dots, 10^3\} on a log scale. Larger CC may help on clean, well-separated data; smaller CC helps when outliers or label noise are present. The trade is exactly the bias-variance tradeoff with a different parameterization: 1/C1/C plays the role of λ\lambda in ridge.

The soft margin permits violations so overlapping classes can still be separated; the parameter C trades margin width against those violations.
The soft margin permits violations so overlapping classes can still be separated; the parameter C trades margin width against those violations.

Check it on arrays

python · numpy
import numpy as np

rng = np.random.default_rng(0)

# Nonseparable 2D data: two overlapping Gaussians
n = 200
X = np.vstack([rng.normal([0.8, 0], scale=1.0, size=(n//2, 2)),
               rng.normal([-0.8, 0], scale=1.0, size=(n//2, 2))])
y = np.array([1.0] * (n//2) + [-1.0] * (n//2))

def soft_margin_svm(X, y, C=1.0, lr=0.01, steps=5000):
    n, d = X.shape
    w = np.zeros(d)
    b = 0.0
    for _ in range(steps):
        margins = y * (X @ w + b)
        viol = margins < 1.0                            # which points violate
        grad_w = w - C * (y[viol, None] * X[viol]).sum(axis=0)
        grad_b = - C * y[viol].sum()
        w -= lr * grad_w / n
        b -= lr * grad_b / n
    return w, b

# Sweep C: more weight on violations -> tighter margin
for C in [0.01, 1.0, 100.0]:
    w, b = soft_margin_svm(X, y, C=C, lr=0.1)
    margin = 1.0 / np.linalg.norm(w)
    acc = np.mean(np.sign(X @ w + b) == y)
    viol = np.mean(y * (X @ w + b) < 1.0)
    print(f"C={C:>6}: margin={margin:.3f}, accuracy={acc:.3f}, fraction with violation={viol:.3f}")

# Verify the hinge-loss equivalence: optimal slack is max(0, 1 - y(w^T x + b))
w, b = soft_margin_svm(X, y, C=1.0, lr=0.1)
hinge_loss = np.maximum(0, 1 - y * (X @ w + b)).sum()
print(f"\ntotal hinge loss = {hinge_loss:.3f}  (= sum of optimal slacks)")

Larger CC tightens the margin and reduces the fraction of margin violations; the total hinge loss equals the sum of optimal slacks.

Exercises

Exercise 1. Four points have signed margins zi=yi(w⊤xi+b)z_i = y_i(w^\top x_i + b) equal to 2.02.0, 0.70.7, 0.00.0, and −1.0-1.0. Compute the optimal slack ξi\xi_i for each, the per-example hinge loss, and classify each point as outside the margin, inside the band, on the boundary, or misclassified.

Solution

Step 1. The optimal slack is ξi=max⁡(0,1−zi)\xi_i = \max(0, 1 - z_i), which is also the hinge loss ℓhinge(zi)\ell_{\text{hinge}}(z_i):

ξ(2.0)=0,ξ(0.7)=0.3,ξ(0.0)=1.0,ξ(−1.0)=2.0.\xi(2.0) = 0, \quad \xi(0.7) = 0.3, \quad \xi(0.0) = 1.0, \quad \xi(-1.0) = 2.0.

Step 2. Read off the regime from ziz_i and ξi\xi_i:

  • z=2.0z = 2.0, ξ=0\xi = 0: outside the margin (confidently correct).
  • z=0.7z = 0.7, ξ=0.3\xi = 0.3: inside the band, still on the correct side (0<ξ≤10 < \xi \le 1).
  • z=0.0z = 0.0, ξ=1.0\xi = 1.0: on the decision boundary; slack of exactly 11 is the inside/misclassified boundary.
  • z=−1.0z = -1.0, ξ=2.0\xi = 2.0: misclassified (ξ>1\xi > 1).

The total hinge loss is 0+0.3+1.0+2.0=3.30 + 0.3 + 1.0 + 2.0 = 3.3.

Exercise 2. For fixed (w,b)(w, b), the soft-margin objective in the slack ξi\xi_i is min⁡ξi≥0Cξi\min_{\xi_i \ge 0} C\xi_i subject to ξi≥1−zi\xi_i \ge 1 - z_i with zi=yi(w⊤xi+b)z_i = y_i(w^\top x_i + b). Show the minimizer is ξi⋆=max⁡(0,1−zi)\xi_i^\star = \max(0, 1 - z_i), which is why the slack penalty collapses to the hinge loss.

Solution

Step 1. The cost CξiC\xi_i is increasing in ξi\xi_i (since C>0C > 0), so the minimizer is the smallest ξi\xi_i that is still feasible.

Step 2. Feasibility requires both ξi≥0\xi_i \ge 0 and ξi≥1−zi\xi_i \ge 1 - z_i, so the smallest feasible value is the larger of the two lower bounds: ξi⋆=max⁡(0,1−zi)\xi_i^\star = \max(0, 1 - z_i).

Step 3. Two cases confirm it. If zi≥1z_i \ge 1, then 1−zi≤01 - z_i \le 0 and the binding bound is 00, so ξi⋆=0\xi_i^\star = 0 (no penalty). If zi<1z_i < 1, then 1−zi>01 - z_i > 0 is the binding bound, so ξi⋆=1−zi>0\xi_i^\star = 1 - z_i > 0. Both cases are summarized by max⁡(0,1−zi)\max(0, 1 - z_i), the hinge loss. Substituting ξi⋆\xi_i^\star into C∑iξiC\sum_i \xi_i turns the constrained QP into unconstrained regularized hinge-loss minimization.

Exercise 3 (code). On two overlapping Gaussian classes, sweep C∈{0.01,1,100}C \in \{0.01, 1, 100\} with subgradient descent and confirm that the margin width 1/∥w∥1/\lVert w\rVert is non-increasing in CC (larger CC penalizes violations harder, so the margin tightens).

Solution
python · numpy
import numpy as np

rng = np.random.default_rng(0)
n = 200
X = np.vstack([rng.normal([0.8, 0], 1.0, (n // 2, 2)),
               rng.normal([-0.8, 0], 1.0, (n // 2, 2))])
y = np.array([1.0] * (n // 2) + [-1.0] * (n // 2))

def soft_margin_svm(X, y, C, lr=0.1, steps=5000):
    n, d = X.shape
    w = np.zeros(d)
    b = 0.0
    for _ in range(steps):
        viol = y * (X @ w + b) < 1.0               # points inside the margin
        grad_w = w - C * (y[viol, None] * X[viol]).sum(axis=0)
        grad_b = -C * y[viol].sum()
        w -= lr * grad_w / n
        b -= lr * grad_b / n
    return w, b

margins = []
for C in [0.01, 1.0, 100.0]:
    w, b = soft_margin_svm(X, y, C)
    margins.append(1.0 / np.linalg.norm(w))

print("margins by C:", [round(m, 3) for m in margins])
assert margins[0] >= margins[1] >= margins[2]      # margin shrinks as C grows

The margin falls from about 1.511.51 at C=0.01C = 0.01 to about 0.530.53 at C=100C = 100: tightening CC buys fewer violations at the cost of a narrower band, the bias-variance trade in SVM clothing.

The next lesson casts the SVM in its dual form, where the support-vector structure becomes explicit.


References

  1. [1]Cortes, C., & Vapnik, V. (1995). "Support-vector networks". Machine Learning, 20(3), 273-297. Introduces the soft-margin SVM with slack variables (doi:10.1007/BF00994018).↩
  2. [2]Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning (2nd ed.). Springer. §12.3 frames the SVM as penalized hinge-loss minimization (doi:10.1007/978-0-387-84858-7).↩