Запуск 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 дает очень слабые оценки вероятности.
Ответы
Ответ 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 до большого количества сэмплов, как это.
Ответ 5
Некоторые ответы упоминаются с использованием class_weight == 'auto'
. Для версии sklearn выше 0.17 используйте вместо этого class_weight == 'balanced'
:https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html