首页 > 解决方案 > 为 sklearn 的 SVC 使用自定义 rbf 内核函数比内置方法快得多

问题描述

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

从我目前所看到和理解的情况来看,两个版本之间的唯一区别是在内置 rbf 的情况下,不是 sklearn 而是 libsvm 将计算 kernel。将专用内核函数作为超参数传递给 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. 对于我的特定用例(通常是大型数据集和较长的计算时间),这实际上非常有用,因为我可以使用第二种方法运行更多的超参数设置,因为计算时间显着减少。有什么理由不这样做?

标签: pythonperformancescikit-learnsvm

解决方案


我在 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 中实现。


推荐阅读