使用GridSearchCV提前停止使用保留的CV集进行验证

2024-06-17 09:17:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在scikit learns中使用early-stopping-选项GridSearchCV-方法。下面的SO-thread中显示了一个示例:

import xgboost as xgb
from sklearn.model_selection import GridSearchCV

trainX= [[1], [2], [3], [4], [5]]
trainY = [1, 2, 3, 4, 5]

testX = trainX 
testY = trainY

param_grid = {"subsample" : [0.5, 0.8],
              "n_estimators" : [600]}

fit_params = {"early_stopping_rounds":1,
             "eval_set" : [[testX, testY]]}


model = xgb.XGBRegressor()
gridsearch = GridSearchCV(estimator  = xgb.XGBRegressor(), 
                          param_grid=param_grid,
                          fit_params=fit_params,                          
                          verbose=1,                          
                          cv=2)
gridsearch.fit(trainX,trainY)

但是,我想使用交叉验证过程的保留集作为验证集。有没有办法在GridSearchCV中指定它?在


Tags: importmodelparamtrainyparamsgridfitearly
2条回答

以前,我建立了一个类,包装“HyperOpt”以满足我的需要。在

我会尽快把它最小化,这样你就可以使用它了。下面是代码和一些注释,以帮助您解决问题:

import numpy as np
from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
import xgboost as xgb
max_float_digits = 4


def rounded(val):
    return '{:.{}f}'.format(val, max_float_digits)


class HyperOptTuner(object):
    """
    Tune my parameters!
    """
    def __init__(self, dtrain, dvalid, early_stopping=200, max_evals=200):
        self.counter = 0
        self.dtrain = dtrain
        self.dvalid = dvalid
        self.early_stopping = early_stopping
        self.max_evals = max_evals
        self.tuned_params = None


    def score(self, params):
        self.counter += 1
        # Edit params
        print("Iteration {}/{}".format(self.counter, self.max_evals))
        num_round = int(params['n_estimators'])
        del params['n_estimators']

        watchlist = [(self.dtrain, 'train'), (self.dvalid, 'eval')]
        model = xgb.train(params, self.dtrain, num_round, evals=watchlist, early_stopping_rounds=self.early_stopping,
                          verbose_eval=False)
        n_epoach = model.best_ntree_limit
        score = model.best_score
        params['n_estimators'] = n_epoach
        params = dict([(key, rounded(params[key]))
                       if type(params[key]) == float
                       else (key, params[key])
                       for key in params])

        print "Trained with: "
        print params
        print "\tScore {0}\n".format(score)
        return {'loss': 1 - score, 'status': STATUS_OK, 'params': params}

    def optimize(self, trials):
        space = {
            'n_estimators': 2000,  # hp.quniform('n_estimators', 10, 1000, 10),
            'eta': hp.quniform('eta', 0.025, 0.3, 0.025),
            'max_depth': hp.choice('max_depth', np.arange(1, 9, dtype=int)),
            'min_child_weight': hp.choice('min_child_weight', np.arange(1, 10, dtype=int)),
            'subsample': hp.quniform('subsample', 0.3, 1, 0.05),
            'gamma': hp.quniform('gamma', 0.1, 20, 0.1),
            'colsample_bytree': hp.quniform('colsample_bytree', 0.5, 1, 0.25),
            'eval_metric': 'map',
            'objective': 'rank:pairwise',
            'silent': 1
        }

        fmin(self.score, space, algo=tpe.suggest, trials=trials, max_evals=self.max_evals),

        min_loss = 1
        min_params = {}
        for trial in trials.trials:
            tmp_loss, tmp_params = trial['result']['loss'], trial['result']['params']
            if tmp_loss < min_loss:
                min_loss, min_params = tmp_loss, tmp_params

        print("Winning params:")
        print(min_params)
        print "\tScore: {}".format(1-min_loss)
        self.tuned_params = min_params

    def tune(self):
        print "Tuning...\n"
        # Trials object where the history of search will be stored
        trials = Trials()
        self.optimize(trials)

所以我使用了一个类,主要用来定义参数和保存结果以备将来使用。有2个电源功能。在

  1. optimize()创建来定义我们的“搜索空间”,计算 使错误最小化的最佳参数(所以请注意 最小化错误)并保存找到的最佳参数。还添加了一些指纹以帮助您遵循流程。

  2. score()用于使用特定 “搜索空间”中的超参数。它用的是提前停车 在类中定义。因为我不需要用十字架 我用过的验证xgb.列车(),但您可以将其更改为xgb.cv() 这确实支持早期停止子弹。还添加了指纹 帮助您遵循流程。score返回1-score(因为我已经 计算出的地图需要增加,所以如果 你计算一个像RMSE这样的错误,只需按原样返回分数。)

这是在有了dtrain和dtest矩阵之后,如何从代码中激活它:

^{pr2}$

其中max_evals是“搜索网格”的大小

遵循这些指导原则,如果你有困难,请告诉我。在

对于当前的xgboost实现(指版本0.6和0.7),这是不可能的。 请注意本机xgboost之间的区别

    xgboost.train(params, dtrain, num_boost_round=10, evals=(), obj=None, 
feval=None, maximize=False, early_stopping_rounds=None, evals_result=None, 
verbose_eval=True, xgb_model=None, callbacks=None, learning_rates=None)

或者

^{pr2}$

以及sklearn接口

    class xgboost.XGBRegressor(max_depth=3, learning_rate=0.1, 
n_estimators=100, silent=True, objective='reg:linear', booster='gbtree', 
n_jobs=1, nthread=None, gamma=0, min_child_weight=1, max_delta_step=0, 
subsample=1, colsample_bytree=1, colsample_bylevel=1, reg_alpha=0, 
reg_lambda=1, scale_pos_weight=1, base_score=0.5, random_state=0, seed=None, 
missing=None, **kwargs)

正如您所见,没有什么事情可以像提前停止xgboost.XGBRegressor。请注意,sklearn接口是唯一可以与GridSearchCV结合使用的接口,它需要一个带有.fit(),.predict()等的正确的sklearn估计器。。。在

您可以将early_stopping_rounds,和eval_set作为一个额外的fit_参数传递给GridSearchCV,这实际上是可行的。 但是,GridSearchCV不会改变不同折叠之间的拟合参数,因此您将最终在所有折叠中使用相同的eval_set,这可能不是您所说的CV。在

model=xgb.XGBClassifier()
clf = GridSearchCV(model, parameters,
                         fit_params={'early_stopping_rounds':20,\
                         'eval_set':[(X,y)]},cv=kfold)  

经过一番调整,我发现集成early_stopping_rounds和sklearnapi的最安全的方法是实现一个自己的早期停止机制。如果您使用GridSearchCV作为要调整的参数,您可以这样做。然后,您可以观察不同模型的mean_validation_score,并增加n_rounds。然后,您可以为早期停止定义一个定制的启发式;您会注意到默认的启发式不是最优的。在

我认为这也是一个更好的方法,而不是使用一个单一的分裂持有。在

相关问题 更多 >