【问题标题】:Using a custom rbf kernel function for sklearn's SVC is way faster than built-in method为 sklearn 的 SVC 使用自定义 rbf 内核函数比内置方法快得多
【发布时间】:2021-12-09 07:22:30
【问题描述】:

在使用 Scikit-Learn 的 SVC 实现时,我注意到一个相当奇特但可能非常有用的现象。将内置 rbf 内核与 SVC 一起使用比将 自定义 rbf 函数传递给 SVC()数量级。

据我目前所见和了解,两个版本之间的唯一区别是在内置 rbf 的情况下,不是 sklearn 而是 libsvm 将计算内核。将专用内核函数作为超参数传递给 SVC() 会导致内核在 sklearn 中的计算,而不是在 libsvm 中。结果是相同的,但后一种情况只需要一小部分计算时间

示例

我提供了一个示例,以便您可以复制此行为。

我创建了一个模拟我目前正在处理的数据的玩具数据集。顺便说一句,我还处理大约一千个样本但高维(约 50000 个特征)的数据。这导致几乎相同的行为。

import numpy as np
from time import time
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.metrics.pairwise import rbf_kernel
from sklearn.metrics import accuracy_score

# create toy data
n_features = 1000
n_samples = 10000
n_informative = 10
X, y = make_classification(n_samples, n_features, n_informative=n_informative)
gamma = 1 / n_features

内置RBF

首先,让我们使用内置的“rbf”内核来适配 SVC。这可能是人们通常运行 SVC 的方式。

# fit SVC with built-in rbf kernel
svc_built_in = SVC(kernel='rbf', gamma=gamma)
np.random.seed(13)
t1 = time()
svc_built_in.fit(X, y)
acc = accuracy_score(y, svc_built_in.predict(X))
print("Fitting SVC with built-in kernel took {:.1f} seconds".format(time()-t1))
print("Accuracy: {}".format(acc))

自定义RBF函数

其次,让我们做同样的事情,只传递 sklearn 的 rbf 核函数,它应该做的完全一样。

# fit SVC with custom rbf kernel
svc_custom = SVC(kernel=rbf_kernel, gamma=gamma)
np.random.seed(13)
t1 = time()
svc_custom.fit(X, y)
acc = accuracy_score(y, svc_custom.predict(X))
print("Fitting SVC with a custom kernel took {:.1f} seconds".format(time()-t1))
print("Accuracy: {}".format(acc))

结果

这将给出以下结果。

Fitting SVC with built-in kernel took 58.6 seconds
Accuracy: 0.9846
Fitting SVC with a custom kernel took 3.2 seconds
Accuracy: 0.9846

我的问题

  1. 有人知道为什么传递内核函数比使用 libsvm 的内核计算要快得多吗?
  2. 对于我的特定用例(通常是大型数据集和较长的计算时间),这实际上非常有用,因为我可以使用第二种方法运行更多的超参数设置,因为计算时间显着减少。有什么理由不这样做?

【问题讨论】:

标签: python performance scikit-learn svm


【解决方案1】:

我在 sklearn 错误报告 (https://github.com/scikit-learn/scikit-learn/issues/21410) 上收到了一些很好的答案,所以我想在这里分享这些知识。

显然,sklearn(而不是 libsvm)中内核的计算是使用 numpy 完成的。然而,Numpy 会自动使用您机器上的所有可用线程来加速内核计算。当我在具有 32 个线程的机器上运行此分析时,我看到了性能的显着提升。不确定 numpy 是否有其他原因更快(更快或更智能的内存访问或类似的东西),但我可以肯定地确认并行化正在发生。

因此,我对此的看法是,如果您在更大的数据集上运行 SVC,并且可以在您的机器上使用多个线程,则可能值得将内核函数本身而不是字符串说明符传递给 SVC实例。所有标准内核函数都已在metrics.pairwise (https://scikit-learn.org/stable/modules/metrics.html) 的sklearn 中实现。

【讨论】:

    最近更新 更多