运行 GridsearchCV 有没有更快的方法
Is there a quicker way of running GridsearchCV
我正在为 sklearn 中的 SVC 优化一些参数,这里最大的问题是在我尝试任何其他参数之前必须等待 30 分钟 运行ges。更糟糕的是,我想在同一个 运行ge 中尝试更多的 c 和 gamma 值(这样我就可以创建更平滑的曲面图),但我知道这只会花费越来越长的时间......当我今天 运行 它时,我将 cache_size 从 200 更改为 600(实际上并不知道它的作用)以查看它是否有所作为。时间减少了大约一分钟。
有什么我可以帮忙的吗?还是我只需要处理很长时间?
clf = svm.SVC(kernel="rbf" , probability = True, cache_size = 600)
gamma_range = [1e-7,1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1e0,1e1]
c_range = [1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3,1e4,1e5]
param_grid = dict(gamma = gamma_range, C = c_range)
grid = GridSearchCV(clf, param_grid, cv= 10, scoring="accuracy")
%time grid.fit(X_norm, y)
returns:
Wall time: 32min 59s
GridSearchCV(cv=10, error_score='raise',
estimator=SVC(C=1.0, cache_size=600, class_weight=None, coef0=0.0, degree=3, gamma=0.0,
kernel='rbf', max_iter=-1, probability=True, random_state=None,
shrinking=True, tol=0.001, verbose=False),
fit_params={}, iid=True, loss_func=None, n_jobs=1,
param_grid={'C': [0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0], 'gamma': [1e-07, 1e-06, 1e-05, 0.0001, 0.001, 0.01, 0.1, 1.0, 10.0]},
pre_dispatch='2*n_jobs', refit=True, score_func=None,
scoring='accuracy', verbose=0)
几件事:
- 10 倍 CV 太过分了,会导致您为每个参数组拟合 10 个模型。通过切换到 5 倍或 3 倍 CV(即
GridSearchCV
调用中的 cv=3
),您可以获得即时 2-3 倍的加速,而性能估计没有任何有意义的差异。
- 每轮尝试更少的参数选项。对于 9x9 组合,您要在每个 运行 上尝试 81 种不同的组合。通常,您会在规模的一端或另一端发现更好的性能,因此可以从 3-4 个选项的粗略网格开始,然后在您开始确定对您的数据更感兴趣的区域时变得更精细。 3x3 选项意味着 9 倍加速比你现在正在做的。
- 您可以通过在
GridSearchCV
调用中将 njobs
设置为 2+ 来获得微不足道的加速,这样您就可以同时 运行 多个模型。根据您的数据大小,您可能无法将其增加得太高,并且您不会看到将其增加到超过您 运行ning 的核心数量的改进,但您可能 trim 有点时间。
您还可以在 SVC 估计器内部设置 probability=False 以避免在内部应用昂贵的 Platt 校准。
(如果具有 运行 predict_proba 的能力至关重要,请使用 refit=False
执行 GridSearchCv,并在根据测试集上的模型质量选择最佳参数集后,重新训练概率为 True 的最佳估计器训练集。)
另一个步骤是使用 RandomizedSearchCV
而不是 GridSearchCV
,这将允许您在大致相同的时间达到更好的模型质量(由 n_iters
参数控制)。
并且,如前所述,使用 n_jobs=-1
除了其他答案(例如不使用 10 倍 CV 和每轮使用更少的参数选项)之外,还有其他方法可以加速您的模型。
并行化您的代码
Randy 提到可以使用 n_jobs 来并行化您的训练(这取决于您计算机上的核心数)。与下面代码的唯一区别是它使用 n_jobs = -1
自动为每个内核创建 1 个作业。所以如果你有 4 个核心,它会尝试利用所有 4 个核心。下面的代码是在 8 核计算机上 运行。在我的电脑上使用 n_jobs = -1
花费了 18.3 秒,而没有
则需要 2 分 17 秒
import numpy as np
from sklearn import svm
from sklearn import datasets
from sklearn.model_selection import GridSearchCV
rng = np.random.RandomState(0)
X, y = datasets.make_classification(n_samples=1000, random_state=rng)
clf = svm.SVC(kernel="rbf" , probability = True, cache_size = 600)
gamma_range = [1e-7,1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1e0,1e1]
c_range = [1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3,1e4,1e5]
param_grid = dict(gamma = gamma_range, C = c_range)
grid = GridSearchCV(clf, param_grid, cv= 10, scoring="accuracy", n_jobs = -1)
%time grid.fit(X, y)
请注意,如果您有权访问集群,则可以使用 Dask or Ray 分发您的训练。
不同的超参数优化技术
您的代码使用 GridSearchCV which is an exhaustive search over specified parameter values for an estimator. Scikit-Learn also has RandomizedSearchCV 从具有指定分布的参数 space 中抽取给定数量的候选样本。对下面的代码示例使用随机搜索花费了 3.35 秒。
import numpy as np
from sklearn import svm
from sklearn import datasets
from sklearn.model_selection import RandomizedSearchCV
rng = np.random.RandomState(0)
X, y = datasets.make_classification(n_samples=1000, random_state=rng)
clf = svm.SVC(kernel="rbf" , probability = True, cache_size = 600)
gamma_range = [1e-7,1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1e0,1e1]
c_range = [1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3,1e4,1e5]
param_grid = dict(gamma = gamma_range, C = c_range)
grid = RandomizedSearchCV(clf, param_grid, cv= 10, scoring="accuracy", n_jobs = -1)
%time grid.fit(X, y)
图片来自documentation.
最近(scikit-learn 0.24.1 2021 年 1 月),scikit-learn 添加了实验性超参数搜索估计器,将网格搜索减半 (HalvingGridSearchCV) and halving random search (HalvingRandomSearch)。这些技术可用于使用连续减半来搜索参数 space。上图显示所有超参数候选者在第一次迭代时都使用少量资源进行评估,并且在每个连续 iteration.You 期间选择更有希望的候选者并给予更多资源可以通过升级你的 scikit-learn (pip install --upgrade scikit-learn
)
我正在为 sklearn 中的 SVC 优化一些参数,这里最大的问题是在我尝试任何其他参数之前必须等待 30 分钟 运行ges。更糟糕的是,我想在同一个 运行ge 中尝试更多的 c 和 gamma 值(这样我就可以创建更平滑的曲面图),但我知道这只会花费越来越长的时间......当我今天 运行 它时,我将 cache_size 从 200 更改为 600(实际上并不知道它的作用)以查看它是否有所作为。时间减少了大约一分钟。
有什么我可以帮忙的吗?还是我只需要处理很长时间?
clf = svm.SVC(kernel="rbf" , probability = True, cache_size = 600)
gamma_range = [1e-7,1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1e0,1e1]
c_range = [1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3,1e4,1e5]
param_grid = dict(gamma = gamma_range, C = c_range)
grid = GridSearchCV(clf, param_grid, cv= 10, scoring="accuracy")
%time grid.fit(X_norm, y)
returns:
Wall time: 32min 59s
GridSearchCV(cv=10, error_score='raise',
estimator=SVC(C=1.0, cache_size=600, class_weight=None, coef0=0.0, degree=3, gamma=0.0,
kernel='rbf', max_iter=-1, probability=True, random_state=None,
shrinking=True, tol=0.001, verbose=False),
fit_params={}, iid=True, loss_func=None, n_jobs=1,
param_grid={'C': [0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0], 'gamma': [1e-07, 1e-06, 1e-05, 0.0001, 0.001, 0.01, 0.1, 1.0, 10.0]},
pre_dispatch='2*n_jobs', refit=True, score_func=None,
scoring='accuracy', verbose=0)
几件事:
- 10 倍 CV 太过分了,会导致您为每个参数组拟合 10 个模型。通过切换到 5 倍或 3 倍 CV(即
GridSearchCV
调用中的cv=3
),您可以获得即时 2-3 倍的加速,而性能估计没有任何有意义的差异。 - 每轮尝试更少的参数选项。对于 9x9 组合,您要在每个 运行 上尝试 81 种不同的组合。通常,您会在规模的一端或另一端发现更好的性能,因此可以从 3-4 个选项的粗略网格开始,然后在您开始确定对您的数据更感兴趣的区域时变得更精细。 3x3 选项意味着 9 倍加速比你现在正在做的。
- 您可以通过在
GridSearchCV
调用中将njobs
设置为 2+ 来获得微不足道的加速,这样您就可以同时 运行 多个模型。根据您的数据大小,您可能无法将其增加得太高,并且您不会看到将其增加到超过您 运行ning 的核心数量的改进,但您可能 trim 有点时间。
您还可以在 SVC 估计器内部设置 probability=False 以避免在内部应用昂贵的 Platt 校准。
(如果具有 运行 predict_proba 的能力至关重要,请使用 refit=False
执行 GridSearchCv,并在根据测试集上的模型质量选择最佳参数集后,重新训练概率为 True 的最佳估计器训练集。)
另一个步骤是使用 RandomizedSearchCV
而不是 GridSearchCV
,这将允许您在大致相同的时间达到更好的模型质量(由 n_iters
参数控制)。
并且,如前所述,使用 n_jobs=-1
除了其他答案(例如不使用 10 倍 CV 和每轮使用更少的参数选项)之外,还有其他方法可以加速您的模型。
并行化您的代码
Randy 提到可以使用 n_jobs 来并行化您的训练(这取决于您计算机上的核心数)。与下面代码的唯一区别是它使用 n_jobs = -1
自动为每个内核创建 1 个作业。所以如果你有 4 个核心,它会尝试利用所有 4 个核心。下面的代码是在 8 核计算机上 运行。在我的电脑上使用 n_jobs = -1
花费了 18.3 秒,而没有
import numpy as np
from sklearn import svm
from sklearn import datasets
from sklearn.model_selection import GridSearchCV
rng = np.random.RandomState(0)
X, y = datasets.make_classification(n_samples=1000, random_state=rng)
clf = svm.SVC(kernel="rbf" , probability = True, cache_size = 600)
gamma_range = [1e-7,1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1e0,1e1]
c_range = [1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3,1e4,1e5]
param_grid = dict(gamma = gamma_range, C = c_range)
grid = GridSearchCV(clf, param_grid, cv= 10, scoring="accuracy", n_jobs = -1)
%time grid.fit(X, y)
请注意,如果您有权访问集群,则可以使用 Dask or Ray 分发您的训练。
不同的超参数优化技术
您的代码使用 GridSearchCV which is an exhaustive search over specified parameter values for an estimator. Scikit-Learn also has RandomizedSearchCV 从具有指定分布的参数 space 中抽取给定数量的候选样本。对下面的代码示例使用随机搜索花费了 3.35 秒。
import numpy as np
from sklearn import svm
from sklearn import datasets
from sklearn.model_selection import RandomizedSearchCV
rng = np.random.RandomState(0)
X, y = datasets.make_classification(n_samples=1000, random_state=rng)
clf = svm.SVC(kernel="rbf" , probability = True, cache_size = 600)
gamma_range = [1e-7,1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1e0,1e1]
c_range = [1e-3,1e-2,1e-1,1e0,1e1,1e2,1e3,1e4,1e5]
param_grid = dict(gamma = gamma_range, C = c_range)
grid = RandomizedSearchCV(clf, param_grid, cv= 10, scoring="accuracy", n_jobs = -1)
%time grid.fit(X, y)
图片来自documentation.
最近(scikit-learn 0.24.1 2021 年 1 月),scikit-learn 添加了实验性超参数搜索估计器,将网格搜索减半 (HalvingGridSearchCV) and halving random search (HalvingRandomSearch)。这些技术可用于使用连续减半来搜索参数 space。上图显示所有超参数候选者在第一次迭代时都使用少量资源进行评估,并且在每个连续 iteration.You 期间选择更有希望的候选者并给予更多资源可以通过升级你的 scikit-learn (pip install --upgrade scikit-learn
)