web-dev-qa-db-fra.com

Rendre SVM plus rapide dans python

En utilisant le code ci-dessous pour svm en python:

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)

Mais cela prend énormément de temps.

Dimensions des données réelles :

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

Comment puis-je l'accélérer (parallèlement ou autrement)? S'il vous plaît aider. J'ai déjà essayé la PCA et le sous-échantillonnage.

J'ai 6 cours. Edit: Trouvé http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html mais je souhaite des estimations de probabilité et il semble que ce ne soit pas le cas pour svm.

Modifier:

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,:]

Edit 2: La réponse de user3914041 donne des estimations de probabilité très faibles.

45
Abhishek Bhatia

Si vous souhaitez vous en tenir au SVC autant que possible et vous entraîner à l'intégralité du jeu de données, vous pouvez utiliser des ensembles de SVC formés sur des sous-ensembles de données pour réduire le nombre d'enregistrements par classificateur (ce qui a apparemment une influence quadratique sur la complexité). Scikit supporte cela avec le wrapper BaggingClassifier. Cela devrait vous donner une précision similaire (sinon meilleure) par rapport à un classificateur unique, avec beaucoup moins de temps de formation. La formation des classificateurs individuels peut également être configurée pour s'exécuter en parallèle à l'aide de la commande n_jobs paramètre.

Alternativement, je considérerais également l’utilisation d’un classifieur Random Forest - il prend en charge la classification multi-classes de manière native, il est rapide et donne de bonnes estimations de probabilité lorsque min_samples_leaf est réglé correctement.

J'ai fait des tests rapides sur l'ensemble de données de l'iris agrandi 100 fois avec un ensemble de 10 SVC, chacun formé sur 10% des données. Il est plus de 10 fois plus rapide qu'un classificateur unique. Voici les chiffres que j'ai sur mon ordinateur portable:

SVC simple: 45s

Ensemble SVC: 3s

Classificateur de forêt aléatoire: 0.5s

Voir ci-dessous le code que j'ai utilisé pour produire les numéros:

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)

Si vous voulez vous assurer que chaque enregistrement n'est utilisé qu'une seule fois pour l'apprentissage du BaggingClassifier, vous pouvez définir le paramètre bootstrap sur False.

78
Alexander Bauer

Les classificateurs SVM ne s'adaptent pas aussi facilement. Des docs, sur la complexité de sklearn.svm.SVC.

La complexité temporelle de l'ajustement est plus que quadratique par rapport au nombre d'échantillons, ce qui rend difficile la mise à l'échelle d'un jeu de données comprenant plus de 10000 échantillons.

En scikit-learn, vous avez svm.linearSVC qui peut mieux évoluer. Apparemment, il pourrait être capable de gérer vos données.

Sinon, vous pouvez simplement aller avec un autre classificateur. Si vous voulez des estimations de probabilité, je suggérerais une régression logistique. La régression logistique a également l'avantage de ne pas nécessiter étalonnage de probabilité pour générer des probabilités "correctes".

Modifier:

Je ne connaissais pas la complexité de linearSVC, enfin j'ai trouvé des informations dans le guide de l'utilisateur :

Notez également que dans le cas linéaire, l'algorithme utilisé dans LinearSVC par l'implémentation linéaire est beaucoup plus efficace que son équivalent SVC basé sur libsvm et qu'il peut évoluer presque linéairement vers des millions d'échantillons et/ou d'entités.

Pour obtenir la probabilité d'un linearSVC, consultez ce lien . Il ne s’agit que de quelques liens par rapport au guide de calibration de probabilité que j’ai lié ci-dessus et qui contient un moyen d’estimer les probabilités. À savoir:

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

Notez que les estimations seront probablement médiocres sans calibration, comme illustré dans le lien.

15
ldirer

Cela a été brièvement mentionné dans la réponse du haut. voici le code: Le moyen le plus rapide de le faire est via le n_jobs paramètre : remplace la ligne

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

avec

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

Cela utilisera tous les processeurs disponibles sur votre ordinateur, tout en effectuant le même calcul qu'auparavant.

7
serv-inc

Vous pouvez utiliser le kernel_approximation module pour adapter les SVM à un grand nombre d’échantillons comme celui-ci.

7
Andreas Mueller

Quelques réponses mentionnées en utilisant class_weight == 'auto'. Pour les versions supérieures à 0.17, utilisez class_weight == 'balanced' à la place: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html

0
Yuhang Lin