如何保存GridSearchCV对象?

17

最近,我一直在使用Grid Search交叉验证(sklearn GridSearchCV)对Keras和Tensorflow后端的超参数进行调整。当我的模型完成调整后,我尝试保存GridSearchCV对象以供日后使用,但没有成功。

超参数调整步骤如下:

x_train, x_val, y_train, y_val = train_test_split(NN_input, NN_target, train_size = 0.85, random_state = 4)

history = History() 
kfold = 10


regressor = KerasRegressor(build_fn = create_keras_model, epochs = 100, batch_size=1000, verbose=1)

neurons = np.arange(10,101,10) 
hidden_layers = [1,2]
optimizer = ['adam','sgd']
activation = ['relu'] 
dropout = [0.1] 

parameters = dict(neurons = neurons,
                  hidden_layers = hidden_layers,
                  optimizer = optimizer,
                  activation = activation,
                  dropout = dropout)

gs = GridSearchCV(estimator = regressor,
                  param_grid = parameters,
                  scoring='mean_squared_error',
                  n_jobs = 1,
                  cv = kfold,
                  verbose = 3,
                  return_train_score=True))

grid_result = gs.fit(NN_input,
                    NN_target,
                    callbacks=[history],
                    verbose=1,
                    validation_data=(x_val, y_val))

注意:create_keras_model函数初始化并编译Keras序列模型。

在完成交叉验证后,我尝试使用以下代码保存网格搜索对象(gs):

from sklearn.externals import joblib

joblib.dump(gs, 'GS_obj.pkl')

我正在遇到的错误是以下内容:
TypeError: can't pickle _thread.RLock objects

请问这个错误的原因可能是什么?

谢谢!

附注:joblib.dump方法适用于保存用于训练sklearn MLPRegressors的GridSearchCV对象。


请告诉我我的回答是否解决了您的问题。 - seralouk
3个回答

20

直接使用import joblib

而不是使用from sklearn.externals import joblib

使用以下代码保存对象或结果:

joblib.dump(gs, 'model_file_name.pkl')

并使用以下代码加载结果:

joblib.load("model_file_name.pkl")

这里有一个简单的可行示例:


import joblib

#save your model or results
joblib.dump(gs, 'model_file_name.pkl')

#load your model for further usage
joblib.load("model_file_name.pkl")


9

尝试以下方法:

from sklearn.externals import joblib
joblib.dump(gs.best_estimator_, 'filename.pkl')

如果您想将对象转储到一个文件中,请使用以下命令:
joblib.dump(gs.best_estimator_, 'filename.pkl', compress = 1)

简单示例:

from sklearn import svm, datasets
from sklearn.model_selection import GridSearchCV
from sklearn.externals import joblib

iris = datasets.load_iris()
parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
svc = svm.SVC()
gs = GridSearchCV(svc, parameters)
gs.fit(iris.data, iris.target)

joblib.dump(gs.best_estimator_, 'filename.pkl')

#['filename.pkl']

编辑1:

您也可以保存整个对象:

joblib.dump(gs, 'gs_object.pkl')

谢谢您的回复!如果我没理解错,您提出的是仅保存具有最佳调整参数(最佳估计器)的模型的方法。然而,我想要做的是保存GridSearchCV对象中包含的所有信息,即所有训练模型的性能信息。一种方法是保存gs.cv_results_而不是整个对象,但我只是想知道为什么不能将整个对象保存在文件中。 - E.Thrampoulidis
1
你可以使用joblib.dump(gs,'gs_object.pkl')保存整个对象。请查看我编辑后的答案。 - seralouk
如我在问题中所述,我已经尝试过保存整个对象的方法,但它并没有起作用。我仍然没有弄清楚原因。 - E.Thrampoulidis
1
@E.Thrampoulidis 我正在自己解决这个问题。问题在于GridSearchCV旨在通过n_jobs参数支持并行处理。据我所知,没有简单的方法可以pickle一个支持并行调用的对象(因此会出现有关pickling线程的错误)。Pickle非常适合简单的数据结构,例如字典(cv_results),但对于复杂对象(例如GridSearchCV类)来说并不是一个好选择,因为它从一开始就不打算进行序列化。 - campellcl
joblib自scikit 0.21版本起已被弃用,并将在0.23版本中移除。现在,它需要作为一个单独的包进行安装,可以通过pip(pip install joblib)或condaconda install -c anaconda joblib)进行安装。 - Arturo Moncada-Torres

1

继承sklearn.model_selection._search.BaseSearchCV类。重写fit(self, X, y=None, groups=None, **fit_params)方法,并修改其内部的evaluate_candidates(candidate_params)函数。不要立即从evaluate_candidates(candidate_params)返回results字典,而是在此处执行序列化(或者根据您的用例在_run_search方法中执行)。通过一些额外的修改,这种方法还有一个额外的好处,可以让您按顺序执行网格搜索(请参见源代码中的注释:_search.py)。请注意,evaluate_candidates(candidate_params)返回的results字典与cv_results字典相同。这种方法对我有效,但我还尝试添加了中断网格搜索执行的保存和恢复功能。


你好Chris! 你能够保存并恢复中断的网格搜索吗? 我想使用BayesSearchCV(来自Scikit-Optimize库),它使用类似于GridSearchCV的接口来实现类似的功能。 - SergeGardien
@SergeGardien 是的,但这不是一个快速解决方案。您必须修改核心库中的一些方法。最好维护自己的cv_results字典并从中进行序列化和恢复。 - campellcl
明白了,谢谢。问题在于BayesSearchCV是路径相关的,与GridSearchCV不同,我认为仅仅存储cv_results并不足以拥有恢复过程所需的所有信息。无论如何,如果有时间我会看看能否解决这个问题,否则我会尽量避免需要恢复优化过程的情况。 - SergeGardien
@SergeGardien 我很乐意在有机会的时候提供更多细节。祝你好运! - campellcl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接