IIUC, вы пытаетесь распараллелить этот пример из sklearn
документов. Если это так, то вот один из возможных подходов к адресу
почему даска не работает
и
Любое конструктивное руководство или дополнительные знания по этой проблеме
Общий импорт
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn import preprocessing
from imblearn.over_sampling import SMOTE
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score, GridSearchCV, KFold, train_test_split
from sklearn.neural_network import MLPClassifier
import dask_ml.model_selection as dcv
import time
Данные
- Я определил 3 набора данных, чтобы опробовать реализацию
dask_ml
- размер, # строк, третьего (набор данных 3), который можно регулировать, и может быть произвольно увеличен в зависимости от вашей вычислительной мощности
- Я рассчитал выполнение
dask_ml
, используя только этот набор данных
- приведенный ниже код работает для всех 3 наборов данных
- Набор данных 1 - это немного более длинная версия образца данных в вопросе SO
#### Dataset 1 - longer version of data in the question
d = """gene Tissue Druggable Eigenvalue CADDvalue Catalogpresence Category
ACE 1 1 1 0 1 Certain
ABO 1 0 0 0 0 Likely
TP53 1 1 0 0 0 Possible"""
data = pd.DataFrame([x.split(' ') for x in d.split('\n')])
data.columns = data.loc[0,:]
data.drop(0, axis=0, inplace=True)
data = pd.concat([data]*15)
data = data.drop(["gene"],1)
df = data.iloc[:,0:5]
X = MinMaxScaler().fit_transform(df)
le = preprocessing.LabelEncoder()
encoded_value = le.fit_transform(["Certain", "Likely", "Possible"])
Y = le.fit_transform(data["Category"])
sm = SMOTE(random_state=100)
X_res, y_res = sm.fit_resample(X, Y)
#### Dataset 2 - iris dataset from example in sklearn nested cross validation docs
# Load the dataset
from sklearn.datasets import load_iris
iris = load_iris()
X_res = iris.data
y_res = iris.target
#### Dataset 3 - size (#rows, #columns) is adjustable (I used this to time code execution)
X_res = pd.DataFrame(np.random.rand(300,50), columns=['col_'+str(c+1) for c in list(range(50))])
from random import shuffle
cats = ["paris", "barcelona", "kolkata", "new york", 'sydney']
y_values = cats*int(len(X_res)/len(cats))
shuffle(y_values)
y_res = pd.Series(y_values)
Создание классификаторов - без изменений по коду в вопросе
seed = 7
logreg = LogisticRegression(penalty='l1', solver='liblinear',multi_class='auto')
LR_par= {'penalty':['l1'], 'C': [0.5, 1, 5, 10], 'max_iter':[500, 1000, 5000]}
mlp = MLPClassifier(random_state=seed)
parameter_space = {'hidden_layer_sizes': [(10,20), (10,20,10), (50,)],
'activation': ['tanh', 'relu'],
'solver': ['adam', 'sgd'],
'max_iter': [10000],
'alpha': [0.1, 0.01, 0.001],
'learning_rate': ['constant','adaptive']}
rfc =RandomForestClassifier()
param_grid = {'bootstrap': [True, False],
'max_depth': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, None],
'max_features': ['auto', 'sqrt'],
'min_samples_leaf': [1, 2, 4,25],
'min_samples_split': [2, 5, 10, 25],
'n_estimators': [200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000]}
gbm = GradientBoostingClassifier(min_samples_split=25, min_samples_leaf=25)
param = {"loss":["deviance"],
"learning_rate": [0.15,0.1,0.05,0.01,0.005,0.001],
"min_samples_split": [2, 5, 10, 25],
"min_samples_leaf": [1, 2, 4,25],
"max_depth":[10, 20, 30, 40, 50, 60, 70, 80, 90, 100, None],
"max_features":['auto', 'sqrt'],
"criterion": ["friedman_mse"],
"n_estimators":[200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000]
}
svm = SVC(gamma="scale", probability=True)
tuned_parameters = {'kernel':('linear', 'rbf'), 'C':(1,0.25,0.5,0.75)}
inner_cv = KFold(n_splits=10, shuffle=True, random_state=seed)
outer_cv = KFold(n_splits=10, shuffle=True, random_state=seed)
Используйте GridSearchCV
в соответствии с dask_ml
(как первоначально предложено @MRocklin здесь ) - см. dask_ml
документы для dask_ml.model_selection.GridSearchCV
- для краткости я исключаю
KerasClassifier
и вспомогательную функцию baseline_model()
, но мой подход к обработке первого будет таким же, как и для других
models = []
models.append(('MLP', dcv.GridSearchCV(mlp, parameter_space, cv=inner_cv,iid=False, n_jobs=1)))
models.append(('GBM', dcv.GridSearchCV(gbm, param, cv=inner_cv,iid=False, n_jobs=1)))
models.append(('RFC', dcv.GridSearchCV(rfc, param_grid, cv=inner_cv,iid=False, n_jobs=1)))
models.append(('LR', dcv.GridSearchCV(logreg, LR_par, cv=inner_cv, iid=False, n_jobs=1)))
models.append(('SVM', dcv.GridSearchCV(svm, tuned_parameters, cv=inner_cv, iid=False, n_jobs=1)))
Инициализировать дополнительный пустой список для хранения не вложенных результатов резюме
non_nested_results = []
nested_results = []
names = []
scoring = 'accuracy'
X_train, X_test, Y_train, Y_test = train_test_split(X_res, y_res, test_size=0.2, random_state=0)
Joblib и dask
настройка клиента
- Я создал кластер на моей локальной машине
# Create a local cluster
from dask.distributed import Client
client = Client(processes=False, threads_per_worker=4,
n_workers=1, memory_limit='6GB')
from sklearn.externals import joblib
Выполнение вложенного резюме в соответствии с примером sklearn
документов
- первое исполнение
GridSearchCV
- второе использование
cross_val_score
- обратите внимание, что в демонстрационных целях я использовал только модель 1
sklearn
(SVC
) из списка моделей в примере кода в вопросе
start = time.time()
for name, model in [models[-1]]:
# Non_nested parameter search and scoring
with joblib.parallel_backend('dask'):
model.fit(X_train, Y_train)
non_nested_results.append(model.best_score_)
# Nested CV with parameter optimization
nested_score = cross_val_score(model, X=X_train, y=Y_train, cv=outer_cv)
nested_results.append(nested_score.mean())
names.append(name)
msg = "Nested CV Accuracy %s: %f (+/- %f )" %\
(name, np.mean(nested_results)*100, np.std(nested_results)*100)
print(msg)
print('Test set accuracy: {:.2f}'.format(model.score(X_test, Y_test)*100), '%')
print("Best Estimator: \n{}\n".format(model.best_estimator_))
print("Best Parameters: \n{}\n".format(model.best_params_))
print("Best CV Score: \n{}\n".format(model.best_score_))
score_difference = [a_i - b_i for a_i, b_i in zip(non_nested_results, nested_results)]
print("Average difference of {0:6f} with std. dev. of {1:6f}."
.format(np.mean(score_difference), np.std(score_difference)))
print('Total running time of the script: {:.2f} seconds' .format(time.time()-start))
client.close()
Ниже приведены выходные данные (с указанием времени выполнения скрипта) с использованием набора данных 3
Выход + синхронизация без dask
1
Nested CV Accuracy SVM: 20.416667 (+/- 0.000000 )
Test set accuracy: 16.67 %
Best Estimator:
SVC(C=0.75, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='linear',
max_iter=-1, probability=True, random_state=None, shrinking=True,
tol=0.001, verbose=False)
Best Parameters:
{'C': 0.75, 'kernel': 'linear'}
Best CV Score:
0.2375
Average difference of 0.033333 with std. dev. of 0.000000.
Total running time of the script: 23.96 seconds
Выход + синхронизация с dask
(с использованием n_workers=1
и threads_per_worker=4
) 2
Nested CV Accuracy SVM: 18.750000 (+/- 0.000000 )
Test set accuracy: 13.33 %
Best Estimator:
SVC(C=0.5, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=True, random_state=None, shrinking=True,
tol=0.001, verbose=False)
Best Parameters:
{'C': 0.5, 'kernel': 'rbf'}
Best CV Score:
0.1916666666666667
Average difference of 0.004167 with std. dev. of 0.000000.
Total running time of the script: 8.84 seconds
Выход + синхронизация с dask
(с использованием n_workers=4
и threads_per_worker=4
) 2
Nested CV Accuracy SVM: 23.333333 (+/- 0.000000 )
Test set accuracy: 21.67 %
Best Estimator:
SVC(C=0.25, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='linear',
max_iter=-1, probability=True, random_state=None, shrinking=True,
tol=0.001, verbose=False)
Best Parameters:
{'C': 0.25, 'kernel': 'linear'}
Best CV Score:
0.25
Average difference of 0.016667 with std. dev. of 0.000000.
Total running time of the script: 7.52 seconds
Выход + синхронизация с dask
(с использованием n_workers=1
и threads_per_worker=8
) 2
Nested CV Accuracy SVM: 20.416667 (+/- 0.000000 )
Test set accuracy: 18.33 %
Best Estimator:
SVC(C=1, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='scale', kernel='rbf',
max_iter=-1, probability=True, random_state=None, shrinking=True,
tol=0.001, verbose=False)
Best Parameters:
{'C': 1, 'kernel': 'rbf'}
Best CV Score:
0.23333333333333334
Average difference of 0.029167 with std. dev. of 0.000000.
Total running time of the script: 7.06 seconds
1 использует sklearn.model_selection.GridSearchCV()
и не использует joblib()
2 использует dask_ml.model_selection.GridSearchCV()
для замены sklearn.model_selection.GridSearchCV()
и использует joblib()
Примечания о коде и выводе в этом ответе
- Я заметил в вашем вопросе, у вас был порядок
sklearn.model_selection.GridSearchCV()
и cross_val_score
в обратном порядке, по сравнению с примером в документации
- не уверен, что это повлияет на ваш вопрос слишком сильно, но подумал, что я упомяну это
- У меня нет опыта с вложенной перекрестной проверкой, поэтому я не могу комментировать, является ли
Client(..., n_workers=n, threads_per_worker=m)
с n>1
и / или m=4 or m=8
приемлемым / неправильным
Общие комментарии по использованию dask_ml
(насколько я понимаю)
- Случай 1 : если данные обучения достаточно малы, чтобы поместиться в память на одной машине, , но набор данных тестирования не помещается в память, вы можете использовать оболочку
ParallelPostFit
- читать данные тестирования параллельно в кластер
- делает прогнозы при параллельном тестировании данных, используя всех работников в кластере
- IIUC, этот случай не относится к вашему вопросу
- Случай 2 : если вы хотите использовать
joblib
для обучения большой модели scikit-learn
в кластере (но данные обучения / тестирования помещаются в память) - то есть распределенный scikit-learn
- тогда вы можно использовать кластер для обучения, а код скелета (согласно документам dask_ml
) показан ниже
- IIUC это дело
- имеет отношение к вашему вопросу
- подход, который я использовал в этом ответе
Сведения о системе (используется для выполнения кода)
dask==1.2.0
dask-ml==0.12.0
numpy==1.16.2+mkl
pandas==0.24.0
scikit-learn==0.20.3
sklearn==0.0
OS==Windows 8 (64-bit)
Python version (import platform; print(platform.python_version()))==3.7.2