EVERYTHING AIAI engineering, made visual
0/18 complete
LESSON 05 · MACHINE LEARNING × AI · BUILD

Draw the widest street
between two classes.

margin = 2 / ‖w‖ is the whole idea: widen the buffer until only the nearest points touch it. Then C prices the mistakes, and a kernel bends the street into any shape.

75 MIN · 7 CHAPTERSPREREQ · LESSONS 08, 14, 18
FIG. 05 / THE MARGIN WIDENS AS THE BOUNDARY SETTLES
MARGIN 2/‖w‖ = 0.00 · VIOLATIONS = 0 + class − class margin
LESSON 05TYPE · BUILD~75 MINPREREQ · PHASE 1 · LESSONS 08, 14, 18ORIGINAL LESSON ↗
THE 60-SECOND VERSIONThen show me the street ↓
01 / THE WIDEST STREET

Among all separating lines, pick the widest.

Scale w and b so the nearest points sit at y·(w·x + b) = 1. Then the distance from the boundary to each rail is 1/‖w‖ and the street width is 2/‖w‖. Maximizing that width is minimizing ½‖w‖² — a convex problem with one global answer.

margin = 2 / ‖w‖
02 / THE CRITICAL FEW

Only the curb-sitters set the boundary.

The points touching the rails are the support vectors; they are the only ones with nonzero dual weight α. Delete a point outside the street and the boundary does not move. At prediction time the model is just the support vectors.

αᵢ > 0 ⟺ support vector
03 / C AND KERNELS

Pay for mistakes, then bend the street.

Real data overlaps, so each point may break its constraint for a price: slack ξ = max(0, 1 − y·f(x)), multiplied by C. Swap the dot product for a kernel K(x, z) and the same linear machine draws curved boundaries without ever visiting the feature space.

½‖w‖² + C·Σ max(0, 1 − yᵢ·f(xᵢ))
MENTAL MODEL IN ONE SENTENCE

An SVM draws the widest street it can between the classes, charges a fine C·ξ to any point that wanders into the street, and at prediction time remembers only the points standing on the curb — or, with a kernel, only their pairwise similarities.

By the end you will be able to compute a margin from w, say which points are support vectors and why, read the C and slack trade-off off a plot, parse hinge loss, and choose between a kernel SVM, a linear SVM and logistic regression for a given dataset.

THE WIDEST STREET

Infinitely many lines fit.
Pick the widest one.

Two classes, one separating line — and an infinite family of candidates. The SVM adds one tie-breaker: leave the largest possible buffer to the nearest points of each class.

A classifier is a hyperplane: w·x + b = 0. The vector w points perpendicular to it, and b shifts it. For any data point xᵢ, the signed distance to the hyperplane is (w·xᵢ + b) / ‖w‖; with labels yᵢ ∈ {−1, +1}, the quantity yᵢ·(w·xᵢ + b) is positive on the correct side and measures confidence up to the scale of w.

Since multiplying w and b by any positive number leaves the boundary unchanged, we are free to fix the scale. The standard choice pins the nearest points at exactly 1: yᵢ·(w·xᵢ + b) ≥ 1. With that convention the distance from the boundary to each margin rail is 1/‖w‖, so the margin width is 2/‖w‖. Maximizing it is the same as minimizing ½‖w‖² — a convex quadratic program with exactly one global solution.

margin = 2 / ‖w‖support vectorsupport vector+ class (circles) · − class (squares)decision boundary: w·x + b = 0
The SVM picks the boundary whose buffer to the nearest points is largest. The two dashed rails are the margin lines w·x + b = ±1; the points that touch them are the support vectors, and they alone pin the street in place. Move any point outside the rails and nothing changes.

The widest street, solved exactly

Drag any point, or pick one and use the sliders. The boundary is recomputed from scratch — it is the unique line that maximizes the width of the band while keeping the classes outside it.

boundary: -0.769·x + 0.513·y + (0.026) = 0 ‖w‖ = 0.925 margin width = 2/‖w‖ = 2.163 distance from boundary to each margin line = 1/‖w‖ = 1.082 support vectors: #3 (-0.6, 1.0), #6 (1.2, -0.2) 8 other points sit strictly outside the band and could move anywhere outside it without changing this line.

The solver sweeps 720 directions and refines the winner, so the printed margin matches the drawing. In the solver’s scaling, every support vector satisfies y·(w·x + b) = 1 and every other point has y·(w·x + b) > 1.

Derivation: distance to a hyperplane, and why margin = 2/‖w‖

Distance. Take a point x and the hyperplane through the origin with normal w. The projection of x onto w is (w·x / ‖w‖²)·w. Slide a copy of the hyperplane to touch x: its offset is the length of that projection, |w·x| / ‖w‖. Adding a shift b changes w·x to w·x + b, so the distance is |w·x + b| / ‖w‖.

numeric check: w = (3, 4), b = 0, x = (6, 8) w·x = 18 + 32 = 50, ‖w‖ = √(9+16) = 5 distance = 50 / 5 = 10 = ‖x‖ ✓ (x is parallel to w) point (3, 0) against the line x + y − 1 = 0: w·x + b = 3 + 0 − 1 = 2, ‖w‖ = √2 distance = 2 / √2 = √2 ≈ 1.4142 scaling w and b by 2 changes nothing: 2·3 + 2·0 − 2 = 4, ‖2w‖ = 2√2, 4 / (2√2) = √2 same ✓

Margin. Choose the scaling so every point satisfies yᵢ(w·xᵢ + b) ≥ 1. The rail on the + side is the line w·x + b = 1; the rail on the − side is w·x + b = −1. Both are parallel to the boundary, and each is 1/‖w‖ away from it, so the street width is 2/‖w‖. Maximizing 2/‖w‖ is equivalent to minimizing ½‖w‖² (same minimizer, friendlier derivative), giving the primal problem:

minimize ½‖w‖² subject to yᵢ·(w·xᵢ + b) ≥ 1 for every point numeric check: w = (3, 4) → ‖w‖ = 5 → margin = 2/5 = 0.4 nearest points sit 1/5 = 0.2 from the boundary on each side.

Every constraint is linear and the objective is a convex bowl, so this is a convex quadratic program: one global optimum, no local minima, no random restarts. That guarantee is a large part of why SVMs were trusted long before neural networks were.

THE CRITICAL FEW

Only the points on the curb
hold the street in place.

A trained SVM ignores almost all of its training data. The points sitting exactly on the margin rails are the support vectors, and they alone determine w and b.

Look again at the street: the nearest + point and the nearest − point touch the rails. Those touching points satisfy y·(w·x + b) = 1 exactly and are called the support vectors. Every other point has y·(w·x + b) > 1: it sits strictly outside the street and contributes nothing. Move it, delete it, add ten more like it — the boundary does not budge. In the language of the dual problem, support vectors are exactly the points with a nonzero coefficient αᵢ; everything else has αᵢ = 0.

This sparsity has two consequences. At prediction time an SVM only needs the stored support vectors and their α values — not the full training set. And the count of support vectors is a bound on generalization error: the smaller the fraction of training points that end up supporting the boundary, the more confidently the model has separated the classes.

The dual console: α is the census of importance

Four points, two per class, all on the line y = x. Uncheck points and watch the exact max-margin solution, the support-vector list and the dual weights α update. Non-support vectors have α = 0: uncheck them and nothing moves.

training points

Checkbox edits change the dataset; the solver recomputes w, b and the margin exactly for the displayed points.

included points: 4 / 4 max-margin solution: w = (0.5000, 0.5000) b = 0.0000 ‖w‖ = 0.7071 margin = 2/‖w‖ = 2.8284 support vectors (α > 0): (1.00, 1.00) y=+1 α = 0.2500 y·f(x) = 1.0000 (-1.00, -1.00) y=−1 α = 0.2500 y·f(x) = 1.0000 2 point(s) with α = 0 sit strictly outside the band and can be removed without changing w, b or the margin. duality check: Σ αᵢyᵢ = 0.0000 (must be 0) ✓ dual objective Σα − ½ΣΣ αᵢαⱼyᵢyⱼ(xᵢ·xⱼ) = 0.2500 ½‖w‖² = 0.2500 → strong duality: equal ✓
Worked example: four points, solved in the dual by hand

Take a tiny dataset, all on the line y = x: two + points at (1, 1) and (2, 2), two − points at (−1, −1) and (−2, −2). By symmetry the widest street is perpendicular to that line: direction u = (1, 1)/√2.

projections onto u: (1, 1) → √2 (2, 2) → 2√2 (−1, −1) → −√2 (−2, −2) → −2√2 gap between nearest classes: √2 − (−√2) = 2√2 half the gap: g = √2 boundary at the midpoint: 0 w = u / g = (0.5, 0.5) b = 0 margin = 2/‖w‖ = 2/√0.5 = 2√2 ≈ 2.8284 y·f(x): (1, 1) → 1.0000 ✓ support vector (−1, −1) → 1.0000 ✓ support vector (2, 2) → 2.0000 outside, α = 0 (−2, −2) → 2.0000 outside, α = 0

Now recover the dual weights from w = Σ αᵢyᵢxᵢ and Σ αᵢyᵢ = 0. Only the two support vectors can have αᵢ > 0: w = α₁(1, 1) + α₃(1, 1) = (α₁ + α₃)(1, 1), and Σαᵢyᵢ = α₁ − α₃ = 0, so α₁ = α₃ = 0.25. Check primal = dual: ½‖w‖² = ½(0.25 + 0.25) = 0.25, and the dual objective Σαᵢ − ½ΣΣ αᵢαⱼyᵢyⱼ(xᵢ·xⱼ) works out to 0.5 − 0.25 = 0.25 as well — strong duality, verified numerically.

Delete the outer point (2, 2) and nothing changes. Delete the inner point (1, 1) instead and the street must stretch to reach (2, 2): w = (1/3, 1/3), b = −1/3, margin = 3√2 ≈ 4.243, with α = 1/9 on the two remaining support vectors. Same data, one deletion, a completely different boundary — that is the definition of a support vector.

Quick check

You delete a training point that lies far from the boundary, well outside the margin. What happens to the SVM's decision boundary?

C AND SLACK

Real data wanders.
Charge it a fine.

A hard margin demands a clean separation and gives up when the data overlaps. The soft margin keeps the widest street it can and pays a penalty for every point that steps inside.

Hard-margin constraints yᵢ·(w·xᵢ + b) ≥ 1 are unsolvable the moment a + point and a − point are close enough that no line separates them, and nearly unsolvable with one noisy outlier. The fix is one new variable per point: a slack ξᵢ ≥ 0 that relaxes its constraint to yᵢ·(w·xᵢ + b) ≥ 1 − ξᵢ. A point outside the street has ξᵢ = 0; a point inside it has ξᵢ equal to how far past the rail it stands; a misclassified point has ξᵢ > 1.

Training now minimizes two things at once: the width term ½‖w‖² and the total slack, with C deciding the exchange rate:

minimize ½‖w‖² + C · Σᵢ ξᵢ subject to yᵢ·(w·xᵢ + b) ≥ 1 − ξᵢ ξᵢ ≥ 0 for every point small C → slack is cheap → wide margin, more violations large C → slack is expensive → narrow margin, fewer violations

Because ξᵢ = max(0, 1 − yᵢ·f(xᵢ)) at the optimum, the two-line problem above is equivalent to the unconstrained objective ½‖w‖² + C·Σ max(0, 1 − yᵢ·f(xᵢ)) — hinge loss plus L2 regularization, which is the subject of the next chapter. One warning before you tune anything: C is the inverse of a regularization strength. Large C means less regularization (the model contorts to fit), small C means more (the model stays smooth and may underfit).

C: the price of wandering into the street

One noisy + point at (1.0, −0.8) sits inside the − cluster. Slide C from cheap fines (left) to expensive fines (right) and watch the SVM choose between a wide margin and a clean training set.

C = 0.5000 w = [-0.469, 0.542] b = 0.249 margin 2/‖w‖ = 2.7910 violations (slack > 0): 2 misclassified: 1 support vectors and their margin y·f(x): #3 z=1.000 α=0.20 · #6 z=-0.653 α=0.50 · #7 z=0.895 α=0.50 · #8 z=1.000 α=0.07 · #9 z=1.000 α=0.12 α reaches the cap C on points pinned inside the margin; α = 0 on points the model is allowed to ignore. Noisy point (1.0, −0.8), label +: y·f(x) = -0.6534 slack ξ = 1.6534 it is inside the margin — C decides how much that bothers the model.

Small C → wide margin, many violations (underfitting). Large C → margin collapses, zero violations, risk of overfitting. The objective printed in the footer is the exact quantity the solver minimizes.

Slack in numbers: the same dataset at four values of C

These are the lab’s 11 points and the exact output of its dual SMO solver (same algorithm as Platt’s Sequential Minimal Optimization, run to KKT convergence). Only the noisy + point at (1.0, −0.8) changes story.

C = 0.05 w = (−0.307, 0.310) b = 0.139 margin = 4.586 violations = 6 misclassified = 1 noisy point: y·f(x) = −0.416 → ξ = 1.416 C = 0.5 w = (−0.469, 0.542) b = 0.249 margin = 2.791 violations = 2 misclassified = 1 noisy point: y·f(x) = −0.653 → ξ = 1.653 C = 5 w = (−1.381, 1.208) b = 2.020 margin = 1.090 violations = 1 misclassified = 1 noisy point: y·f(x) = −0.327 → ξ = 1.327 C = 50 w = (−4.103, 3.590) b = 7.974 margin = 0.367 violations = 0 misclassified = 0 noisy point: y·f(x) = 1.000 → ξ = 0 (now a support vector) objective checks: at C = 0.05, ½‖w‖² + CΣξ = 0.095 + 0.152 = 0.247 at C = 50, ½‖w‖² + CΣξ = 14.859 + 0 = 14.859

Follow the margin column: 4.586 → 0.367, a 12× collapse, while violations drop 6 → 0. At C = 0.05 the model shrugs at the noisy point and keeps a broad, safe boundary; at C = 50 it rotates the boundary until that single point is respected, and the street squeezes into a sliver. Both are optimal — for different prices of slack. That is why C is a hyperparameter you tune with validation data, not a setting with one right answer.

Quick check

You switch an SVM from C = 0.1 to C = 100 on a noisy dataset. What do you expect?

HINGE LOSS

A loss that stops caring
once you are safe.

The soft-margin problem can be written as an unconstrained sum of per-point penalties. Those penalties are hinge-shaped: linear while you are in trouble, exactly zero once you are outside the margin.

Define the margin score of a point as z = y·f(x) where f(x) = w·x + b. Its hinge loss is max(0, 1 − z). Three regimes, one formula:

  1. z ≥ 1 — correctly classified and outside the street: loss 0, gradient 0. The point is done.
  2. 0 ≤ z < 1 — correctly classified but inside the street: loss 1 − z, gradient −1. The model is pushed to widen the street.
  3. z < 0 — misclassified: loss 1 + |z|, the largest push of all. The model is actively wrong and pays for it.

Compare it with the logistic loss log(1 + e^(−z)) from Lesson 03. Logistic loss is smooth and never exactly zero — every point keeps voting forever. Hinge loss is zero with zero gradient on the whole half-line z > 1, so safely classified points drop out of the solution entirely. That is the loss-level explanation of support vectors: training with hinge loss produces sparse models.

Hinge, logistic, and the 0-1 loss nobody can train

Move the vertical line along z = y·f(x). Outside the margin (z ≥ 1) the hinge is flat at zero; inside it falls with slope −1. The 0-1 loss is flat almost everywhere — no slope, no direction, no learning.

hinge max(0, 1 − 0.50) = 0.5000 logistic log(1 + e^(−0.50)) = 0.4741 0-1 loss 0 (right side) inside the margin, correctly classified: the hinge still pushes the point outward with slope −1. numerical anchor: z = 0.5 gives hinge 0.5000 and logistic 0.4741; z = 2 gives hinge 0.0000 and logistic 0.1269.

The 0-1 loss counts mistakes, which is what we care about — but it is flat (zero gradient) on both plateaus, so gradient descent gets no signal. Hinge and logistic are stand-ins with usable slopes.

Derivation: soft margin = hinge loss + L2, and one live update

In the constrained problem, the best feasible slack for a point is its shortfall below the rail: ξᵢ = max(0, 1 − zᵢ). Substituting that into ½‖w‖² + CΣξᵢ removes every ξ and every constraint, leaving the unconstrained objective the source code actually minimizes:

L(w, b) = ½‖w‖² + C · Σᵢ max(0, 1 − yᵢ·(w·xᵢ + b)) subgradient with respect to w: if zᵢ ≥ 1: ∇w = w (only the regularizer pulls) if zᵢ < 1: ∇w = w − C·yᵢ·xᵢ (regularizer + the violated point) subgradient with respect to b: if zᵢ ≥ 1: ∂L/∂b = 0 if zᵢ < 1: ∂L/∂b = −C·yᵢ

Numeric check. Take z = 0.15 from w = (0.2, −0.3), b = 0.1 and the point x = (1, 0.5), y = +1. Compute z = 0.2·1 + (−0.3)·0.5 + 0.1 = 0.15, so the hinge is 0.85. With C = 1 and learning rate 0.1:

∇w = w − y·x = (0.2, −0.3) − (1, 0.5) = (−0.8, −0.8) w′ = (0.2, −0.3) − 0.1·(−0.8, −0.8) = (0.28, −0.22) ∂L/∂b = −y = −1 b′ = 0.1 − 0.1·(−1) = 0.2 new z = 0.28·1 + (−0.22)·0.5 + 0.2 = 0.37 new hinge = max(0, 1 − 0.37) = 0.63 (was 0.85 — one step closer to safe)

One step moved the point’s margin from 0.15 to 0.37. If z had already been 1.5, both gradients would have been zero for this point and nothing would have changed — the difference between hinge and logistic loss in a single example.

Quick check

Which training points contribute a nonzero gradient under hinge loss?

THE VIEW FROM THE DUAL

Rewrite the problem,
and the data becomes a kernel.

The same SVM has a second form in which the weights disappear and the data appears only as pairwise dot products. That one change is what lets a linear method draw nonlinear boundaries.

Every constrained problem has a companion dual, and Lesson 18 built the machinery: introduce one multiplier per constraint, form the Lagrangian, and — for convex problems — the two optima coincide (strong duality). Applying it to the soft margin, with multipliers αᵢ for the margin constraints and μᵢ for ξᵢ ≥ 0, gives:

primal: minimize ½‖w‖² + C·Σξᵢ s.t. yᵢ(w·xᵢ + b) ≥ 1 − ξᵢ, ξᵢ ≥ 0 dual: maximize Σαᵢ − ½ΣΣ αᵢαⱼyᵢyⱼ(xᵢ·xⱼ) s.t. 0 ≤ αᵢ ≤ C and Σαᵢyᵢ = 0 recover: w = Σαᵢyᵢxᵢ predict: f(x) = Σαᵢyᵢ(xᵢ·x) + b

Read the prediction line carefully: x never appears alone — it appears only dotted with training points. The weight vector is not needed at prediction time at all. And wherever the primal used a dot product xᵢ·xⱼ, the dual may replace it with any kernel function K(xᵢ, xⱼ) that behaves like a dot product in some feature space. That substitution is the kernel trick: a linear boundary in a richer space becomes a nonlinear boundary in the original one, and the richer space is never built.

linear: K(x, z) = x·z polynomial: K(x, z) = (x·z + c)^d RBF: K(x, z) = exp(−γ‖x − z‖²) numeric checks with the reference point x = (1, 0): z = (2, 0) linear 2.00 poly d=2 9.00 RBF γ=0.5 0.6065 z = (0, 1) linear 0.00 poly d=2 1.00 RBF γ=0.5 0.3679 z = (1.1, 0.1) linear 1.10 poly d=2 4.41 RBF γ=0.5 0.9900 z = (5, 0) linear 5.00 poly d=2 36.00 RBF γ=0.5 0.000335 z = (−1, 0) linear −1.00 poly d=2 0.00 RBF γ=0.5 0.1353 K((1,0), (5,0)) = exp(−0.5·16) = e^−8 ≈ 0.000335: far apart → similarity 0. K((1,0), (1.1,0.1)) = exp(−0.01) ≈ 0.9900: close → similarity 1.

The lift that makes a plane possible

Ten points at radius 1 (squares, class −) and ten at radius 2 (circles, class +). In the input plane no line separates them. Add a third coordinate z = x² + y² and the two rings become two flat levels: z = 1 and z = 4.

feature map: (x, y) → (x, y, x² + y²) inner ring samples (label −1): (1.00, 0.00) → (1.00, 0.00, 1.00) (0.60, 0.80) → (0.60, 0.80, 1.00) (0.28, 0.96) → (0.28, 0.96, 1.00) 0.28² + 0.96² = 0.0784 + 0.9216 = 1.0000 ✓ outer ring samples (label +1): (2.00, 0.00) → (2.00, 0.00, 4.00) (1.20, 1.60) → (1.20, 1.60, 4.00) (0.56, 1.92) → (0.56, 1.92, 4.00) 1.20² + 1.60² = 1.44 + 2.56 = 4.0000 ✓ a plane w·φ(x) + b = 0 with w = (0, 0, 2/3), b = −5/3: inner: (2/3)·1 − 5/3 = −1 ✓ exactly on the lower margin outer: (2/3)·4 − 5/3 = +1 ✓ exactly on the upper margin ‖w‖ = 2/3, margin = 2/‖w‖ = 3 = 4 − 1 ✓ the same trick with K(x, z) = φ(x)·φ(z) never builds z at all — this is the kernel trick.

The lift is a teaching example of a feature map, not what an SVM literally computes: a kernel SVM reaches this decision boundary by evaluating similarities, never the third coordinate.

Derivation: where w = Σαᵢyᵢxᵢ comes from, with a polynomial check

Write the Lagrangian with multipliers αᵢ ≥ 0 on the margin constraints and μᵢ ≥ 0 on the slacks:

L = ½‖w‖² + CΣξᵢ − Σαᵢ[yᵢ(w·xᵢ + b) − 1 + ξᵢ] − Σμᵢξᵢ stationarity: ∂L/∂w = 0 → w = Σαᵢyᵢxᵢ ∂L/∂b = 0 → Σαᵢyᵢ = 0 ∂L/∂ξᵢ = 0 → αᵢ + μᵢ = C, so 0 ≤ αᵢ ≤ C substitute w back and the w-terms collapse to −½ΣΣ αᵢαⱼyᵢyⱼ(xᵢ·xⱼ), leaving the dual objective from the box above.

Why the dot products are all the dual needs. Look at the one place training data appears in the dual: the pairwise product xᵢ·xⱼ. If those numbers can be produced by a similarity function K, the optimizer never asks what φ looks like. Concretely, with the polynomial kernel of degree 2, K(x, z) = (x·z + 1)² = φ(x)·φ(z) for the explicit feature map

φ(x) = (x₁², x₂², √2·x₁x₂, √2·x₁, √2·x₂, 1) x = (1, 2), z = (3, 1): x·z = 3 + 2 = 5 K(x, z) = (5 + 1)² = 36 φ(x)·φ(z) = 1·9 + 4·1 + 2√2·3√2 + √2·3√2 + 2√2·√2 + 1 = 9 + 4 + 12 + 6 + 4 + 1 = 36 ✓ degree d = 3 in D = 100 features: explicit φ has C(103, 3) = 176,851 coordinates K(x, z) costs about 100 multiplications.

The RBF kernel is the extreme case: exp(−γ‖x−z‖²) = exp(−γ‖x‖²)·exp(2γ·x·z)·exp(−γ‖z‖²), and the middle factor expands as a polynomial of every degree. Its feature space is infinite-dimensional — and it is still evaluated in a handful of floating-point operations.

SIMILARITY, TUNED

One knob sets how far
a point can reach.

The RBF kernel measures closeness. Gamma decides what “close” means: a wide neighbourhood that blends many points together, or a narrow one where every point is its own island.

K(x, z) = exp(−γ‖x − z‖²) equals 1 when two points coincide, 0.6065 at squared distance 0.5/γ, and 0.000335 at squared distance 8/γ. For γ = 0.5 that means 0.6065 at squared distance 1 and 0.000335 at squared distance 16 (distance 4). So γ is a zoom knob on distance: small γ makes distant points count as similar (the boundary is smooth and nearly global), while large γ makes only immediate neighbours count (the boundary grows spiky and can carve a private island around each point). Same kernel, same data, wildly different geometry.

The polynomial kernel trades locality for degree: (x·z + c)^d encodes feature interactions up to order d, which is why d = 1 is the linear kernel and d = 2 already draws conic boundaries (as the lift lab showed for x² + y²). The default advice is unglamorous and correct: start with a scaled linear SVM, and only reach for RBF when the linear boundary is clearly wrong.

The same machinery works for regression. Support Vector Regression fits a tube of width ε around the data: points inside the tube cost nothing, points outside pay linearly, and the support vectors are the points on or outside the tube wall. Wider tube → fewer support vectors → smoother fit. And the situations where SVMs still beat the crowd are concrete: hundreds to a few thousand training points, very high-dimensional sparse features, binary problems with a clean margin, one-class anomaly detection, and any setting where you want a training-time guarantee rather than a hope. Deep learning owns the other end — images, audio, and millions of rows with learnable features.

Gamma: how far one point’s influence reaches

This trains a real RBF-kernel SVM (C = 1) with the same dual solver as the C lab. Slide γ from smooth to spiky and watch the decision regions change shape.

kernel width: γ = 0.5000 similarity between two points d apart: K = exp(−γ·d²) d = 1.0 → K = 0.6065 d = 2.0 → K = 0.1353 d = 3.0 → K = 0.0111 support vectors: 16 / 16 training accuracy: 16 / 16 γ middle: influence is local — the boundary wraps the inner ring cleanly without chasing points.

Rule of thumb: γ small → each point influences a wide area (smooth, underfits). γ large → each point only recognizes its own neighbourhood (spiky, overfits). scikit-learn’s default gamma="scale" is 1/(features · variance of X).

Gamma in numbers, and the pipeline that keeps it honest

Similarity values at three distances for γ = 0.5 (the lab defaults to γ = 0.5 and lets you move it):

d = 1 → K = exp(−0.5) = 0.6065 d = 2 → K = exp(−2) = 0.1353 d = 3 → K = exp(−4.5) = 0.0111 γ = 0.05 (wide): d = 3 still gives exp(−0.45) = 0.6376 γ = 20 (narrow): d = 1 already gives exp(−20) = 2.1e−9 scikit-learn's gamma="scale" sets γ = 1 / (n_features · Var(X)), so each feature contributes in units of its own spread.

The scaling rule. σ of the features sets the unit of ‖x − z‖², so γ and feature scale are entangled: doubling every feature quadruples its contribution to distance, which is equivalent to multiplying γ by four. That is why the standard pipeline is standardize → SVM → tune C and γ together, never tune one without the other.

logistic regression linear SVM (hinge) loss log(1 + e^−z) max(0, 1 − z) outputs probability signed score / margin training all points contribute only support vectors (α > 0) prediction dense dot product sparse: support vectors only strengths calibrated probabilities kernels, sparse high-dim data, online / streaming strong margin guarantees scale helpful but optional essential before training
Use it — scikit-learnpython
from sklearn.svm import SVC, LinearSVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

# small data, nonlinear boundary: RBF kernel, dual solver
clf = Pipeline([
    ("scaler", StandardScaler()),
    ("svm", SVC(kernel="rbf", C=1.0, gamma="scale")),
])
clf.fit(X_train, y_train)
print(f"accuracy: {clf.score(X_test, y_test):.4f}")
print(f"support vectors: {clf['svm'].n_support_}")

# tall data (n large, d small): primal solver, O(n) per epoch
fast = Pipeline([
    ("scaler", StandardScaler()),
    ("svm", LinearSVC(C=1.0, max_iter=10000)),
])
The scaler is not optional: an SVM measures distance, so it must see comparable units. Use SVC for small or nonlinear problems and LinearSVC when n is large and d is small.
Quick check

You train an RBF SVM and it gets 100% training accuracy, but the decision regions are ragged islands around individual points. What is the most likely cause, and what should you try first?

CHECK YOURSELF

Five questions.
Then the terms worth keeping.

Answer before you look. The C question and the support-vector question are exactly the ones that separate a memorized answer from a working understanding.

0 / 5 answered · 0 correct

01What are support vectors in an SVM?

02What does the SVM maximize when finding the decision boundary?

03What happens when you increase the C parameter in an SVM?

04How does the kernel trick enable SVMs to learn nonlinear boundaries?

05Hinge loss is zero when y·f(x) ≥ 1. What does this mean in terms of classification?

Key terms, demystified

Click a card to swap the lazy description for what it actually means.

Exercises from the lesson

Four short problems with exact numbers. Try first; a worked answer is one click away.

  1. Find the maximum-margin boundary for the four points (1, 1) +, (2, 2) +, (−1, −1) −, (−2, −2) − by hand. Compute w, b, the margin and the support vectors. Then delete (2, 2); delete (1, 1) instead. What changes?
    Show one worked answer

    All four points lie on the line y = x, so the widest street runs perpendicular to it. Take the unit direction u = (1, 1)/√2; the projections u·x are √2 and 2√2 for the positives, −√2 and −2√2 for the negatives. The gap between the nearest classes is √2 − (−√2) = 2√2, so half the gap is g = √2 and the boundary sits at the midpoint, 0. Rescaling gives w = u/g = (0.5, 0.5) and b = 0, with margin 2/‖w‖ = 2√2 ≈ 2.828. Support vectors: (1, 1) and (−1, −1), where y·f(x) = 1 exactly; the outer points have y·f(x) = 2. Deleting (2, 2) changes nothing (y·f = 2 > 1, α = 0). Deleting (1, 1) forces the boundary to move toward the remaining positive point: g = 3√2/2, w = (1/3, 1/3), b = −1/3, margin = 3√2 ≈ 4.243, and now (2, 2) and (−1, −1) are the support vectors. Exact dual weights for the four-point problem: α = (0.25, 0, 0.25, 0), and the dual objective is 0.25 = ½‖w‖².

  2. The lesson's noisy dataset has five + points clustered around the top left, five − points at the bottom right, and one noisy + point at (1.0, −0.8) deep among the negatives. Train the soft-margin SVM for C = 0.05, 0.5, 5 and 50. For each, report margin width, violations and the noisy point's margin y·f(x).
    Show one worked answer

    The C-lab solver (dual SMO on the same 11 points) gives: C = 0.05 → w = (−0.307, 0.310), b = 0.139, margin 4.586, 6 violations, noisy-point margin −0.416 (slack 1.416). C = 0.5 → w = (−0.469, 0.542), b = 0.249, margin 2.791, 2 violations, noisy-point margin −0.653 (slack 1.653). C = 5 → w = (−1.381, 1.208), b = 2.020, margin 1.090, 1 violation, noisy-point margin −0.327. C = 50 → w = (−4.103, 3.590), b = 7.974, margin 0.367, 0 violations, noisy-point margin exactly 1.000 (it became a support vector, sitting on the margin). The pattern is the whole trade-off: as C grows, the street narrows from 4.59 to 0.37 and the model contorts itself to stop paying fines. At C = 0.05 the model has 6 violations and still gets 10/11 training points right; at C = 50 it gets all 11 but the margin is 12× narrower.

  3. Two concentric circles: (1, 0) with label −1 and (2, 0) with label +1. Show that no straight line separates them through the origin, then compute the RBF kernel values K(x, z) = exp(−γ‖x − z‖²) with γ = 0.5 and check that a kernel classifier separates the two points.
    Show one worked answer

    A line through the origin has equation ax + by = 0; restricted to the x-axis it is ax = 0, so its sign is constant for all x > 0 and cannot put (1, 0) and (2, 0) on opposite sides. Kernel values: K((1,0), (1,0)) = exp(0) = 1; K((2,0), (2,0)) = 1; K((1,0), (2,0)) = exp(−0.5·1) = e^−0.5 ≈ 0.6065. Use the signed vote f(x) = Σ αᵢyᵢK(xᵢ, x) with αᵢ = 1 for both points: at x = (1, 0), f = 1·(−1)·1 + 1·(+1)·0.6065 = −0.3935 < 0 → predict −1 ✓. At x = (2, 0), f = 1·(−1)·0.6065 + 1·(+1)·1 = +0.3935 > 0 → predict +1 ✓. Being close in input space makes K near 1 and far makes it near 0; the kernel's similarity geometry, not the original coordinates, separates the classes. A real RBF SVM would also learn the αᵢ, but the direction of the fix is exactly this.

  4. Tabulate hinge loss max(0, 1 − z) and logistic loss log(1 + e^−z) for z = y·f(x) ∈ {−1, 0, 0.5, 1, 2}. Which of these points contribute a nonzero hinge gradient, and what does that imply for the trained model?
    Show one worked answer

    z = −1: hinge 2.000, logistic 1.3133, hinge slope −1 (subgradient), logistic slope −0.7311. z = 0: hinge 1.000, logistic 0.6931, slopes −1 and −0.5000. z = 0.5: hinge 0.500, logistic 0.4741, slopes −1 and −0.3775. z = 1: hinge 0.000, logistic 0.3133, hinge slope 0 (subgradient lies in [−1, 0]), logistic slope −0.2689. z = 2: hinge 0.000, logistic 0.1269, slopes 0 and −0.1192. Only the first three contribute to the hinge gradient: the points with z ≥ 1 are done, and their weights in the solution are exactly zero. Logistic loss gives every point a nonzero slope forever, so every training point keeps its vote. That is why an SVM's prediction cost depends on the number of support vectors rather than the size of the training set.

Terms this lesson borrows from later lessons (or outside)

You do not need to master these here. Each one gets a proper treatment in its own lesson; the one-line meaning is enough to keep reading. Orange dotted underlines in the prose point back to this list.

  • norm ‖w‖The length of the weight vector, √(w₁² + w₂² + …). The margin is 2/‖w‖, so the norm of w literally sets the width of the street. (Phase 1, Lesson 14)
  • dot productw·x = w₁x₁ + w₂x₂ + …, the raw material of both the decision function and the kernel K(x, z). (Phase 1, Lesson 02)
  • gradient descentStepping parameters opposite the loss gradient. The source trains a linear SVM this way; the labs solve the same problem exactly with the dual. (Phase 1, Lessons 04 & 08)
  • convex quadratic programMinimizing a bowl-shaped quadratic subject to linear constraints. The SVM primal is one, so it has a unique global solution — no local minima to worry about. (Phase 1, Lesson 18)
  • Lagrange multipliers & KKTThe machinery for constrained optimization: a multiplier αᵢ per constraint, and conditions that say a multiplier is positive only when its constraint is active. Example: αᵢ > 0 exactly for support vectors. (Phase 1, Lesson 18)
  • regularizationPunishing large weights so the model generalizes. The ½‖w‖² term is L2 regularization, and C is the inverse regularization strength. (Phase 1, Lesson 18; Phase 2, Lesson 12)
  • feature map φ(x)A function that turns each input into a richer vector (for example (x₁, x₂) → (x₁², x₂², √2x₁x₂, …)). Kernels compute with φ implicitly. (Phase 1, Lesson 03)
  • standardizationRescaling each feature to mean 0 and standard deviation 1 before training. SVMs are distance-based, so skipping it distorts the margin and the kernel. (Phase 2, Lesson 02)
KEEP GOING

A picture is a start.
Practice is the rest.

This lesson is a port of an open course. Everything here traces back to it — and the next step is running the code yourself.

Lesson text adapted from AI Engineering from Scratch (Phase 02, Lesson 05) and the Math Foundations Notebook reference build. Interactive figures, the exact hard-margin and SMO solvers, the kernel-lift and gamma labs, the dual console, worked exercise answers and the numeric checks are original to this page. Every lab runs in your browser.