Support vector machines and kernels
A support vector machine separates two classes with the widest possible street. Learn how the margin is measured with the dot product, which students hold the street in place, how the soft margin and its C setting handle overlap, and how kernels let a straight line become a curve.
Warm-up
One question before the lesson. Choose an answer and check it.
Two lines both separate the training passes from the fails. Line A passes 1 hour from the nearest student, line B only 0.1 hours. Which would you trust more on new students?
Show the answer
A: Line A: it leaves room for new students who land a little off. New students rarely land exactly where the training students did. A line that keeps its distance from both groups still classifies them correctly when they land a little off. That distance is the margin, and an SVM makes it as wide as it can.
Step 1 Many lines separate them
Lessons 4 to 8 drew the boundary between passes and fails in different ways. A support vector machine (SVM) draws a straight line, and chooses it by one idea: stay as far from both groups as possible.
Start with a clean case. Lesson 6’s students passed with the chance its true pattern gave them, so luck played a part. Suppose instead that the pattern alone decided: every student on the pass side of its line, where 0.9 × (study − 5) + 0.8 × (sleep − 6.5) is 0 or more, passed, and everyone else failed. Then 4 of the 20 students change result, students 5, 12, 18 and 19:
| Student | Study | Sleep | Pattern’s log-odds | Pattern says | Real result |
|---|---|---|---|---|---|
| 1 | 1.4 | 4.2 | 0.9 × (1.4 − 5) + 0.8 × (4.2 − 6.5) = −3.24 − 1.84 = −5.08 | fail | fail |
| 2 | 2.6 | 5.7 | 0.9 × (2.6 − 5) + 0.8 × (5.7 − 6.5) = −2.16 − 0.64 = −2.8 | fail | fail |
| 3 | 1.6 | 8.7 | 0.9 × (1.6 − 5) + 0.8 × (8.7 − 6.5) = −3.06 + 1.76 = −1.3 | fail | fail |
| 4 | 3.6 | 6.4 | 0.9 × (3.6 − 5) + 0.8 × (6.4 − 6.5) = −1.26 − 0.08 = −1.34 | fail | fail |
| 5 | 6.9 | 4.1 | 0.9 × (6.9 − 5) + 0.8 × (4.1 − 6.5) = 1.71 − 1.92 = −0.21 | fail | pass |
| 6 | 0.8 | 5.9 | 0.9 × (0.8 − 5) + 0.8 × (5.9 − 6.5) = −3.78 − 0.48 = −4.26 | fail | fail |
| 7 | 6 | 8.5 | 0.9 × (6 − 5) + 0.8 × (8.5 − 6.5) = 0.9 + 1.6 = 2.5 | pass | pass |
| 8 | 7.1 | 8.1 | 0.9 × (7.1 − 5) + 0.8 × (8.1 − 6.5) = 1.89 + 1.28 = 3.17 | pass | pass |
| 9 | 6.1 | 5.5 | 0.9 × (6.1 − 5) + 0.8 × (5.5 − 6.5) = 0.99 − 0.8 = 0.19 | pass | pass |
| 10 | 1.9 | 4.1 | 0.9 × (1.9 − 5) + 0.8 × (4.1 − 6.5) = −2.79 − 1.92 = −4.71 | fail | fail |
| 11 | 6.2 | 7.6 | 0.9 × (6.2 − 5) + 0.8 × (7.6 − 6.5) = 1.08 + 0.88 = 1.96 | pass | pass |
| 12 | 3.1 | 7.2 | 0.9 × (3.1 − 5) + 0.8 × (7.2 − 6.5) = −1.71 + 0.56 = −1.15 | fail | pass |
| 13 | 2.8 | 4 | 0.9 × (2.8 − 5) + 0.8 × (4 − 6.5) = −1.98 − 2 = −3.98 | fail | fail |
| 14 | 8.2 | 8.3 | 0.9 × (8.2 − 5) + 0.8 × (8.3 − 6.5) = 2.88 + 1.44 = 4.32 | pass | pass |
| 15 | 8.7 | 4.6 | 0.9 × (8.7 − 5) + 0.8 × (4.6 − 6.5) = 3.33 − 1.52 = 1.81 | pass | pass |
| 16 | 8.6 | 5.7 | 0.9 × (8.6 − 5) + 0.8 × (5.7 − 6.5) = 3.24 − 0.64 = 2.6 | pass | pass |
| 17 | 7.6 | 8.3 | 0.9 × (7.6 − 5) + 0.8 × (8.3 − 6.5) = 2.34 + 1.44 = 3.78 | pass | pass |
| 18 | 6.4 | 6.1 | 0.9 × (6.4 − 5) + 0.8 × (6.1 − 6.5) = 1.26 − 0.32 = 0.94 | pass | fail |
| 19 | 1.9 | 7.9 | 0.9 × (1.9 − 5) + 0.8 × (7.9 − 6.5) = −2.79 + 1.12 = −1.67 | fail | pass |
| 20 | 1.4 | 4.7 | 0.9 × (1.4 − 5) + 0.8 × (4.7 − 6.5) = −3.24 − 1.44 = −4.68 | fail | fail |
Now a straight line separates the passes from the fails. The pattern’s own line does, and so do many others, and every one of them gets all 20 training students right, so training accuracy cannot choose between them. What differs is how close each comes to the students. The pattern’s line passes 0.158 hours from student 9. The line an SVM picks keeps 0.2665 hours from every student, so a new student who lands a little away from the training students is less likely to cross it.
Try it yourself
Set C and watch the street widen or narrow, with each student’s hinge loss worked out, on the students marked by the pattern or by their real results. Then switch to an RBF kernel and raise γ, and watch training and validation accuracy pull apart.
boundary street’s edges
Filled dots passed, hollow dots failed. Ringed: the support vectors.
Street 7.211 hours wide
w = (0.2615, 0.0923), b = −1.7538
Support vectors: 18. Training: 17 of 20 right. Validation: 33 of 40.
objective = ½ × (0.2615² + 0.0923²) + 0.01 × 8.7595 = 0.0385 + 0.0876 = 0.1261
Show the calculation
| Student | Study | Sleep | y | w · x + b | Hinge loss |
|---|---|---|---|---|---|
| 1 | 1.4 | 4.2 | −1 | −1 | 0 |
| 2 | 2.6 | 5.7 | −1 | −0.5478 | 1 − 0.5478 = 0.4522 |
| 3 | 1.6 | 8.7 | −1 | −0.5324 | 1 − 0.5324 = 0.4676 |
| 4 | 3.6 | 6.4 | −1 | −0.2217 | 1 − 0.2217 = 0.7783 |
| 5 | 6.9 | 4.1 | +1 | 0.429 | 1 − 0.429 = 0.571 |
| 6 | 0.8 | 5.9 | −1 | −1 | 0 |
| 7 | 6 | 8.5 | +1 | 0.5997 | 1 − 0.5997 = 0.4003 |
| 8 | 7.1 | 8.1 | +1 | 0.8505 | 1 − 0.8505 = 0.1495 |
| 9 | 6.1 | 5.5 | +1 | 0.349 | 1 − 0.349 = 0.651 |
| 10 | 1.9 | 4.1 | −1 | −0.8785 | 1 − 0.8785 = 0.1215 |
| 11 | 6.2 | 7.6 | +1 | 0.569 | 1 − 0.569 = 0.431 |
| 12 | 3.1 | 7.2 | +1 | −0.2786 | 1 − (−0.2786) = 1.2786 |
| 13 | 2.8 | 4 | −1 | −0.6524 | 1 − 0.6524 = 0.3476 |
| 14 | 8.2 | 8.3 | +1 | 1.1566 | 0 |
| 15 | 8.7 | 4.6 | +1 | 0.9458 | 1 − 0.9458 = 0.0542 |
| 16 | 8.6 | 5.7 | +1 | 1.0212 | 0 |
| 17 | 7.6 | 8.3 | +1 | 0.9997 | 0 |
| 18 | 6.4 | 6.1 | −1 | 0.4828 | 1 − (−0.4828) = 1.4828 |
| 19 | 1.9 | 7.9 | +1 | −0.5278 | 1 − (−0.5278) = 1.5278 |
| 20 | 1.4 | 4.7 | −1 | −0.9539 | 1 − 0.9539 = 0.0461 |
| Total | 8.7595 |
Raise C and the street narrows. On the pattern’s results, from C = 10 it is step 2’s widest street, with no student on it.
Practice problems
Work each problem out on paper, then type your answer and press Check. Every problem has hints and a full solution.
Score: 0 of 10 points
Problem 1
1 pointHow far is the point (2, 3) from the line 3x₁ + 4x₂ − 10 = 0?
Hint 1
distance = |w · x + b| ÷ ||w||, with w = (3, 4) and b = −10.
Solution
w · x + b = 3 × 2 + 4 × 3 − 10 = 6 + 12 − 10 = 8
||w|| = √(3² + 4²) = √25 = 5
distance = 8 ÷ 5 = 1.6
Problem 2
2 pointsAn SVM’s weights are w = (3, 4), scaled so its support vectors give exactly +1 and −1. How wide is its street?
Hint 1
A support vector is 1 ÷ ||w|| from the middle line, and the street has two sides.
Solution
||w|| = √(3² + 4²) = 5
width = 2 ÷ ||w|| = 2 ÷ 5 = 0.4
Problem 3
2 pointsA student who failed (y = -1) has w · x + b = 0.4. What is its hinge loss?
Hint 1
hinge = max(0, 1 − y × (w · x + b)).
Hint 2
y is -1 for a fail, so y × (w · x + b) is negative here.
Solution
y × (w · x + b) = -1 × 0.4 = −0.4
hinge = max(0, 1 − (−0.4)) = 1.4
Problem 4
2 pointsFor x = (1, 2) and z = (3, 1), what is (x · z)², the dot product of their inputs (x₁², √2 x₁x₂, x₂²) and (z₁², √2 z₁z₂, z₂²)?
Hint 1
Work out x · z first, then square it.
Solution
x · z = 1 × 3 + 2 × 1 = 5
(x · z)² = 5² = 25
check: 1 × 9 + 2 × (1 × 2) × (3 × 1) + 4 × 1 = 9 + 12 + 4 = 25
Problem 5
3 pointsWith γ = 0.5, what is the RBF kernel k(x, z) = e^(−γ||x − z||²) for x = (1, 2) and z = (2, 4)? Give it to 2 decimal places.
Hint 1
||x − z||² is the squared distance: square each difference and add.
Hint 2
Multiply it by γ = 0.5, then take e to minus that.
Solution
||x − z||² = (1 − 2)² + (2 − 4)² = 1 + 4 = 5
k = e^(−0.5 × 5) = e^(−2.5) = 0.0821
Programming exercise
Write the pieces of an SVM in plain Python: distances and the margin, the hinge loss and the objective, training by subgradient descent, and the RBF kernel. Save svm.py and test_svm.py in the same folder, fill in each function in svm.py, and run the tests:
python test_svm.py
"""Support vector machines: programming exercise. Write the pieces of a support vector machine in plain Python: a line's valueand distance, the street's width, the hinge loss and the objective, trainingby subgradient descent, and the RBF kernel. Run the tests from this folder: python test_svm.py A point x is a list of two numbers, such as [hours studied, hours slept]. Theweights w are a list of two numbers too, and b is a number. A result y is +1for passed and -1 for failed.""" import math # noqa: F401 (you will need math.hypot and math.exp) def decision(w, b, x): """Return the line's value for x: w[0] * x[0] + w[1] * x[1] + b.""" raise NotImplementedError def distance(w, b, x): """Return how far x is from the line w . x + b = 0: the size of decision(w, b, x), divided by the length of w.""" raise NotImplementedError def margin_width(w): """Return the width of the street, 2 divided by the length of w, for w scaled so the support vectors give +1 and -1.""" raise NotImplementedError def hinge(w, b, x, y): """Return the hinge loss of point x with result y: max(0, 1 - y * decision(w, b, x)).""" raise NotImplementedError def objective(w, b, C, xs, ys): """Return the soft margin's objective: half the squared length of w, plus C times the total hinge loss of the points.""" raise NotImplementedError def train(xs, ys, C, steps, rate): """Train a soft-margin SVM by subgradient descent, and return (w, b). Start from w = [0, 0] and b = 0. Each step, find the points whose y * decision(w, b, x) is less than 1. The objective's slope for w is w minus C times the sum of y * x over those points, and for b it is minus C times the sum of their y. Move w and b against their slopes, by rate times each slope, all at once. """ raise NotImplementedError def rbf(x, z, gamma): """Return the RBF kernel: e to the power of -gamma times the squared distance between x and z.""" raise NotImplementedError def kernel_decision(xs, ys, alphas, b, x, gamma): """Return a kernel SVM's value for x: the sum of alphas[i] * ys[i] * rbf(xs[i], x, gamma) over every point, plus b.""" raise NotImplementedError Stuck? Write decision first: the other functions use it. train moves w and b against the objective’s slope: w’s slope is w minus C times the sum of yᵢxᵢ over the students whose hinge loss is above 0, and b’s is minus C times the sum of their yᵢ. The Solution tab has one way to write each function.
In practice: SVMs in real projects
Scale the inputs. An SVM measures distances, so an input measured in large units drowns out the others, as with k-nearest neighbours in Lesson 6. Standardise each input first, for example with scikit-learn’s StandardScaler in a pipeline, fitted on the training data only.
Choosing C and γ. Try values spaced by factors of 10 (0.01, 0.1, 1, 10 and so on) for both, scored on a validation set or by cross-validation; scikit-learn’s GridSearchCV does this. scikit-learn’s SVC starts at C = 1 and γ = "scale", which is 1 divided by the number of inputs times the variance of all the inputs.
Size and speed. A kernel SVM compares training examples in pairs, so training time grows at least with the square of their number, and past tens of thousands of examples it gets slow. For large or sparse data, such as text, a linear SVM (LinearSVC, or SGDClassifier with hinge loss) scales far better. SVC gives probabilities only if asked (probability=True), by fitting an extra model on top.
Test your knowledge
01What is the margin of a linear classifier, and why maximise it?Show answer
The distance from the boundary to the nearest training examples. Many lines may separate the training data; the one with the widest margin leaves the most room for new examples that land a little away from the training ones.
02What are support vectors?Show answer
The training examples on the edges of the margin, or inside it. The boundary depends only on them: moving any other example, without it crossing into the margin, leaves the boundary where it is.
03What does C control in a soft-margin SVM?Show answer
How much each unit of hinge loss costs against the width of the margin. A small C allows a wide margin with more examples inside it; a large C narrows the margin to make fewer training mistakes, and can overfit.
04What is the kernel trick?Show answer
An SVM uses its inputs only through dot products between examples. A kernel computes the dot product of a larger set of features straight from the original inputs, so the SVM can draw curved boundaries without ever building those features.
05What does γ do in an RBF kernel?Show answer
It sets how quickly similarity falls with distance. A large γ lets each example affect only its close neighbours, so the boundary can wrap around single examples and overfit; a small γ gives smooth boundaries. γ is chosen with C on a validation set.
Exit ticket
One last question on the main idea of the lesson.
An SVM with an RBF kernel and a very large γ gets every training student right. What should you expect on new students?
Show the answer
C: Worse: each student is alike only to its nearest neighbours, so the boundary wraps around the noise. Choose γ on a validation set. In this lesson, γ = 3 gets 100% of the training students right and only 47.5% of the validation students, while γ = 0.1 gets 82.5%.