web-dev-qa-db-ja.com

pythonでSVMの実行を高速化する

Pythonのsvmで以下のcodeを使用します。

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 __== '__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による回答では、非常に低い確率推定が得られます。

45
Abhishek Bhatia

可能な限りSVCに固執し、完全なデータセットでトレーニングする場合は、データのサブセットでトレーニングされたSVCのアンサンブルを使用して、分類子ごとのレコード数を減らすことができます(明らかに複雑性に2次的な影響があります)。 ScikitはBaggingClassifierラッパーでそれをサポートしています。これにより、単一の分類器と比較して(改善されていないとしても)同様の精度が得られ、トレーニング時間が大幅に短縮されます。個々の分類子のトレーニングは、n_jobsパラメーターを使用して並行して実行するように設定することもできます。

あるいは、ランダムフォレスト分類器の使用も検討します。これは、マルチクラス分類をネイティブにサポートし、高速で、min_samples_leafが適切に設定されている場合にかなり良い確率推定値を提供します。

私は、10個のSVCのアンサンブルを使用して100回爆破された虹彩データセットで簡単なテストを行い、それぞれがデータの10%でトレーニングを行いました。単一の分類子よりも10倍以上高速です。これらは私のラップトップで得た数字です:

単一のSVC:45秒

アンサンブルSVC:3秒

ランダムフォレスト分類子:0.5秒

数値の生成に使用したコードを以下に示します。

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のトレーニングに1回だけ使用されるようにする場合は、bootstrapパラメーターをFalseに設定できます。

78
Alexander Bauer

SVM分類器はそれほど簡単に拡張できません。ドキュメントから、sklearn.svm.SVCの複雑さについて。

適合時間の複雑さは、サンプル数の2次以上であり、10000サンプル以上のデータセットへのスケーリングが困難です。

Scikit-learnには、svm.linearSVCがあります。どうやらそれはあなたのデータを処理することができる可能性があります。

または、別の分類器を使用することもできます。確率推定が必要な場合は、ロジスティック回帰をお勧めします。ロジスティック回帰には、「適切な」確率を出力するために 確率較正 を必要としないという利点もあります。

編集:

linearSVCの複雑さについて知りませんでしたが、最終的に ユーザーガイド で情報を見つけました。

また、線形の場合、liblinear実装によってLinearSVCで使用されるアルゴリズムは、libsvmベースのSVCカウンターパートよりもはるかに効率的であり、数百万のサンプルや機能にほぼ線形にスケーリングできることに注意してください。

linearSVCから確率を取得するには、 このリンク をチェックアウトします。上記でリンクした確率較正ガイドから数リンク離れているだけで、確率を推定する方法が含まれています。すなわち:

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

リンクに示されているように、推定値はおそらくキャリブレーションなしでは不十分です。

15
ldirer

トップアンサーで簡単に言及されました。コードは次のとおりです。これを行う最も簡単な方法は、 n_jobsパラメータ :行を置き換えることです。

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

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

これにより、以前と同じ計算を実行しながら、コンピューターで使用可能なすべてのCPUが使用されます。

7
serv-inc

_kernel_approximation module SVMをこのような多数のサンプルにスケールアップします。

7
Andreas Mueller

class_weight == 'auto'を使用して言及されたいくつかの回答。 0.17以降のsklearnバージョンの場合は、代わりにclass_weight == 'balanced'を使用してください。 https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html

0
Yuhang Lin