Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(二)(3)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(二)

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(二)(2)https://developer.aliyun.com/article/1482411


Lasso 回归

最小绝对值收缩和选择算子回归(通常简称为Lasso 回归)是线性回归的另一个正则化版本:就像岭回归一样,它向成本函数添加一个正则化项,但是它使用权重向量的ℓ[1]范数,而不是ℓ[2]范数的平方(参见方程 4-10)。请注意,ℓ[1]范数乘以 2α,而ℓ[2]范数在岭回归中乘以α / m。选择这些因子是为了确保最佳α值与训练集大小无关:不同的范数导致不同的因子(有关更多细节,请参阅Scikit-Learn 问题#15657)。

方程 4-10. Lasso 回归成本函数

J(θ)=MSE(θ)+2α∑i=1nθi

图 4-18 显示了与图 4-17 相同的内容,但用 Lasso 模型替换了岭模型,并使用不同的α值。

图 4-18. 线性(左)和多项式(右)模型,都使用不同级别的 Lasso 正则化

Lasso 回归的一个重要特征是它倾向于消除最不重要特征的权重(即将它们设置为零)。例如,图 4-18 中右侧图中的虚线看起来大致是立方形:高次多项式特征的所有权重都等于零。换句话说,Lasso 回归自动执行特征选择,并输出具有少量非零特征权重的稀疏模型

你可以通过查看图 4-19 来了解这种情况:坐标轴代表两个模型参数,背景轮廓代表不同的损失函数。在左上角的图中,轮廓代表ℓ[1]损失(|θ[1]| + |θ[2]|),随着你靠近任何轴,损失会线性下降。例如,如果你将模型参数初始化为θ[1] = 2 和θ[2] = 0.5,运行梯度下降将等量减少两个参数(如虚线黄线所示);因此θ[2]会先达到 0(因为它最初更接近 0)。之后,梯度下降将沿着槽滚动,直到达到θ[1] = 0(稍微反弹一下,因为ℓ[1]的梯度从不接近 0:对于每个参数,它们要么是-1 要么是 1)。在右上角的图中,轮廓代表套索回归的成本函数(即,MSE 成本函数加上ℓ[1]损失)。小白色圆圈显示了梯度下降优化某些模型参数的路径,这些参数最初设定为θ[1] = 0.25 和θ[2] = -1:再次注意路径如何迅速到达θ[2] = 0,然后沿着槽滚动并最终在全局最优解周围反弹(由红色方块表示)。如果增加α,全局最优解将沿着虚线黄线向左移动,而如果减小α,全局最优解将向右移动(在这个例子中,未正则化 MSE 的最佳参数为θ[1] = 2 和θ[2] = 0.5)。

图 4-19。套索与岭正则化

两个底部图表展示了相同的情况,但使用了ℓ[2]惩罚。在左下角的图中,你可以看到随着我们靠近原点,ℓ[2]损失减少,因此梯度下降直接朝着那个点前进。在右下角的图中,轮廓代表岭回归的成本函数(即,MSE 成本函数加上ℓ[2]损失)。正如你所看到的,随着参数接近全局最优解,梯度变小,因此梯度下降自然减慢。这限制了反弹,有助于岭回归比套索收敛更快。还要注意,当增加α时,最佳参数(由红色方块表示)越来越接近原点,但它们永远不会完全消失。

提示

为了防止在使用套索回归时梯度下降在最后反弹到最优解周围,你需要在训练过程中逐渐减小学习率。它仍然会在最优解周围反弹,但步长会变得越来越小,因此会收敛。

套索成本函数在θ[i] = 0(对于 i = 1, 2, ⋯, n)处不可微,但如果在任何θ[i] = 0 时使用子梯度向量 g⁠¹¹,梯度下降仍然有效。方程 4-11 展示了一个你可以用于套索成本函数的梯度下降的子梯度向量方程。

方程 4-11。套索回归子梯度向量

g(θ,J)=∇θMSE(θ)+2αsign(θ1)sign(θ2)⋮sign(θn)where sign(θi)=-1if θi<00if θi=0+1if θi>0

这里有一个使用Lasso类的小型 Scikit-Learn 示例:

>>> from sklearn.linear_model import Lasso
>>> lasso_reg = Lasso(alpha=0.1)
>>> lasso_reg.fit(X, y)
>>> lasso_reg.predict([[1.5]])
array([1.53788174])

请注意,您也可以使用SGDRegressor(penalty="l1", alpha=0.1)

弹性网回归

弹性网回归是岭回归和套索回归之间的中间地带。正则化项是岭回归和套索回归正则化项的加权和,您可以控制混合比例r。当r=0 时,弹性网等同于岭回归,当r=1 时,它等同于套索回归(方程 4-12)。

方程 4-12。弹性网成本函数

J(θ)=MSE(θ)+r2α∑i=1nθi+(1-r)αm∑i=1nθi2

那么何时使用弹性网回归,或者岭回归、套索回归,或者普通线性回归(即没有任何正则化)?通常最好至少有一点点正则化,因此通常应避免普通线性回归。岭回归是一个很好的默认选择,但如果您怀疑只有少数特征是有用的,您应该更喜欢套索或弹性网,因为它们倾向于将无用特征的权重降至零,正如前面讨论的那样。总的来说,相对于套索,弹性网更受青睐,因为当特征数量大于训练实例数量或者多个特征强相关时,套索可能表现不稳定。

这里有一个使用 Scikit-Learn 的ElasticNet的简短示例(l1_ratio对应混合比例r):

>>> from sklearn.linear_model import ElasticNet
>>> elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5)
>>> elastic_net.fit(X, y)
>>> elastic_net.predict([[1.5]])
array([1.54333232])

早停

一种非常不同的正则化迭代学习算法(如梯度下降)的方法是在验证错误达到最小值时停止训练。这被称为早停止。图 4-20 显示了一个复杂模型(在本例中,是一个高次多项式回归模型)在我们之前使用的二次数据集上使用批量梯度下降进行训练。随着时代的变迁,算法学习,其在训练集上的预测误差(RMSE)下降,以及在验证集上的预测误差也下降。然而,一段时间后,验证错误停止下降并开始上升。这表明模型已经开始过拟合训练数据。通过早停止,您只需在验证错误达到最小值时停止训练。这是一种简单而高效的正则化技术,Geoffrey Hinton 称之为“美丽的免费午餐”。

图 4-20。早停止正则化
提示

对于随机梯度下降和小批量梯度下降,曲线不那么平滑,可能很难知道是否已经达到最小值。一个解决方案是只有在验证错误超过最小值一段时间后(当您确信模型不会再有更好的表现时),然后将模型参数回滚到验证错误最小值的点。

这是早停止的基本实现:

from copy import deepcopy
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import StandardScaler
X_train, y_train, X_valid, y_valid = [...]  # split the quadratic dataset
preprocessing = make_pipeline(PolynomialFeatures(degree=90, include_bias=False),
                              StandardScaler())
X_train_prep = preprocessing.fit_transform(X_train)
X_valid_prep = preprocessing.transform(X_valid)
sgd_reg = SGDRegressor(penalty=None, eta0=0.002, random_state=42)
n_epochs = 500
best_valid_rmse = float('inf')
for epoch in range(n_epochs):
    sgd_reg.partial_fit(X_train_prep, y_train)
    y_valid_predict = sgd_reg.predict(X_valid_prep)
    val_error = mean_squared_error(y_valid, y_valid_predict, squared=False)
    if val_error < best_valid_rmse:
        best_valid_rmse = val_error
        best_model = deepcopy(sgd_reg)

这段代码首先添加多项式特征并缩放所有输入特征,对于训练集和验证集都是如此(代码假定您已将原始训练集分成较小的训练集和验证集)。然后它创建一个没有正则化和较小学习率的SGDRegressor模型。在训练循环中,它调用partial_fit()而不是fit(),以执行增量学习。在每个时代,它测量验证集上的 RMSE。如果低于迄今为止看到的最低 RMSE,则将模型的副本保存在best_model变量中。这个实现实际上并没有停止训练,但它允许您在训练后返回到最佳模型。请注意,使用copy.deepcopy()复制模型,因为它同时复制了模型的超参数和学习参数。相比之下,sklearn.base.clone()只复制模型的超参数。

逻辑回归

正如在第一章中讨论的那样,一些回归算法可以用于分类(反之亦然)。逻辑回归(也称为logit 回归)通常用于估计一个实例属于特定类别的概率(例如,这封电子邮件是垃圾邮件的概率是多少?)。如果估计的概率大于给定阈值(通常为 50%),则模型预测该实例属于该类别(称为正类,标记为“1”),否则预测它不属于该类别(即属于负类,标记为“0”)。这使其成为一个二元分类器。

估计概率

那么逻辑回归是如何工作的呢?就像线性回归模型一样,逻辑回归模型计算输入特征的加权和(加上偏置项),但是不像线性回归模型直接输出结果,它输出这个结果的逻辑(参见方程 4-13)。

方程 4-13。逻辑回归模型估计概率(向量化形式)

p ^ = h θ ( x ) = σ ( θ ⊺ x )

逻辑函数 σ(·) 是一个 S 形函数,输出介于 0 和 1 之间的数字。它的定义如 方程式 4-14 和 图 4-21 所示。

方程式 4-14. 逻辑函数

σ ( t ) = 1 1+exp(-t)

图 4-21. 逻辑函数

逻辑回归模型一旦估计出概率 p^ = hθ,即实例 x 属于正类的概率,它可以轻松地进行预测 ŷ(见 方程式 4-15)。

方程式 4-15. 使用 50% 阈值概率的逻辑回归模型预测

y ^ = 0 if p ^ < 0.5 1 if p ^ ≥ 0.5

注意到当 t < 0 时,σ(t) < 0.5,当 t ≥ 0 时,σ(t) ≥ 0.5,因此使用默认的 50% 概率阈值的逻辑回归模型会在 θ^⊺ x 为正时预测为 1,为负时预测为 0。

注意

得分 t 通常被称为 对数几率。这个名字来自于对数几率函数的定义,即 logit(p) = log(p / (1 – p)),它是逻辑函数的反函数。实际上,如果计算估计概率 p 的对数几率,你会发现结果是 t。对数几率也被称为 对数几率比,因为它是正类估计概率与负类估计概率之间的比值的对数。

训练和成本函数

现在你知道逻辑回归模型如何估计概率并进行预测了。但是它是如何训练的呢?训练的目标是设置参数向量 θ,使模型为正实例(y = 1)估计出高概率,为负实例(y = 0)估计出低概率。这个想法被 方程式 4-16 中的成本函数所捕捉,针对单个训练实例 x

方程式 4-16. 单个训练实例的成本函数

c(θ)=-log(p^)if y=1-log(1-p^)if y=0

这个成本函数是有意义的,因为当 t 接近 0 时,–log(t) 会变得非常大,所以如果模型为正实例估计出接近 0 的概率,成本会很大,如果模型为负实例估计出接近 1 的概率,成本也会很大。另一方面,当 t 接近 1 时,–log(t) 接近 0,所以如果负实例的估计概率接近 0,或者正实例的估计概率接近 1,成本会接近 0,这正是我们想要的。

整个训练集上的成本函数是所有训练实例的平均成本。它可以用一个称为对数损失的单个表达式来表示,如方程 4-17 所示。

方程 4-17。逻辑回归成本函数(对数损失)

J(θ)=-1m∑i=1my(i)logp^(i)+(1-y(i))log1-p^(i)

警告

对数损失不是凭空想出来的。可以用数学方法(使用贝叶斯推断)证明,最小化这种损失将导致具有最大可能性的模型是最优的,假设实例围绕其类的平均值遵循高斯分布。当您使用对数损失时,这是您所做的隐含假设。这种假设错误越大,模型就会越有偏见。同样,当我们使用 MSE 来训练线性回归模型时,我们隐含地假设数据是纯线性的,再加上一些高斯噪声。因此,如果数据不是线性的(例如,如果是二次的),或者噪声不是高斯的(例如,如果异常值不是指数稀有的),那么模型就会有偏见。

坏消息是,没有已知的闭式方程可以计算最小化这个成本函数的θ的值(没有等价于正规方程)。但好消息是,这个成本函数是凸的,因此梯度下降(或任何其他优化算法)保证会找到全局最小值(如果学习率不是太大,并且等待足够长的时间)。成本函数对于j^(th)模型参数θ[j]的偏导数由方程 4-18 给出。

方程 4-18。逻辑成本函数偏导数

数学显示=“block”>∂ ∂θ j J ( θ ) = 1 m ∑ i=1 m σ ( θ ⊺ x (i) ) - y (i) x j (i)

这个方程看起来非常像方程 4-5:对于每个实例,它计算预测误差并将其乘以j^(th)特征值,然后计算所有训练实例的平均值。一旦有包含所有偏导数的梯度向量,您就可以在批量梯度下降算法中使用它。就是这样:您现在知道如何训练逻辑回归模型了。对于随机梯度下降,您将一次处理一个实例,对于小批量梯度下降,您将一次处理一个小批量。

决策边界

我们可以使用鸢尾花数据集来说明逻辑回归。这是一个包含 150 朵三种不同物种鸢尾花(Iris setosaIris versicolorIris virginica)的萼片和花瓣长度和宽度的著名数据集(参见图 4-22)。

图 4-22。三种鸢尾植物物种的花朵⁠¹²

让我们尝试构建一个基于花瓣宽度特征的分类器来检测Iris virginica类型。第一步是加载数据并快速查看:

>>> from sklearn.datasets import load_iris
>>> iris = load_iris(as_frame=True)
>>> list(iris)
['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names',
 'filename', 'data_module']
>>> iris.data.head(3)
 sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)
0                5.1               3.5                1.4               0.2
1                4.9               3.0                1.4               0.2
2                4.7               3.2                1.3               0.2
>>> iris.target.head(3)  # note that the instances are not shuffled
0    0
1    0
2    0
Name: target, dtype: int64
>>> iris.target_names
array(['setosa', 'versicolor', 'virginica'], dtype='<U10')

接下来我们将拆分数据并在训练集上训练逻辑回归模型:

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
X = iris.data[["petal width (cm)"]].values
y = iris.target_names[iris.target] == 'virginica'
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
log_reg = LogisticRegression(random_state=42)
log_reg.fit(X_train, y_train)

让我们看看模型对花朵的估计概率,这些花朵的花瓣宽度从 0 厘米到 3 厘米不等(参见图 4-23):⁠¹³

X_new = np.linspace(0, 3, 1000).reshape(-1, 1)  # reshape to get a column vector
y_proba = log_reg.predict_proba(X_new)
decision_boundary = X_new[y_proba[:, 1] >= 0.5][0, 0]
plt.plot(X_new, y_proba[:, 0], "b--", linewidth=2,
         label="Not Iris virginica proba")
plt.plot(X_new, y_proba[:, 1], "g-", linewidth=2, label="Iris virginica proba")
plt.plot([decision_boundary, decision_boundary], [0, 1], "k:", linewidth=2,
         label="Decision boundary")
[...] # beautify the figure: add grid, labels, axis, legend, arrows, and samples
plt.show()

图 4-23。估计的概率和决策边界

Iris virginica花朵的花瓣宽度(表示为三角形)范围从 1.4 厘米到 2.5 厘米,而其他鸢尾花(用方块表示)通常具有较小的花瓣宽度,范围从 0.1 厘米到 1.8 厘米。请注意,存在一些重叠。大约在 2 厘米以上,分类器非常确信花朵是Iris virginica(输出该类的高概率),而在 1 厘米以下,它非常确信它不是Iris virginica(“非 Iris virginica”类的高概率)。在这两个极端之间,分类器不确定。但是,如果要求它预测类别(使用predict()方法而不是predict_proba()方法),它将返回最有可能的类别。因此,在大约 1.6 厘米处有一个决策边界,两个概率都等于 50%:如果花瓣宽度大于 1.6 厘米,分类器将预测花朵是Iris virginica,否则它将预测它不是(即使它不太自信):

>>> decision_boundary
1.6516516516516517
>>> log_reg.predict([[1.7], [1.5]])
array([ True, False])

图 4-24 显示了相同的数据集,但这次显示了两个特征:花瓣宽度和长度。一旦训练完成,逻辑回归分类器可以根据这两个特征估计新花朵是Iris virginica的概率。虚线代表模型估计 50%概率的点:这是模型的决策边界。请注意,这是一个线性边界。⁠¹⁴ 每条平行线代表模型输出特定概率的点,从 15%(左下角)到 90%(右上角)。所有超过右上线的花朵根据模型有超过 90%的概率是Iris virginica

图 4-24。线性决策边界
注意

控制 Scikit-Learn LogisticRegression模型正则化强度的超参数不是alpha(像其他线性模型一样),而是它的倒数:CC值越高,模型的正则化就越

与其他线性模型一样,逻辑回归模型可以使用ℓ[1]或ℓ[2]惩罚进行正则化。Scikit-Learn 实际上默认添加了ℓ[2]惩罚。

Softmax 回归

逻辑回归模型可以直接泛化为支持多类别,而无需训练和组合多个二元分类器(如第三章中讨论的)。这称为softmax 回归多项式逻辑回归

这个想法很简单:给定一个实例x,Softmax 回归模型首先为每个类别k计算一个分数s**k,然后通过应用softmax 函数(也称为归一化指数函数)来估计每个类别的概率。计算s**k的方程应该看起来很熟悉,因为它就像线性回归预测的方程(参见方程 4-19)。

方程 4-19。类别 k 的 Softmax 分数

s k ( x ) = (θ (k) ) ⊺ x

注意每个类别都有自己专用的参数向量θ^((k))。所有这些向量通常被存储为参数矩阵 Θ 的行。

一旦你计算出每个类别对于实例x的得分,你可以通过将得分通过 softmax 函数(方程 4-20)来估计实例属于类别k的概率p^k。该函数计算每个得分的指数,然后对它们进行归一化(除以所有指数的和)。这些得分通常被称为对数几率或对数几率(尽管它们实际上是未归一化的对数几率)。

方程 4-20. Softmax 函数

p ^ k = σ s(x) k = exps k (x) ∑ j=1 K exps j (x)

在这个方程中:

  • K 是类别的数量。
  • s(x)是包含实例x每个类别得分的向量。
  • σ(s(x))[k]是实例x属于类别k的估计概率,给定该实例每个类别的得分。

就像逻辑回归分类器一样,默认情况下,softmax 回归分类器预测具有最高估计概率的类别(即具有最高得分的类别),如方程 4-21 所示。

方程 4-21. Softmax 回归分类器预测

y ^ = argmax k σ s(x) k = argmax k s

argmax运算符返回最大化函数的变量值。在这个方程中,它返回最大化估计概率σ(s(x))[k]的k值。

提示

softmax 回归分类器一次只预测一个类别(即它是多类别的,而不是多输出的),因此它只能用于具有互斥类别的情况,例如不同种类的植物。你不能用它来识别一张图片中的多个人。

现在你知道模型如何估计概率并进行预测了,让我们来看看训练。目标是让模型估计目标类的概率很高(因此其他类的概率很低)。最小化方程 4-22 中显示的成本函数,称为交叉熵,应该能够实现这个目标,因为当模型估计目标类的概率很低时,它会受到惩罚。交叉熵经常用来衡量一组估计的类别概率与目标类别的匹配程度。

方程 4-22. 交叉熵成本函数

J(Θ)=-1m∑i=1m∑k=1Kyk(i)logp^k(i)

在这个方程中,yk(i)是第i个实例属于第k类的目标概率。一般来说,它要么等于 1,要么等于 0,取决于实例是否属于该类。

注意,当只有两类(K = 2)时,这个成本函数等同于逻辑回归成本函数(对数损失;参见方程 4-17)。

这个成本函数关于θ^((k))的梯度向量由方程 4-23 给出。

方程 4-23. 类别 k 的交叉熵梯度向量

∇ θ (k) J ( Θ ) = 1 m ∑ i=1 m p ^ k (i) - y k (i) x (i)

现在你可以计算每个类别的梯度向量,然后使用梯度下降(或任何其他优化算法)来找到最小化成本函数的参数矩阵Θ

让我们使用 softmax 回归将鸢尾花分类为所有三类。当你在多于两类上训练 Scikit-Learn 的LogisticRegression分类器时,它会自动使用 softmax 回归(假设你使用solver="lbfgs",这是默认值)。它还默认应用ℓ[2]正则化,你可以使用之前提到的超参数C来控制:

X = iris.data[["petal length (cm)", "petal width (cm)"]].values
y = iris["target"]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
softmax_reg = LogisticRegression(C=30, random_state=42)
softmax_reg.fit(X_train, y_train)

所以下次当你发现一朵花瓣长 5 厘米,宽 2 厘米的鸢尾花时,你可以让你的模型告诉你它是什么类型的鸢尾花,它会以 96%的概率回答Iris virginica(第 2 类)(或以 4%的概率回答Iris versicolor):

>>> softmax_reg.predict([[5, 2]])
array([2])
>>> softmax_reg.predict_proba([[5, 2]]).round(2)
array([[0\.  , 0.04, 0.96]])

图 4-25 显示了由背景颜色表示的决策边界。请注意,任意两个类之间的决策边界是线性的。图中还显示了Iris versicolor类的概率,由曲线表示(例如,标有 0.30 的线表示 30% 概率边界)。请注意,模型可以预测估计概率低于 50% 的类。例如,在所有决策边界相交的点,所有类的估计概率均为 33%。

图 4-25. Softmax 回归决策边界

在本章中,你学习了训练线性模型的各种方法,包括回归和分类。你使用闭式方程解决线性回归问题,以及梯度下降,并学习了在训练过程中如何向成本函数添加各种惩罚以对模型进行正则化。在此过程中,你还学习了如何绘制学习曲线并分析它们,以及如何实现早期停止。最后,你学习了逻辑回归和 softmax 回归的工作原理。我们已经打开了第一个机器学习黑匣子!在接下来的章节中,我们将打开更多黑匣子,从支持向量机开始。

练习

  1. 如果你有一个拥有数百万个特征的训练集,你可以使用哪种线性回归训练算法?
  2. 假设你的训练集中的特征具有非常不同的尺度。哪些算法可能会受到影响,以及如何受影响?你可以采取什么措施?
  3. 在训练逻辑回归模型时,梯度下降是否会陷入局部最小值?
  4. 如果让所有梯度下降算法运行足够长的时间,它们会导致相同的模型吗?
  5. 假设你使用批量梯度下降,并在每个时期绘制验证误差。如果你注意到验证误差持续上升,可能出现了什么问题?如何解决?
  6. 当验证误差上升时,立即停止小批量梯度下降是一个好主意吗?
  7. 在我们讨论的梯度下降算法中,哪种算法会最快接近最优解?哪种实际上会收敛?如何使其他算法也收敛?
  8. 假设你正在使用多项式回归。你绘制学习曲线并注意到训练误差和验证误差之间存在很大差距。发生了什么?有哪三种方法可以解决这个问题?
  9. 假设你正在使用岭回归,并且注意到训练误差和验证误差几乎相等且相当高。你会说模型存在高偏差还是高方差?你应该增加正则化超参数α还是减少它?
  10. 为什么要使用:
  1. 是否可以使用岭回归代替普通线性回归(即,没有任何正则化)?
  2. 是否可以使用 Lasso 代替岭回归?
  3. 是否可以使用弹性网络代替 Lasso 回归?
  1. 假设你想要将图片分类为室内/室外和白天/黑夜。你应该实现两个逻辑回归分类器还是一个 softmax 回归分类器?
  2. 使用 NumPy 实现批量梯度下降并进行早期停止以进行 softmax 回归,而不使用 Scikit-Learn。将其应用于鸢尾花数据集等分类任务。

这些练习的解决方案可在本章笔记本的末尾找到,网址为https://homl.info/colab3

¹ 闭式方程仅由有限数量的常数、变量和标准操作组成:例如,a = sin(bc)。没有无限求和、极限、积分等。

² 从技术上讲,它的导数是Lipschitz 连续的。

³ 由于特征 1 较小,改变θ[1]以影响成本函数需要更大的变化,这就是为什么碗沿着θ[1]轴被拉长的原因。

⁴ Eta(η)是希腊字母表的第七个字母。

⁵ 而正规方程只能执行线性回归,梯度下降算法可以用来训练许多其他模型,您将会看到。

⁶ 这种偏差的概念不应与线性模型的偏差项混淆。

⁷ 通常使用符号J(θ)表示没有简短名称的代价函数;在本书的其余部分中,我经常会使用这种符号。上下文将清楚地表明正在讨论哪个代价函数。

⁸ 范数在第二章中讨论。

⁹ 一个全是 0 的方阵,除了主对角线(从左上到右下)上的 1。

¹⁰ 或者,您可以使用Ridge类与"sag"求解器。随机平均梯度下降是随机梯度下降的一种变体。有关更多详细信息,请参阅由不列颠哥伦比亚大学的 Mark Schmidt 等人提出的演示“使用随机平均梯度算法最小化有限和”

¹¹ 您可以将非可微点处的次梯度向量视为该点周围梯度向量之间的中间向量。

¹² 照片来源于相应的维基百科页面。Iris virginica照片由 Frank Mayfield 拍摄(知识共享署名-相同方式共享 2.0),Iris versicolor照片由 D. Gordon E. Robertson 拍摄(知识共享署名-相同方式共享 3.0),Iris setosa照片为公共领域。

¹³ NumPy 的reshape()函数允许一个维度为-1,表示“自动”:该值是从数组的长度和剩余维度推断出来的。

¹⁴ 它是一组点x,使得θ[0] + θ[1]x[1] + θ[2]x[2] = 0,这定义了一条直线。

第五章:支持向量机

支持向量机(SVM)是一个强大且多功能的机器学习模型,能够执行线性或非线性分类、回归,甚至新颖性检测。SVM 在小到中等大小的非线性数据集(即,数百到数千个实例)上表现出色,尤其适用于分类任务。然而,它们在处理非常大的数据集时并不很好,您将看到。

本章将解释 SVM 的核心概念,如何使用它们以及它们的工作原理。让我们开始吧!

线性 SVM 分类

支持向量机背后的基本思想最好通过一些可视化来解释。图 5-1 展示了在第四章末尾介绍的鸢尾花数据集的一部分。这两个类可以很容易地用一条直线分开(它们是线性可分的)。左图显示了三种可能线性分类器的决策边界。决策边界由虚线表示的模型非常糟糕,甚至不能正确地分开这两个类。其他两个模型在这个训练集上表现完美,但它们的决策边界与实例非常接近,因此这些模型在新实例上可能表现不佳。相比之下,右图中的实线代表 SVM 分类器的决策边界;这条线不仅分开了两个类,而且尽可能远离最接近的训练实例。您可以将 SVM 分类器视为在类之间拟合最宽可能的街道(由平行虚线表示)。这被称为大边距分类

图 5-1. 大边距分类

请注意,添加更多训练实例“离开街道”不会对决策边界产生任何影响:它完全由位于街道边缘的实例决定(或“支持”)。这些实例被称为支持向量(它们在图 5-1 中被圈出)。

警告

支持向量机对特征的尺度敏感,如您可以在图 5-2 中看到。在左图中,垂直尺度远大于水平尺度,因此最宽可能的街道接近水平。经过特征缩放(例如,使用 Scikit-Learn 的StandardScaler),右图中的决策边界看起来好多了。

图 5-2. 特征尺度的敏感性

软边距分类

如果我们严格要求所有实例必须远离街道并位于正确的一侧,这被称为硬边距分类。硬边距分类存在两个主要问题。首先,它仅在数据线性可分时有效。其次,它对异常值敏感。图 5-3 展示了鸢尾花数据集中仅有一个额外异常值的情况:在左侧,找到硬边距是不可能的;在右侧,决策边界与图 5-1 中看到的没有异常值的情决策边界非常不同,模型可能不会很好地泛化。

图 5-3. 硬边距对异常值的敏感性

为了避免这些问题,我们需要使用一个更灵活的模型。目标是在尽可能保持街道尽可能宽阔和限制边距违规(即,最终位于街道中间甚至错误一侧的实例)之间找到一个良好的平衡。这被称为软边距分类

在使用 Scikit-Learn 创建 SVM 模型时,您可以指定几个超参数,包括正则化超参数C。如果将其设置为较低的值,则会得到左侧图 5-4 中的模型。如果设置为较高的值,则会得到右侧的模型。正如您所看到的,减少C会使街道变宽,但也会导致更多的间隔违规。换句话说,减少C会导致更多的实例支持街道,因此过拟合的风险较小。但是,如果减少得太多,那么模型最终会欠拟合,就像这里的情况一样:C=100的模型看起来比C=1的模型更容易泛化。

图 5-4. 大间隔(左)与较少间隔违规(右)
提示

如果您的 SVM 模型过拟合,可以尝试通过减少C来对其进行正则化。

以下 Scikit-Learn 代码加载了鸢尾花数据集,并训练了一个线性 SVM 分类器来检测Iris virginica花。该流水线首先对特征进行缩放,然后使用LinearSVCC=1进行训练:

from sklearn.datasets import load_iris
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
iris = load_iris(as_frame=True)
X = iris.data[["petal length (cm)", "petal width (cm)"]].values
y = (iris.target == 2)  # Iris virginica
svm_clf = make_pipeline(StandardScaler(),
                        LinearSVC(C=1, random_state=42))
svm_clf.fit(X, y)

生成的模型在图 5-4 的左侧表示。

然后,像往常一样,您可以使用模型进行预测:

>>> X_new = [[5.5, 1.7], [5.0, 1.5]]
>>> svm_clf.predict(X_new)
array([ True, False])

第一个植物被分类为Iris virginica,而第二个没有。让我们看看 SVM 用于做出这些预测的分数。这些分数衡量了每个实例与决策边界之间的有符号距离:

>>> svm_clf.decision_function(X_new)
array([ 0.66163411, -0.22036063])

LogisticRegression不同,LinearSVC没有predict_proba()方法来估计类概率。也就是说,如果您使用SVC类(稍后讨论)而不是LinearSVC,并将其probability超参数设置为True,那么模型将在训练结束时拟合一个额外的模型,将 SVM 决策函数分数映射到估计概率。在幕后,这需要使用 5 倍交叉验证为训练集中的每个实例生成样本外预测,然后训练一个LogisticRegression模型,因此会显著减慢训练速度。之后,predict_proba()predict_log_proba()方法将可用。

非线性 SVM 分类

尽管线性 SVM 分类器高效且通常表现出色,但许多数据集甚至远非线性可分。处理非线性数据集的一种方法是添加更多特征,例如多项式特征(就像我们在第四章中所做的那样);在某些情况下,这可能会导致一个线性可分的数据集。考虑图 5-5 中的左侧图:它代表一个只有一个特征x[1]的简单数据集。正如您所看到的,这个数据集是线性不可分的。但是,如果添加第二个特征x[2] = (x[1])²,那么得到的 2D 数据集就是完全线性可分的。

图 5-5. 添加特征使数据集线性可分

要使用 Scikit-Learn 实现这个想法,您可以创建一个包含PolynomialFeatures转换器(在“多项式回归”中讨论)、StandardScalerLinearSVC分类器的流水线。让我们在 moons 数据集上测试这个流水线,这是一个用于二元分类的玩具数据集,其中数据点呈两个交错新月形状(参见图 5-6)。您可以使用make_moons()函数生成这个数据集:

from sklearn.datasets import make_moons
from sklearn.preprocessing import PolynomialFeatures
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
polynomial_svm_clf = make_pipeline(
    PolynomialFeatures(degree=3),
    StandardScaler(),
    LinearSVC(C=10, max_iter=10_000, random_state=42)
)
polynomial_svm_clf.fit(X, y)

图 5-6. 使用多项式特征的线性 SVM 分类器

多项式核

添加多项式特征很容易实现,并且可以与各种机器学习算法(不仅仅是 SVM)很好地配合。也就是说,在低多项式度数下,这种方法无法处理非常复杂的数据集,而在高多项式度数下,它会创建大量特征,使模型变得过于缓慢。

幸运的是,在使用 SVM 时,你可以应用一种几乎神奇的数学技术,称为核技巧(稍后在本章中解释)。核技巧使得可以获得与添加许多多项式特征相同的结果,即使是非常高次的,而无需实际添加它们。这意味着特征数量不会组合爆炸。这个技巧由SVC类实现。让我们在 moons 数据集上测试一下:

from sklearn.svm import SVC
poly_kernel_svm_clf = make_pipeline(StandardScaler(),
                                    SVC(kernel="poly", degree=3, coef0=1, C=5))
poly_kernel_svm_clf.fit(X, y)

这段代码使用三次多项式核训练了一个 SVM 分类器,左侧在图 5-7 中表示。右侧是另一个使用十次多项式核的 SVM 分类器。显然,如果你的模型出现过拟合,你可能需要降低多项式次数。相反,如果出现欠拟合,你可以尝试增加它。超参数coef0控制模型受高次项和低次项影响的程度。

图 5-7. 使用多项式核的 SVM 分类器
提示

虽然超参数通常会自动调整(例如使用随机搜索),但了解每个超参数实际上是做什么以及它如何与其他超参数交互是很有帮助的:这样,你可以将搜索范围缩小到一个更小的空间。

相似性特征

解决非线性问题的另一种技术是添加使用相似性函数计算的特征,该函数衡量每个实例与特定“地标”的相似程度,就像我们在第二章中添加地理相似性特征时所做的那样。例如,让我们取之前的一维数据集,在x[1] = -2 和x[1] = 1 处添加两个地标(参见图 5-8 中的左图)。接下来,我们将定义相似性函数为带有γ = 0.3 的高斯 RBF。这是一个钟形函数,从 0(远离地标)变化到 1(在地标处)。

现在我们准备计算新特征。例如,让我们看一下实例x[1] = -1:它距离第一个地标 1,距离第二个地标 2。因此,它的新特征是x[2] = exp(–0.3 × 1²) ≈ 0.74 和x[3] = exp(–0.3 × 2²) ≈ 0.30。图 5-8 中右侧的图显示了转换后的数据集(放弃了原始特征)。如你所见,现在它是线性可分的。

图 5-8. 使用高斯 RBF 的相似性特征

你可能想知道如何选择地标。最简单的方法是在数据集中的每个实例位置创建一个地标。这样做会创建许多维度,从而增加转换后的训练集线性可分的机会。缺点是,一个包含m个实例和n个特征的训练集会转换为一个包含m个实例和m个特征的训练集(假设你放弃了原始特征)。如果你的训练集非常大,最终会得到同样数量的特征。

高斯 RBF 核

与多项式特征方法一样,相似性特征方法可以与任何机器学习算法一起使用,但计算所有额外特征可能会很昂贵(尤其是在大型训练集上)。再次,核技巧发挥了 SVM 的魔力,使得可以获得与添加许多相似性特征相同的结果,但实际上并没有这样做。让我们尝试使用高斯 RBF 核的SVC类:

rbf_kernel_svm_clf = make_pipeline(StandardScaler(),
                                   SVC(kernel="rbf", gamma=5, C=0.001))
rbf_kernel_svm_clf.fit(X, y)

这个模型在图 5-9 的左下角表示。其他图显示了使用不同超参数gammaγ)和C训练的模型。增加gamma会使钟形曲线变窄(参见图 5-8 中的左侧图)。因此,每个实例的影响范围更小:决策边界最终变得更加不规则,围绕个别实例摆动。相反,较小的gamma值会使钟形曲线变宽:实例的影响范围更大,决策边界变得更加平滑。因此,γ就像一个正则化超参数:如果你的模型过拟合,应该减小γ;如果欠拟合,应该增加γ(类似于C超参数)。

图 5-9。使用 RBF 核的 SVM 分类器

其他核存在,但使用得更少。一些核专门用于特定的数据结构。字符串核有时用于对文本文档或 DNA 序列进行分类(例如,使用字符串子序列核或基于 Levenshtein 距离的核)。

提示

有这么多核可供选择,你如何决定使用哪一个?作为一个经验法则,你应该始终首先尝试线性核。LinearSVC类比SVC(kernel="linear")快得多,特别是当训练集非常大时。如果不太大,你也应该尝试核化的 SVM,首先使用高斯 RBF 核;它通常效果很好。然后,如果你有多余的时间和计算能力,你可以尝试使用一些其他核进行超参数搜索。如果有专门针对你的训练集数据结构的核,也要试一试。

SVM 类和计算复杂度

LinearSVC类基于liblinear库,该库实现了线性 SVM 的优化算法。⁠¹ 它不支持核技巧,但随着训练实例数量和特征数量的增加,它的缩放几乎是线性的。其训练时间复杂度大约为O(m × n)。如果需要非常高的精度,算法会花费更长的时间。这由容差超参数ϵ(在 Scikit-Learn 中称为tol)控制。在大多数分类任务中,默认容差是可以接受的。

SVC类基于libsvm库,该库实现了一个支持核技巧的算法。⁠² 训练时间复杂度通常在O(m² × n)和O(m³ × n)之间。不幸的是,这意味着当训练实例数量变大时(例如,数十万个实例),算法会变得非常慢,因此这个算法最适合小型或中等大小的非线性训练集。它对特征数量的缩放效果很好,特别是对于稀疏特征(即每个实例具有很少的非零特征)。在这种情况下,算法的缩放大致与每个实例的平均非零特征数量成比例。

SGDClassifier类默认也执行大边距分类,其超参数,特别是正则化超参数(alphapenalty)和learning_rate,可以调整以产生与线性 SVM 类似的结果。它使用随机梯度下降进行训练(参见第四章),允许增量学习并且使用很少的内存,因此可以用于在 RAM 中无法容纳的大型数据集上训练模型(即用于外存学习)。此外,它的缩放非常好,因为其计算复杂度为O(m × n)。表 5-1 比较了 Scikit-Learn 的 SVM 分类类。

表 5-1。Scikit-Learn 用于 SVM 分类的类比较

类别 时间复杂度 外存支持 需要缩放 核技巧
LinearSVC O(m × n)
SVC O(m² × n) 到 O(m³ × n)
SGDClassifier O(m × n)

现在让我们看看 SVM 算法如何用于线性和非线性回归。

SVM 回归

要将 SVM 用于回归而不是分类,关键是调整目标:不再试图在两个类之间拟合尽可能大的间隔同时限制间隔违规,SVM 回归试图在尽可能多的实例间隔上拟合,同时限制间隔违规(即实例间隔之外)。间隔的宽度由超参数ϵ控制。图 5-10 显示了在一些线性数据上训练的两个线性 SVM 回归模型,一个具有较小的间隔(ϵ = 0.5),另一个具有较大的间隔(ϵ = 1.2)。

图 5-10。SVM 回归

减小ϵ会增加支持向量的数量,从而对模型进行正则化。此外,如果在间隔内添加更多训练实例,不会影响模型的预测;因此,该模型被称为ϵ-不敏感

您可以使用 Scikit-Learn 的LinearSVR类执行线性 SVM 回归。以下代码生成了左侧图中表示的模型图 5-10:

from sklearn.svm import LinearSVR
X, y = [...]  # a linear dataset
svm_reg = make_pipeline(StandardScaler(),
                        LinearSVR(epsilon=0.5, random_state=42))
svm_reg.fit(X, y)

为了处理非线性回归任务,您可以使用核化的 SVM 模型。图 5-11 显示了在随机二次训练集上使用二次多项式核进行 SVM 回归。左图中有一些正则化(即较小的C值),右图中的正则化要少得多(即较大的C值)。

图 5-11。使用二次多项式核的 SVM 回归

以下代码使用 Scikit-Learn 的SVR类(支持核技巧)生成了左侧图中表示的模型图 5-11:

from sklearn.svm import SVR
X, y = [...]  # a quadratic dataset
svm_poly_reg = make_pipeline(StandardScaler(),
                             SVR(kernel="poly", degree=2, C=0.01, epsilon=0.1))
svm_poly_reg.fit(X, y)

SVR类是SVC类的回归等价物,LinearSVR类是LinearSVC类的回归等价物。LinearSVR类与训练集的大小呈线性比例(就像LinearSVC类一样),而SVR类在训练集增长非常大时变得非常慢(就像SVC类一样)。

注意

支持向量机也可以用于新颖性检测,正如您将在第九章中看到的那样。

本章的其余部分将解释 SVM 如何进行预测以及它们的训练算法是如何工作的,从线性 SVM 分类器开始。如果您刚开始学习机器学习,可以安全地跳过这部分,直接转到本章末尾的练习,并在以后想要更深入地了解 SVM 时再回来。

线性 SVM 分类器的内部工作原理

线性 SVM 分类器通过首先计算决策函数θ^⊺ x = θ[0] x[0] + ⋯ + θ[n] x[n]来预测新实例x的类别,其中x[0]是偏置特征(始终等于 1)。如果结果为正,则预测的类别ŷ为正类(1);否则为负类(0)。这与LogisticRegression(在第四章中讨论)完全相同。

注意

到目前为止,我一直使用将所有模型参数放在一个向量θ中的约定,包括偏置项θ[0]和输入特征权重θ[1]到θ[n]。这需要向所有实例添加一个偏置输入x[0] = 1。另一个非常常见的约定是将偏置项b(等于θ[0])和特征权重向量w(包含θ[1]到θ[n])分开。在这种情况下,不需要向输入特征向量添加偏置特征,线性 SVM 的决策函数等于w^⊺ x + b = w[1] x[1] + ⋯ + w[n] x[n] + b。我将在本书的其余部分中使用这种约定。

因此,使用线性 SVM 分类器进行预测非常简单。那么训练呢?这需要找到使街道或边界尽可能宽阔的权重向量w和偏置项b,同时限制边界违规的数量。让我们从街道的宽度开始:为了使其更宽,我们需要使w更小。这在 2D 中可能更容易可视化,如图 5-12 所示。让我们将街道的边界定义为决策函数等于-1 或+1 的点。在左图中,权重w[1]为 1,因此w[1] x[1] = -1 或+1 的点是x[1] = -1 和+1:因此边界的大小为 2。在右图中,权重为 0.5,因此w[1] x[1] = -1 或+1 的点是x[1] = -2 和+2:边界的大小为 4。因此,我们需要尽可能保持w较小。请注意,偏置项b对边界的大小没有影响:调整它只是移动边界,而不影响其大小。

图 5-12. 较小的权重向量导致较大的边界

我们还希望避免边界违规,因此我们需要决策函数对所有正训练实例大于 1,对负训练实例小于-1。如果我们定义t^((i)) = -1 为负实例(当y^((i)) = 0 时),t^((i)) = 1 为正实例(当y^((i)) = 1 时),那么我们可以将这个约束写为t((*i*))(**w**x^((i)) + b) ≥ 1 对所有实例成立。

因此,我们可以将硬间隔线性 SVM 分类器的目标表达为方程 5-1 中的约束优化问题。

方程 5-1. 硬间隔线性 SVM 分类器目标

minimize w,b 1 2 w ⊺ w subject to t (i) ( w ⊺ x (i) + b ) ≥ 1 for i = 1 , 2 , ⋯ , m

注意

我们最小化的是½ w^⊺ w,它等于½∥ w ∥²,而不是最小化∥ w ∥(w的范数)。实际上,½∥ w ∥²具有一个简单的导数(就是w),而∥ w ∥在w = 0 处不可微。优化算法在可微函数上通常效果更好。

为了得到软间隔目标,我们需要为每个实例引入一个松弛变量 ζ^((i)) ≥ 0:⁠³ ζ^((i))衡量第i个实例允许违反边界的程度。现在我们有两个相互冲突的目标:尽量减小松弛变量以减少边界违规,同时尽量减小½ w^⊺ w以增加边界。这就是C超参数的作用:它允许我们定义这两个目标之间的权衡。这给我们带来了方程 5-2 中的约束优化问题。

方程 5-2. 软间隔线性 SVM 分类器目标

最小化 w,b,ζ 1 2 w ⊺ w + C ∑ i=1 m ζ (i) 受限于 满足 t (i) ( w ⊺ x (i) + b ) ≥ 1 - ζ (i) 且 ζ (i) ≥ 0 对于 i = 1 , 2 , ⋯ , m

硬间隔和软间隔问题都是具有线性约束的凸二次优化问题。这些问题被称为二次规划(QP)问题。许多现成的求解器可用于通过使用本书范围之外的各种技术来解决 QP 问题。⁠⁴

使用 QP 求解器是训练 SVM 的一种方法。另一种方法是使用梯度下降来最小化铰链损失平方铰链损失(见图 5-13)。给定正类别(即,t=1)的实例x,如果决策函数的输出ss = w^⊺ x + b)大于或等于 1,则损失为 0。这发生在实例偏离街道并位于正侧时。给定负类别(即,t=-1)的实例,如果s ≤ -1,则损失为 0。这发生在实例偏离街道并位于负侧时。实例距离正确边界越远,损失越高:对于铰链损失,它线性增长,对于平方铰链损失,它二次增长。这使得平方铰链损失对异常值更敏感。但是,如果数据集干净,它往往会更快地收敛。默认情况下,LinearSVC使用平方铰链损失,而SGDClassifier使用铰链损失。这两个类允许您通过将loss超参数设置为"hinge""squared_hinge"来选择损失。SVC类的优化算法找到了与最小化铰链损失类似的解。

图 5-13. 铰链损失(左)和平方铰链损失(右)

接下来,我们将看另一种训练线性 SVM 分类器的方法:解决对偶问题。

对偶问题

给定一个约束优化问题,称为原始问题,可以表达一个不同但密切相关的问题,称为对偶问题。对于对偶问题的解通常给出原始问题解的下界,但在某些条件下,它可以与原始问题具有相同的解。幸运的是,SVM 问题恰好符合这些条件,⁠⁵,因此您可以选择解决原始问题或对偶问题;两者都将有相同的解。方程 5-3 显示了线性 SVM 目标的对偶形式。如果您想了解如何从原始问题推导出对偶问题,请参阅本章笔记本中的额外材料部分。

方程 5-3. 线性 SVM 目标的对偶形式

最小化 α12∑i=1m∑j=1mα(i)α(j)t(i)t(j)x(i)⊺x(j)-∑i=1mα(i)受限于 α(i)≥0 对于所有 i=1,2,…,m 和 ∑i=1mα(i)t(i)=0

一旦找到最小化这个方程的向量α ^(使用 QP 求解器),使用方程 5-4 来计算最小化原始问题的w ^和b^。在这个方程中,n[s]代表支持向量的数量。

方程 5-4. 从对偶解到原始解

w ^ = ∑ i=1 m α ^ (i) t (i) x (i) b ^ = 1 n s ∑ i=1 α ^ (i) >0 m t (i) - w ^ ⊺ x (i)

当训练实例的数量小于特征数量时,对偶问题比原始问题更快解决。更重要的是,对偶问题使核技巧成为可能,而原始问题则不行。那么这个核技巧到底是什么呢?

核化支持向量机

假设你想对一个二维训练集(比如 moons 训练集)应用二次多项式转换,然后在转换后的训练集上训练一个线性 SVM 分类器。方程 5-5 展示了你想应用的二次多项式映射函数ϕ

方程 5-5. 二次多项式映射

ϕ x = ϕ x 1 x 2 = x 1 2 2 x 1 x 2 x 2 2

请注意,转换后的向量是 3D 而不是 2D。现在让我们看看如果我们应用这个二次多项式映射,然后计算转换后向量的点积,2D 向量ab会发生什么(参见方程 5-6)。

方程 5-6. 二次多项式映射的核技巧

ϕ (a) ⊺ ϕ ( b ) = a 1 2 2a 1 a 2 a 2 2 ⊺ b 1 2 2 b 1 b 2 b 2 2 = a 1 2 b 1 2 + 2 a 1 b 1 a 2 b 2 + a 2 2 b 2 2 = a 1 b 1 +a 2 b 2 2 = a 1 a 2 ⊺ b 1 b 2 2 = (a ⊺ b) 2

如何?转换后的向量的点积等于原始向量的点积的平方:ϕ(a)^⊺ ϕ(b) = (a^⊺ b)²。

这里的关键见解是:如果将转换 ϕ 应用于所有训练实例,那么对偶问题(参见方程 5-3)将包含点积 ϕ(x((*i*)))ϕ(x^((j)))。但如果 ϕ 是在方程 5-5 中定义的二次多项式变换,那么你可以简单地用(x (i) ⊺ x (j) ) 2来替换这些转换后向量的点积。因此,你根本不需要转换训练实例;只需在方程 5-3 中用其平方替换点积。结果将严格与你经历转换训练集然后拟合线性 SVM 算法的麻烦完全相同,但这个技巧使整个过程更加高效。

函数Kab)=(a^⊺ b)²是一个二次多项式核。在机器学习中,是一个能够基于原始向量ab计算点积ϕa)^⊺ ϕb)的函数,而无需计算(甚至了解)变换ϕ。方程 5-7 列出了一些最常用的核。

方程 5-7。常见核

线性: K ( a , b ) = a ⊺ b 多项式: K ( a , b ) = γa ⊺ b+r d 高斯 RBF: K ( a , b ) = exp ( - γ a-b 2 ) 双曲正切: K ( a , b ) = tanh γ a ⊺ b + r

我们还有一个问题要解决。方程 5-4 展示了如何在线性 SVM 分类器的情况下从对偶解到原始解的转换。但是如果应用核技巧,你会得到包含ϕx^((i)))的方程。事实上,w 必须具有与*ϕ*(*x*((i)))相同数量的维度,这可能非常庞大甚至无限,因此无法计算。但是,如何在不知道w ^的情况下进行预测呢?好消息是,你可以将方程 5-4 中的w 公式代入新实例**x**((n))的决策函数中,得到一个只涉及输入向量点积的方程。这使得可以使用核技巧(方程 5-8)。

方程 5-8。使用核化 SVM 进行预测

h w ^,b ^ ϕ ( x (n) ) = w ^ ⊺ ϕ ( x (n) ) + b ^ = ∑ i=1 m α ^ (i) t (i) ϕ(x (i) ) ⊺ ϕ ( x (n) ) + b ^ = ∑ i=1 m α ^ (i) t (i) ϕ (x (i) ) ⊺ ϕ ( x (n) ) + b ^ = ∑ i=1 α ^ (i) >0 m α ^ (i) t (i) K ( x (i) , x (n) ) + b ^

请注意,由于α^((i)) ≠ 0 仅对支持向量有效,因此进行预测涉及计算新输入向量 x^((n)) 与仅支持向量的点积,而不是所有训练实例。当然,您需要使用相同的技巧来计算偏置项 b^(方程 5-9)。

方程 5-9。使用核技巧计算偏置项

b ^ = 1 n s ∑ i=1 α ^ (i) >0 m t (i) - w ^ ⊺ ϕ ( x (i) ) = 1 n s ∑ i=1 α ^ (i) >0 m t (i) - ∑ j=1 m α ^ (j) t (j) ϕ(x (j) ) ⊺ ϕ ( x (i) ) = 1 n s ∑ i=1 α ^ (i) >0 m t (i) - ∑ j=1 α ^ (j) >0 m α ^ (j) t (j) K ( x (i) , x (j) )

如果您开始头痛,那是完全正常的:这是核技巧的一个不幸的副作用。

注意

还可以实现在线核化 SVM,能够进行增量学习,如论文“增量和减量支持向量机学习”⁠⁷和“具有在线和主动学习的快速核分类器”中所述。⁠⁸这些核化 SVM 是用 Matlab 和 C++实现的。但对于大规模非线性问题,您可能需要考虑使用随机森林(参见第七章)或神经网络(参见第 II 部分)。

练习

  1. 支持向量机背后的基本思想是什么?
  2. 支持向量是什么?
  3. 在使用 SVM 时为什么重要对输入进行缩放?
  4. SVM 分类器在对一个实例进行分类时能输出置信度分数吗?概率呢?
  5. 您如何在LinearSVCSVCSGDClassifier之间进行选择?
  6. 假设您使用 RBF 核训练了一个 SVM 分类器,但似乎对训练集欠拟合。您应该增加还是减少γgamma)?C呢?
  7. 模型是ϵ-insensitive是什么意思?
  8. 使用核技巧的目的是什么?
  9. 在一个线性可分数据集上训练一个LinearSVC。然后在相同数据集上训练一个SVC和一个SGDClassifier。看看是否可以让它们产生大致相同的模型。
  10. 在葡萄酒数据集上训练一个 SVM 分类器,您可以使用sklearn.datasets.load_wine()加载该数据集。该数据集包含了由 3 个不同的种植者生产的 178 个葡萄酒样本的化学分析:目标是训练一个能够根据葡萄酒的化学分析预测种植者的分类模型。由于 SVM 分类器是二元分类器,您需要使用一对所有来对所有三个类进行分类。您能达到什么准确度?
  11. 在加利福尼亚住房数据集上训练和微调一个 SVM 回归器。您可以使用原始数据集,而不是我们在第二章中使用的调整版本,您可以使用sklearn.datasets.fetch_california_housing()加载该数据集。目标代表数十万美元。由于有超过 20,000 个实例,SVM 可能会很慢,因此在超参数调整中,您应该使用更少的实例(例如 2,000)来测试更多的超参数组合。您最佳模型的 RMSE 是多少?

这些练习的解决方案可以在本章笔记本的末尾找到,网址为https://homl.info/colab3

¹ Chih-Jen Lin 等人,“用于大规模线性 SVM 的双坐标下降方法”,第 25 届国际机器学习会议论文集(2008 年):408–415。

² John Platt,“顺序最小优化:用于训练支持向量机的快速算法”(微软研究技术报告,1998 年 4 月 21 日)。

³ Zeta(ζ)是希腊字母表的第六个字母。

⁴ 要了解更多关于二次规划的知识,您可以开始阅读 Stephen Boyd 和 Lieven Vandenberghe 的书籍凸优化(剑桥大学出版社)或观看 Richard Brown 的系列视频讲座

⁵ 目标函数是凸函数,不等式约束是连续可微的凸函数。

⁶ 如第四章中所解释的,两个向量ab的点积通常表示为a·b。然而,在机器学习中,向量经常被表示为列向量(即单列矩阵),因此点积通过计算a^⊺b来实现。为了与本书的其余部分保持一致,我们将在这里使用这种表示法,忽略了这实际上导致了一个单元格矩阵而不是标量值的事实。

⁷ Gert Cauwenberghs 和 Tomaso Poggio,“增量和减量支持向量机学习”,《第 13 届国际神经信息处理系统会议论文集》(2000 年):388–394。

⁸ Antoine Bordes 等人,“具有在线和主动学习的快速核分类器”,《机器学习研究杂志》6(2005 年):1579–1619。


相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
2天前
|
机器学习/深度学习 算法 TensorFlow
TensorFlow 2keras开发深度学习模型实例:多层感知器(MLP),卷积神经网络(CNN)和递归神经网络(RNN)
TensorFlow 2keras开发深度学习模型实例:多层感知器(MLP),卷积神经网络(CNN)和递归神经网络(RNN)
|
4天前
|
机器学习/深度学习 PyTorch TensorFlow
TensorFlow、Keras 和 Python 构建神经网络分析鸢尾花iris数据集|代码数据分享
TensorFlow、Keras 和 Python 构建神经网络分析鸢尾花iris数据集|代码数据分享
15 0
|
13天前
|
机器学习/深度学习 运维 监控
TensorFlow分布式训练:加速深度学习模型训练
【4月更文挑战第17天】TensorFlow分布式训练加速深度学习模型训练,通过数据并行和模型并行利用多机器资源,减少训练时间。优化策略包括配置计算资源、优化数据划分和减少通信开销。实际应用需关注调试监控、系统稳定性和容错性,以应对分布式训练挑战。
|
15天前
|
机器学习/深度学习 人工智能 算法框架/工具
Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(八)(4)
Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(八)
30 0
Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(八)(4)
|
15天前
|
机器学习/深度学习 算法框架/工具 TensorFlow
Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(七)(4)
Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(七)
46 0
Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(七)(4)
|
4月前
|
机器学习/深度学习 人工智能 API
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:1~5
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:1~5
73 0
|
4月前
|
机器学习/深度学习 存储 人工智能
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(3)
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(3)
81 0
|
4月前
|
机器学习/深度学习 Dart TensorFlow
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(5)
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(5)
73 0
|
3月前
|
机器学习/深度学习 PyTorch TensorFlow
Python中的深度学习:TensorFlow与PyTorch的选择与使用
Python中的深度学习:TensorFlow与PyTorch的选择与使用
|
3月前
|
机器学习/深度学习 数据可视化 TensorFlow
基于tensorflow深度学习的猫狗分类识别
基于tensorflow深度学习的猫狗分类识别
65 1