【问题标题】:Making SVM run faster in python使 SVM 在 python 中运行得更快
【发布时间】:2015-10-19 07:23:30
【问题描述】:

在python中使用下面的代码来支持svm:

from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
iris = datasets.load_iris()
X, y = iris.data, iris.target
clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'))
clf.fit(X, y)
proba = clf.predict_proba(X)

但这需要花费大量时间。

实际数据维度

train-set (1422392,29)
test-set (233081,29)

我怎样才能加快速度(并行或其他方式)?请帮忙。 我已经尝试过 PCA 和下采样。

我有 6 节课。 编辑: 找到http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html 但我希望得到概率估计,而 svm 似乎并非如此。

编辑:

from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC,LinearSVC
from sklearn.linear_model import SGDClassifier
import joblib
import numpy as np
from sklearn import grid_search
import multiprocessing
import numpy as np
import math

def new_func(a):                              #converts array(x) elements to (1/(1 + e(-x)))
    a=1/(1 + math.exp(-a))
    return a

if __name__ == '__main__':
    iris = datasets.load_iris()
    cores=multiprocessing.cpu_count()-2
    X, y = iris.data, iris.target                       #loading dataset

    C_range = 10.0 ** np.arange(-4, 4);                  #c value range 
    param_grid = dict(estimator__C=C_range.tolist())              

    svr = OneVsRestClassifier(LinearSVC(class_weight='auto'),n_jobs=cores) ################LinearSVC Code faster        
    #svr = OneVsRestClassifier(SVC(kernel='linear', probability=True,  ##################SVC code slow
    #   class_weight='auto'),n_jobs=cores)

    clf = grid_search.GridSearchCV(svr, param_grid,n_jobs=cores,verbose=2)  #grid search
    clf.fit(X, y)                                                   #training svm model                                     

    decisions=clf.decision_function(X)                             #outputs decision functions
    #prob=clf.predict_proba(X)                                     #only for SVC outputs probablilites
    print decisions[:5,:]
    vecfunc = np.vectorize(new_func)
    prob=vecfunc(decisions)                                        #converts deicision to (1/(1 + e(-x)))
    print prob[:5,:]

编辑 2: user3914041 的回答得出的概率估计非常差。

【问题讨论】:

  • 量化“大量时间”。你用什么来分析你的代码?
  • 你需要全部 140 万个训练样例吗?根据docs,拟合时间复杂度在训练样例数量上超过二次方。此外,您是否需要概率估计?这需要额外运行交叉验证才能生成。
  • OneVsRestClassifier 带有并行选项,但请注意,它可能会占用您的许多资源,因为适应每个模型需要大量时间。尝试根据文档here 设置 n_jobs 参数。
  • 从 Continuum 尝试 MKL 优化,请参阅 store.continuum.io/cshop/mkl-optimizations。他们提供 30 天免费试用,费用为 99 美元。我不是销售代表,但我使用他们的 Anaconda Python 发行版并喜欢它——在 Spark 峰会培训中被推荐。顺便说一句,Spark 支持 SVM,即使在小型 Spark 集群上运行它也会大大提高性能,请参阅 spark.apache.org/docs/1.1.0/…
  • @TrisNefzger Spark 不起作用,因为它不支持 SVM 的概率估计

标签: python scikit-learn svm


【解决方案1】:

如果您想尽可能坚持使用 SVC 并在完整数据集上进行训练,您可以使用在数据子集上训练的 SVC 集合来减少每个分类器的记录数(这显然对复杂)。 Scikit 通过 BaggingClassifier 包装器支持这一点。与单个分类器相比,这应该会给您提供相似(如果不是更好)的准确性,而且训练时间要少得多。也可以使用n_jobs 参数将各个分类器的训练设置为并行运行。

或者,我也会考虑使用随机森林分类器 - 它本身就支持多类分类,它速度很快,并且在适当设置 min_samples_leaf 时给出了相当好的概率估计。

我使用 10 个 SVC 的集合对 iris 数据集进行了 100 次快速测试,每个 SVC 都使用 10% 的数据进行训练。它比单个分类器快 10 倍以上。这些是我在笔记本电脑上得到的数字:

单个 SVC:45 秒

整体 SVC:3 秒

随机森林分类器:0.5s

请看下面我用来生成数字的代码:

import time
import numpy as np
from sklearn.ensemble import BaggingClassifier, RandomForestClassifier
from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC

iris = datasets.load_iris()
X, y = iris.data, iris.target

X = np.repeat(X, 100, axis=0)
y = np.repeat(y, 100, axis=0)
start = time.time()
clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'))
clf.fit(X, y)
end = time.time()
print "Single SVC", end - start, clf.score(X,y)
proba = clf.predict_proba(X)

n_estimators = 10
start = time.time()
clf = OneVsRestClassifier(BaggingClassifier(SVC(kernel='linear', probability=True, class_weight='auto'), max_samples=1.0 / n_estimators, n_estimators=n_estimators))
clf.fit(X, y)
end = time.time()
print "Bagging SVC", end - start, clf.score(X,y)
proba = clf.predict_proba(X)

start = time.time()
clf = RandomForestClassifier(min_samples_leaf=20)
clf.fit(X, y)
end = time.time()
print "Random Forest", end - start, clf.score(X,y)
proba = clf.predict_proba(X)

如果您想确保每条记录在BaggingClassifier 中仅用于训练一次,您可以将bootstrap 参数设置为False。

【讨论】:

  • 感谢您的精彩回答!!我不知道这些。除了速度,准确性也是我最关心的问题。如果可能的话,你能给出一个比较吗?我不受SVC的约束,如果您愿意,也请提出其他好的方法。
  • 您也可以查看sklearn.ensemble.AdaBoostClassifier 以用于随机森林或决策树。
  • 如果你想要一个线性内核,你可以使用sklearn.svm.LinearSVC,它基本相同,但使用比sklearn.svm.SVC更快的库实现。
  • RandomForestClassifier 工作得非常快,但据我了解,它不使用像 SVC 这样的线性/多边形内核,它会降低精度。我可以提高RandomForestClassifier 的准确性吗?
  • 这是一个很棒的方法!:我在 F1 分数上得到了类似的结果;在没有 BaggingClassifier 的情况下运行需要 4 天 3 小时 27 分钟,但使用 BaggingClassifier 运行需要 31 分钟 8 秒
【解决方案2】:

SVM 分类器不那么容易扩展。从文档中,关于sklearn.svm.SVC 的复杂性。

拟合时间复杂度大于二次方 样本,这使得难以扩展到具有超过 a 的数据集 10000 个样本。

在 scikit-learn 中,svm.linearSVC 可以更好地扩展。 显然它可以处理您的数据。

或者,您也可以使用另一个分类器。如果你想要概率估计,我建议逻辑回归。 逻辑回归还具有不需要probability calibration 输出“正确”概率的优点。

编辑:

不知道linearSVC的复杂度,最后在user guide找到了资料:

还要注意,对于线性情况,LinearSVC 中使用的算法由 liblinear 实现比它的效率高得多 基于 libsvm 的 SVC 对应物,几乎可以线性扩展到数百万 样本和/或特征。

要从linearSVC 中获取概率,请查看this link。它距离我上面链接的概率校准指南只有几个链接,并且包含一种估计概率的方法。 即:

    prob_pos = clf.decision_function(X_test)
    prob_pos = (prob_pos - prob_pos.min()) / (prob_pos.max() - prob_pos.min())

请注意,如果没有校准,估计值可能会很差,如链接中所示。

【讨论】:

  • 感谢您的回复!关于缩放@NBartley 之前已经提到过。我尝试过逻辑回归,但准确性较低。
  • 感谢您的回复!但是 linearSVC 没有输出概率估计的选项。
  • 你是对的。一种可能的解决方法是使用decision_function 属性,因为它是在我给出的关于概率校准的链接中使用L​​inearSVC 完成的。不过,您肯定需要校准概率才能有意义。
  • 您能否详细说明校准部分。
  • 如果您有具体问题,请随时提出,但对于这个概念,我将无法比我在帖子中提供的链接做得更好。
【解决方案3】:

您可以使用the kernel_approximation module 将 SVM 扩展到像这样的大量样本。

【讨论】:

    【解决方案4】:

    上面的答案中简要提到过;这是代码:最快的方法是通过the n_jobs parameter:替换行

    clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'))
    

    clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'), n_jobs=-1)
    

    这将使用您计算机上所有可用的 CPU,同时仍执行与以前相同的计算。

    【讨论】:

    • 您会将n_jobs 参数传递给OVR Classifier 还是Bagging Classifier
    • 顶层,在本例中为 OvR
    【解决方案5】:

    对于大型数据集,请考虑使用 LinearSVC 或 SGDClassifier,可能在 Nystroem 转换器之后。

    https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html

    【讨论】:

      猜你喜欢
      • 2020-08-06
      • 1970-01-01
      • 1970-01-01
      • 2020-02-27
      • 2017-11-18
      • 1970-01-01
      • 2013-03-14
      • 2014-11-28
      • 1970-01-01
      相关资源
      最近更新 更多