Подтвердить что ты не робот

Запуск SVM быстрее в python

Использование кода ниже для svm в 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)

Но это занимает огромное количество времени.

Фактические размеры данных:

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

Как я могу ускорить его (параллельно или по-другому)? Пожалуйста помоги. Я уже попробовал PCA и понизил дискретизацию.

У меня есть 6 классов. Редактировать: Найдено http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html но я желаю оценок вероятности, и, похоже, это не так для svm.

Edit:

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 дает очень слабые оценки вероятности.

4b9b3361

Ответ 1

Если вы хотите как можно больше придерживаться SVC и тренироваться по полному набору данных, вы можете использовать ансамбли SVC, которые обучаются на подмножествах данных, чтобы уменьшить количество записей в классификаторе (что, по-видимому, оказывает квадратичное влияние на сложности). Scikit поддерживает это с помощью оболочки BaggingClassifier. Это должно дать вам аналогичную (если не лучшую) точность по сравнению с одним классификатором с гораздо меньшим временем обучения. Обучение отдельных классификаторов также можно запускать параллельно с помощью параметра n_jobs.

В качестве альтернативы, я бы также рассмотрел использование классификатора Random Forest - он поддерживает классификацию нескольких классов изначально, он быстрый и дает довольно хорошие оценки вероятности, когда min_samples_leaf устанавливается соответствующим образом.

Я провел быстрые тесты по набору данных диафрагмы, взорванному 100 раз, с ансамблем из 10 SVC, каждый из которых обучался на 10% данных. Это более чем в 10 раз быстрее, чем один классификатор. Это номера, которые я получил на своем ноутбуке:

Одиночный SVC: 45 с

Ансамбль SVC: 3s

Классификатор случайного леса: 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, вы можете установить для параметра bootstrap значение False.

Ответ 2

Классификаторы SVM не масштабируются так легко. Из документов, о сложности sklearn.svm.SVC.

Сложная временная сложность больше, чем квадратичная с числом образцы, которые затрудняют масштабирование до набора данных с более чем пара 10000 образцов.

В scikit-learn у вас есть svm.linearSVC, который может масштабироваться лучше. По-видимому, он сможет обрабатывать ваши данные.

В качестве альтернативы вы можете просто пойти с другим классификатором. Если вы хотите оценки вероятности, я бы предложил логистическую регрессию. Логистическая регрессия также имеет то преимущество, что не нужна калибровка вероятности для вывода "правильных" вероятностей.

Edit:

Я не знал о сложности linearSVC, наконец, нашел информацию в руководстве пользователя:

Отметим также, что для линейного случая алгоритм, используемый в LinearSVC, равен liblinear реализация намного эффективнее, чем ее на основе SVC, основанной на libsvm, и может масштабироваться почти линейно до миллионов образцов и/или функций.

Чтобы получить вероятность из linearSVC проверить эту ссылку. Это всего лишь пара ссылок от руководства по калибровке вероятности I, связанного выше, и содержит способ оценки вероятностей. А именно:

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

Обратите внимание, что оценки, вероятно, будут плохими без калибровки, как показано в ссылке.

Ответ 3

Это было кратко упомянуто в главном ответе; Вот код: самый быстрый способ сделать это - через параметр 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)

При этом будут использоваться все доступные процессоры на вашем компьютере, но при этом будут выполняться те же вычисления, что и раньше.

Ответ 4

Вы можете использовать модуль kernel_approximation, чтобы масштабировать SVM до большого количества сэмплов, как это.