ML Atlas

Machine learning from zero · Lesson 5.5 · 30 of 33 lessons ready · 12 min

Support vector machines and kernels

In short

An SVM looks for the widest band between the classes. As C grows from 0.01 to 100 the band shrinks from 3.9 to 0.15 cm and the test barely moves.

Warm-up Two questions from earlier lessons. A minute, and it never blocks the lesson.
From lesson 5.4: Naive Bayes: a false assumption, good decisions In versicolor petal length and width correlate with r = 0.80, and the model gets 93.3% of the test flowers right. What follows?

Show the answer

Correct answer: For a decision it is enough that the right species gets the largest product

The false assumption changes the values of the products, but rarely their order when the species lie far apart. The model with correlations gets only a little more right on average.

From lesson 5.3: Gradient boosting: trees that fix each other’s errors True or false: “more boosting rounds always help”.

Show the answer

Correct answer: False, because after a while the extra rounds only fix the noise left

Training falls with every round, the test does not. At step 1, 1 tree is best on validation, and 200 trees give 5944 on the test.

Two iris species, two petal measurements. On the training flowers many straight lines separate them equally well. A support vector machine (SVM) picks the one with the widest empty band around it, the margin. The flowers on the edge of the band, inside it or on the wrong side are the support vectors. Only they set the boundary: you could delete every other flower and the boundary would stay the same. When the classes overlap, the band cannot be empty, so the SVM pays a penalty for every flower inside the band or on the wrong side. The number C sets the price of that penalty. A small C allows a wide band with many violations; a large C insists on keeping flowers on the right side, even at the cost of a narrow band.

Predict, then check A linear SVM tells versicolor from virginica irises by two petal measurements. As C grows from 0.01 to 100, the band shrinks from 3.9 cm to 0.15 cm, and only 4 flowers hold the boundary instead of 70. What happens to the accuracy on the 30 test flowers?
How sure are you?

Interactive lab

This interactive lab runs in a browser with JavaScript enabled. The text around it describes what the lab shows.

Show the answer

Correct answer: It barely changes: at every C the model gets 26 or 27 of the 30 right

Almost unchanged: at all 9 values of C the test is 26 or 27 of 30. The band gets 26 times narrower and the result moves by one flower. On 20 other splits the test accuracy over the values of C differs by at most 2 flowers of 30.

Try it

  • Start with the petals at C = 100. How many flowers hold the boundary, and how wide is the band?
  • Move C down. At which C is validation best, and at which is the band widest for almost the same result?
  • Switch to the sepals. Does any C separate the species here?
  • Go to the wines. Compare „x only”, the features √2·x and x², and the kernel (x·z + 1)². Then switch to the RBF kernel and move γ (how fast the similarity of two wines falls as they move apart) all the way to 1000.

Once you have checked it in the lab, let us name what you see.

The idea in plain words

An SVM does not compute probabilities the way logistic regression does. It draws a boundary and two lines parallel to it, one on each side. The band between them should be as wide as possible, and the flowers should lie outside it, on their own side. A flower that does not fit gets a penalty equal to how deep it went into the band. This is the hinge loss. The model looks for a balance: a wide band on one side, C times the sum of penalties on the other.

At C = 0.01 penalties cost almost nothing. The band is 3.9 cm wide, and all 70 training flowers are support vectors: each one moves the boundary a little. At C = 100 every violation is expensive. The band is 0.15 cm wide, and 4 flowers right next to the boundary hold it. Meanwhile the test changes by one flower. On the petals the species lie far enough apart that almost any sensible line gets the same flowers right.

We choose C like any hyperparameter: by validation, not by the test. The lab runs 5-fold cross-validation inside the 70 training flowers. The best comes at C = 10: 69 of 70. At C = 0.1 it is 68 of 70, and the band is 1.4 cm instead of 0.34 cm. One flower of difference is noise in validation, and a wider band rests the boundary on more flowers. The smallest C goes too far the other way: 64 of 70.

The boundary does not have to be straight. On the wines we only ask whether a wine is cultivar 2 or another one, so there are two classes. Cultivar 2 sits in the middle of the flavanoid axis: cultivar 1 has 2.98 on average, cultivar 2 2.08, cultivar 3 0.78. One threshold cannot cut out the middle, so the linear SVM prefers not to point to cultivar 2 anywhere. Validation: 60.0%, as much as answering „always another cultivar”. Let us replace x with two features: √2·x and x². The wines land on a parabola, and a line in the plane (√2·x, x²) is two thresholds on the axis, an interval. Validation rises to 72.0%.

A kernel does the same without adding columns. The SVM only needs dot products of pairs of examples. A dot product is the sum of the products of matching coordinates of two examples; the SVM uses it as a measure of how similar they are. The kernel (x·z + 1)² gives exactly the dot product of the vectors (1, √2·x, x²), so the boundary comes out identical to the one with the features √2·x and x². This is the kernel trick. The RBF kernel (radial basis function) exp(−γ(x − z)²) measures similarity by distance: γ says how fast the similarity falls as two wines move apart. It corresponds to infinitely many such features. At γ = 3 validation is 78.4%, the best of the eight values of γ, and the test then gives 84.9%. At γ = 0.3, 1 and 10 validation is 76.8%, only 2 wines of 125 fewer. As with C on the irises, that is practically a draw. At γ = 1000 training rises to 89.6% and validation falls to 69.6%. The boundary then breaks into 11 intervals fitted to single wines. The highest test, 86.8%, comes at γ = 100, but choosing by the test is choosing on the data you judge with.

Jak to policzono
  • Irises: Iris (Fisher, 1936; UCI, licence CC BY 4.0), 100 versicolor and virginica flowers. Measurements in centimetres without scaling, because both features share the unit. Stratified split: 70 flowers to learn from, 30 for the test.
  • Wines: Wine (Aeberhard and Forina, 1992; UCI, licence CC BY 4.0), 178 wines, flavanoid content only, C = 1. Split: 125 wines to learn from, 53 for the test. Z-scores come from the learning wines only, and in validation from the learning wines of each fold.
  • Validation: stratified 5-fold cross-validation inside the training part. Model: a soft-margin SVM; the numbers match scikit-learn's SVC.

Why it works

A wide band is regularisation, like the ridge penalty from lesson 3.4. The band is 2/‖w‖ wide, so a wide band means small weights and a boundary that depends less on single flowers. The margin with a penalty for violations was described by Cortes and Vapnik (1995). The kernel trick came to SVMs earlier, from Boser, Guyon and Vapnik (1992): since the model only uses dot products, every dot product can be replaced by a kernel.

That C changes the geometry more than the result is not an accident of one split. On 20 other iris splits the test accuracy over the 9 values of C differs by at most 2 flowers of 30, while the band shrinks from 3.8–4.1 cm to 0.17–0.36 cm.

The RBF kernel measures distances, so units matter. The wines have 13 measurements: proline goes up to 1680, hue at most to 1.71. Without scaling the distance is almost proline alone. An RBF SVM on all 13 measurements then gets on 20 splits 67.2% of the validation wines on average. With scaling learned on the learning part only: 97.9%.

Common mistake

True or false: „always take the RBF kernel, it is the most flexible”. False. On the iris petals a linear SVM and an RBF SVM, each with its settings chosen by validation, get 28.5 of 30 test flowers on average over 20 splits. RBF is better on 1 split and worse on 1. The boundary here is almost straight, so flexibility buys nothing and costs something: two hyperparameters to tune instead of one, and easier overfitting (γ = 1000 on the wines). In the code below linear gets 0.950, RBF 0.947, and RBF is better on 2 splits and worse on 4.

The practical lesson: start with a linear kernel or with logistic regression. Reach for RBF when validation shows that the boundary is not straight, as on the wines.

Quiz

Three questions to check yourself. Pick an answer, or open the answer under a question. Keyboard: arrow keys choose, Enter or Space confirms.

1. Which flowers set the boundary of a linear SVM?
Show the answer

Correct answer: Support vectors: flowers on the band edge, inside it or beyond

The other flowers could be removed and the boundary would not change. At C = 100, 4 flowers of 70 hold it.

2. C grows from 0.01 to 100, the band shrinks from 3.9 to 0.15 cm, and the test stays at 26–27 of 30. What follows?
Show the answer

Correct answer: C changes the geometry more than the result: the species lie far apart

On the petals almost any sensible line gets the same flowers right. Even here the smallest C gets 64 of 70 in validation against the best 69, so choose C by validation anyway.

3. True or false: „always take the RBF kernel, it is the most flexible”.
Show the answer

Correct answer: False: on the petals linear does as well, and RBF needs more tuning

On 20 splits both get 28.5 of 30 on average. A large γ leads to overfitting: on the wines at γ = 1000 training is 89.6% and validation 69.6%.

Key takeaways

  • An SVM picks the boundary with the widest band; only the support vectors set it.
  • C is the price of violations: from C = 0.01 to 100 the band shrinks from 3.9 to 0.15 cm while the test barely moves (26–27 of 30).
  • A kernel gives boundaries that are not straight without computing new features; (x·z + 1)² amounts exactly to the features √2·x and x².
  • Choose C, the kernel and γ by validation. RBF overfits at a large γ and errs far more often without scaling.

Going further: formula, code, practice

The math

Soft margin: minimise ½‖w‖² + C · Σᵢ ξᵢ subject to yᵢ(w·xᵢ + b) ≥ 1 − ξᵢ and ξᵢ ≥ 0. The band is 2/‖w‖ wide, and ξᵢ = max(0, 1 − yᵢ f(xᵢ)) is the hinge loss.

In the dual form f(x) = Σᵢ αᵢ yᵢ K(xᵢ, x) + b with 0 ≤ αᵢ ≤ C; the support vectors are the examples with αᵢ > 0. The polynomial kernel K(x, z) = (x·z + 1)² = φ(x)·φ(z) for φ(x) = (1, √2·x, x²), the RBF kernel K(x, z) = exp(−γ‖x − z‖²).

In code (Python)

The same experiment in scikit-learn: the band and the support vectors at three values of C, then a linear and an RBF SVM, each with its settings chosen by validation, on 20 splits, and finally the wines without and with scaling.

import numpy as np
from sklearn.datasets import load_iris, load_wine
from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

iris = load_iris(as_frame=True)
keep = iris.target > 0
X, y = iris.data.loc[keep, ["petal length (cm)", "petal width (cm)"]], iris.target[keep]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, stratify=y, random_state=0)
for C in [0.01, 1, 100]:
    m = SVC(kernel="linear", C=C).fit(X_tr, y_tr)
    print(f"C = {C:>6}: band {2 / np.linalg.norm(m.coef_):.2f} cm, {m.n_support_.sum()} support vectors of {len(y_tr)}, test {m.score(X_te, y_te):.3f}")
grids = {"linear": {"svc__kernel": ["linear"], "svc__C": [0.01, 0.1, 1, 10, 100]},
         "RBF": {"svc__kernel": ["rbf"], "svc__C": [0.1, 1, 10, 100], "svc__gamma": [0.01, 0.1, 1, 10]}}
test = {k: [] for k in grids}
for seed in range(20):
    X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, stratify=y, random_state=seed)
    cv = StratifiedKFold(5, shuffle=True, random_state=seed)
    for k, grid in grids.items():
        search = GridSearchCV(make_pipeline(StandardScaler(), SVC()), grid, cv=cv).fit(X_tr, y_tr)
        test[k].append(search.score(X_te, y_te))
lin, rbf = np.array(test["linear"]), np.array(test["RBF"])
print(f"20 splits, settings chosen in validation: test linear {lin.mean():.3f}, RBF {rbf.mean():.3f}; RBF better {(rbf > lin).sum()}, worse {(rbf < lin).sum()}, equal {(rbf == lin).sum()}")
wine = load_wine()
cv = StratifiedKFold(5, shuffle=True, random_state=0)
for name, model in [("raw", SVC()), ("scaled inside each fold", make_pipeline(StandardScaler(), SVC()))]:
    print(f"wine, RBF SVM, {name}: validation {cross_val_score(model, wine.data, wine.target, cv=cv).mean():.3f}")

Output

C =   0.01: band 4.21 cm, 70 support vectors of 70, test 1.000
C =      1: band 0.71 cm, 22 support vectors of 70, test 1.000
C =    100: band 0.37 cm, 12 support vectors of 70, test 1.000
20 splits, settings chosen in validation: test linear 0.950, RBF 0.947; RBF better 2, worse 4, equal 14
wine, RBF SVM, raw: validation 0.657
wine, RBF SVM, scaled inside each fold: validation 0.983

The split differs from the lab's, so the numbers differ a little too. The picture is the same: the band shrinks from 4.21 to 0.37 cm and the test does not change (1.000). Over 20 splits the RBF kernel does not beat the linear one (0.947 against 0.950). Without scaling the SVM gets 0.657 on the wines, with scaling inside each fold 0.983.

For practitioners
  • In scikit-learn: SVC(kernel="linear") and SVC(kernel="rbf") (by default gamma="scale"), and for large datasets LinearSVC, which learns much faster. According to the documentation the fit time of SVC grows at least quadratically with the number of examples, so at tens of thousands of rows it can become impractical.
  • Always scale the features in a pipeline: make_pipeline(StandardScaler(), SVC()). The scaler in a pipeline learns only on the learning part of every validation (lesson 4.6).
  • Tune C and γ together, on a grid on a log scale (GridSearchCV, lesson 3.5). A large C and a large γ are two roads to overfitting.
  • An SVM does not give probabilities directly. SVC(probability=True) fits them with a separate calibration in cross-validation (lesson 2.4), so it takes longer to learn.

Go deeper in the Atlas

Encyclopedia entries on the ideas in this lesson: