【问题标题】:How to gridsearch an estimator embeded in OneVsRestClassifier using Pipeline如何使用管道网格搜索嵌入在 OneVsRestClassifier 中的估计器
【发布时间】:2020-07-14 13:37:13
【问题描述】:

我正在使用 GridSearchCV 进行模型选择和超参数调整。从最初的实验来看,带有 rdf 内核的 SVC 具有最好的性能。问题在于它太慢(200K+)样本。使用 OneVsRestClassifier 可以并行化 SVC (n_jobs)。但是,当我使用 Pipeline 同时测试多个估算器时,gridsearchcv 不适用于此嵌入式估算器。

pipe = Pipeline([('clf', SVC())]) # Placeholder Estimator

# Candidate learning algorithms and their hyperparameters
search_space = [{'clf': [OneVsRestClassifier(SVC(tol=0.1, gamma='scale', probability=True), n_jobs=-1],
                 'clf__kernel': ['rbf', 'linear'],
                 'clf__C': [1, 10, 100]},

                {'clf': [LogisticRegression(tol=0.1, penalty='l1', solver='saga', multi_class='multinomial', n_jobs=8)], 
                 'clf__C': [1, 10, 100]},

                {'clf': [RandomForestClassifier(n_jobs=8)],
                 'clf__n_estimators': [50, 100, 200, 300, 400],
                 'clf__max_depth': [10, 20, 30],
                 'clf__min_samples_leaf': [1, 2, 4],
                 'clf__min_samples_split': [2, 5, 10]},

                {'clf': [MultinomialNB()],
                 'clf__alpha': [0.1, 0.5, 1]}]

gs = GridSearchCV(pipe, search_space, cv=skf, scoring='accuracy', verbose=10)

我有错误

Invalid Parameter __kernel

但是根据GridSearch for an estimator inside a OneVsRestClassifier,这个方法应该可以。我认为是管道搞砸了,因为它基本上在 OneVsRestClassifier 之上添加了另一层。我究竟如何为这个嵌套估计器执行 gridsearchcv?

【问题讨论】:

  • @desertnaut 在我根据输出更改为clf__estimator__kernel 之后,它似乎确实加载了第一个估计器。但我立即收到了ValueError: WRITEBACKIFCOPY base is read-only
  • 好吧,不知道那个...!!!???我们需要minimal reproducible example 来调查它...
  • @desertnaut 但此错误仅在我将“估计器”添加到参数后才会发生。仅使用SVC 而没有OneVsRestClassifier 运行良好。实际上,如果我从OneVsRestClassifier 中取出n_jobs=-1,错误就会消失。但是如果不并行运行,就否定了使用OneVsRestClassifier的目的
  • 您的数据中有多少类和特征?
  • @desertnaut 大约 170 个不同的类。这是一个文本分类,因此数据被转换为稀疏矩阵。矢量化后,我取了前 2000 个特征。

标签: python machine-learning scikit-learn pipeline


【解决方案1】:

按原样,管道在OneVsRestClassifier 中查找参数kernel,但找不到(不足为奇,因为模块没有这样的参数),并引发错误。由于您实际上想要SVC 的参数kernel(以及随后的C),因此您应该更深入一点:将search_space 的前3 个条目更改为:

{'clf': [OneVsRestClassifier(SVC(tol=0.1, gamma='scale', probability=True), n_jobs=-1],
 'clf__estimator__kernel': ['rbf', 'linear'],
 'clf__estimator__C': [1, 10, 100]}

你应该没事的。

但是,无论错误如何,您使用这种方法的理由:

问题在于它太慢(200K+)样本。使用 OneVsRestClassifier 可以并行化 SVC (n_jobs)。

不正确。 OneVsRestClassifier 将并行拟合 n_classes 不同的 SVC 估计器,不是 SVC 本身。实际上,您试图通过在其周围包裹其他东西(此处为 OneVsRestClassifier)来避免瓶颈(SVC),这会增加其自身的额外计算复杂性,只是(不出所料)再次在您面前找到它。

我们可以通过一些虚拟数据的时间来证明这一点 - 让我们尝试一个包含 10K 样本、5 个特征和 3 个类别的真实数据集:

from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.datasets import make_classification

X, y = make_classification(n_samples = 10000, n_features=5, n_redundant=0, n_informative=5,
                             n_classes = 3, n_clusters_per_class=1, random_state=42)

%timeit for x in range(10): SVC().fit(X,y)
# 1 loop, best of 3: 7.72 s per loop

%timeit for x in range(10): OneVsRestClassifier(SVC()).fit(X, y)
# 1 loop, best of 3: 21.1 s per loop

嗯,这就是你的基线差异;现在设置n_jobs=-1 有帮助:

%timeit for x in range(10): OneVsRestClassifier(SVC(), n_jobs=-1).fit(X, y)
# 1 loop, best of 3: 19 s per loop

但是,不出所料,它仅与未并行化的 OneVsRestClassifier 相关,SVC 本身相关。

随着功能和类别的增加,差异越来越大;没有详细说明,这里有 10 个特性和 5 个类(相同的样本数量,10K):

X1, y1 = make_classification(n_samples = 10000, n_features=10, n_redundant=0, n_informative=10,
                             n_classes = 5, n_clusters_per_class=1, random_state=42)

%timeit for x in range(10): SVC().fit(X1,y1)
# 1 loop, best of 3: 10.3 s per loop

%timeit for x in range(10): OneVsRestClassifier(SVC()).fit(X1, y1)
# 1 loop, best of 3: 30.7 s per loop

%timeit for x in range(10): OneVsRestClassifier(SVC(), n_jobs=-1).fit(X1, y1)
# 1 loop, best of 3: 24.9 s per loop

因此,我会认真建议您在这里重新考虑您的方法(和您的目标)。

(Google Colab 中的所有时间)。

【讨论】:

    猜你喜欢
    • 2016-08-29
    • 2012-09-19
    • 2020-03-02
    • 2021-01-12
    • 1970-01-01
    • 2019-08-22
    • 2022-12-19
    • 2016-11-28
    • 2018-10-21
    相关资源
    最近更新 更多