为什么scikit-learn的SVM.SVC()运行极其缓慢?

52

我曾尝试使用SVM分类器对大约10万个样本的数据进行训练,但我发现它非常缓慢,即使过了两个小时也没有响应。当数据集大约有1k个样本时,我可以立即得到结果。我还尝试了SGDClassifier和朴素贝叶斯,这两种方法都非常快速,我可以在几分钟内得到结果。您能解释一下这种现象吗?


2个回答

74

SVM-learning的一般注释

sklearn中SVC默认使用非线性核进行SVM训练,其复杂度大约为O(n_samples^2 * n_features)由sklearn开发人员之一给出的这个近似值的问题链接。 这适用于libsvm内部使用的SMO算法,该算法是解决此类问题的sklearn核心求解器。

这在不使用内核并使用sklearn.svm.LinearSVC(基于liblinear)或sklearn.linear_model.SGDClassifier时会发生很大变化。
因此,我们可以进行一些数学计算来近似1k和100k样本之间的时间差异。
1k = 1000^2 = 1.000.000 steps = Time X
100k = 100.000^2 = 10.000.000.000 steps = Time X * 10000 !!!

这只是一个近似值,可能会更糟或更好(例如,设置缓存大小; 把内存与速度之间进行权衡)!

Scikit-learn特定备注

由于scikit-learn在幕后为我们做了很多好事,所以情况也可能更加复杂。上述内容适用于经典的两类支持向量机。如果你正在尝试学习一些多类数据,则scikit-learn将自动使用OneVsRest或OneVsAll方法来完成此任务(因为核心SVM算法不支持此功能)。请阅读scikit-learn文档以了解此部分。

同样的警告适用于生成概率:SVM不会自然地为最终预测产生概率。因此,为了使用这些概率(通过参数激活),scikit-learn使用了一个称为Platt scaling的重型交叉验证过程,这也需要很长时间!

Scikit-learn文档

由于sklearn有最好的文档之一,因此通常在这些文档中有很好的部分来解释这样的问题(link):

enter image description here


4
对于拥有大量数据的用户来说,scikit-learn 不是最佳选择。我也遇到了这个问题。800K 个样本,需要花费我2个小时的时间。 - GoingMyWay
2
@GoingMyWay,那是否存在更快的替代方法? - Riley
4
我认为这是对答案的误解。使用内核的SVM算法的时间复杂性是一个普遍的事实,与使用哪个软件包无关。这是使用SVM模型固有的问题,无论是来自sklearn还是R中的某些东西。除非你知道一种用于优化SVM参数的算法可以奇迹般地改善并且sklearn尚未实现它,否则使用另一个软件包不会带来任何好处。关于SVC,再次强调,“一对多”或其他替代方案本质上是使用多类SVM所必需的。 - Marses
1
@GoingMyWay,听起来你的问题可能是你认为使用带核的SVM太慢了,但这不是sklearn的问题。sklearn只是实现算法,如果算法在你的情况下表现不佳,那是因为你选择了错误的算法。我很想知道自从你发表评论以来,是否已经找到了没有提到缺点的解决方案。 - Marses
最重要的一点是:rbf是默认内核。对于第一遍尝试(甚至可能是最终解决方案,具体取决于问题),线性核可能是您想要的,它将节省大量时间。我个人更喜欢让用户指定核参数而不是使用默认值,但是有反对意见,我在该库的开发中没有任何影响力。 - demongolem

4
如果您使用英特尔CPU,则英特尔已为此提供了解决方案。 Scikit-learn的英特尔扩展为您提供了一种加速现有scikit-learn代码的方式。加速是通过打补丁实现的:用扩展提供的优化版本替换默认的scikit-learn算法。 您应该按照以下步骤操作: 首先安装intelex package for sklearn。
pip install scikit-learn-intelex

现在只需在程序顶部添加以下行即可。
from sklearnex import patch_sklearn 

patch_sklearn()

现在运行程序,速度比以前快得多。

您可以从以下链接了解更多信息: https://intel.github.io/scikit-learn-intelex/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接