【问题标题】:Can't save a Pipeline estimator无法保存管道估算器
【发布时间】:2017-07-26 03:14:32
【问题描述】:

我正在尝试训练一个简单的管道:

pipeline = Pipeline(
    [
        ('scaler', StandardScaler()),
        ('deepnc', deepnc),
    ])

其中 deepnc 是 Keras 分类器:

def create_spec_model(n_col=115, density_value=2, init='normal', dropout=0.2, learning_rate=0.005, decay=0.001,
                      momentum=0.9):
    # create model
    model = Sequential()
    model.add(Dropout(dropout, input_shape=(n_col,)))
    model.add(Dense(50 * density_value, init=init, activation='relu', W_constraint=maxnorm(2),
                    W_regularizer=l1l2(l1=0, l2=1e-4)))
    model.add(Dropout(dropout))
    model.add(Dense(30 * density_value, init=init, activation='relu', W_constraint=maxnorm(2),
                    W_regularizer=l1l2(l1=0, l2=1e-4)))
    model.add(Dropout(dropout))
    model.add(Dense(1, init=init, activation='sigmoid'))
    # load weights
    try:
        model.load_weights(spec_model_path)
    except:
        pass
    # Compile model
    sgd = SGD(lr=learning_rate, momentum=momentum, decay=decay, nesterov=True)
    model.compile(loss='binary_crossentropy', optimizer=sgd, metrics=['accuracy'])
    return model

我将管道放入随机搜索并检查一些参数:

deepnc = KerasClassifier(build_fn=create_spec_model, validation_split=0.1, dropout=0.2, learning_rate=0.005,
                         decay=0.001, verbose=2)
# grid search epochs, batch size and optimizer
optimizers = ['adam']
init = ['uniform', 'normal']
epochs = np.array([20, 40])
batches = np.array([20, 50, 100])
learning_rate = [0.005, 0.01]
dropout = [0.2, 0.3, 0.5]
decay = [0, 0.001, 0.005, 0.01]
density_value = [1, 2, 4]
param_grid = dict(deepnc__nb_epoch=epochs, deepnc__batch_size=batches, deepnc__init=init, deepnc__dropout=dropout,
                  deepnc__learning_rate=learning_rate,
                  deepnc__density_value=density_value)
grid = RandomizedSearchCV(estimator=pipeline, param_distributions=param_grid, n_iter=100, cv=5, verbose=1,
                          scoring='accuracy', fit_params={'deepnc__callbacks': [earlyStopping, modelCheck]})

grid.fit(np.array(X_train.iloc[:, :115]), y_train)

之后,我想保存最佳估算器和最佳参数:

joblib.dump(grid.best_estimator_, 'models/deepn_spec_model.pkl')
joblib.dump(grid.best_params_, 'models/deepn_spec_model_best_params.pkl')

由于某种原因,前者不起作用。幸运的是,我在控制台中运行了脚本,因此我能够单独运行后者并保存最佳参数。但是,我仍在试图弄清楚如何保存模型。我猜想将 Keras 的 scikit 包装器与 Pipeline 和 RandomizedSearchCV 结合会导致问题?

我也试过这个代码:

path = 'models/deepn_spec_model.pkl'
pickle.dump(grid.best_estimator_, open(path, 'wb'))

但它产生了相同的错误回溯。我在下面发布了一个缩短的版本,因为它非常长,并且由一遍又一遍地重复相同的片段组成。谷歌搜索错误没有帮助。有什么想法吗?

  File "/usr/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.7/pickle.py", line 606, in save_list
    self._batch_appends(iter(obj))
  File "/usr/lib/python2.7/pickle.py", line 621, in _batch_appends
    save(x)
  File "/usr/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.7/pickle.py", line 568, in save_tuple
    save(element)
  File "/usr/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.7/pickle.py", line 655, in save_dict
    self._batch_setitems(obj.iteritems())
  File "/usr/lib/python2.7/pickle.py", line 669, in _batch_setitems
    save(v)
  File "/usr/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.7/pickle.py", line 754, in save_global
    (obj, module, name))
PicklingError: Can't pickle <function start_console_server at 0x7f0c22d08a28>: it's not found as __main__.start_console_server

额外问题:我是否正确使用了随机搜索?与最初的努力相比,我没有得到太大的进步。

【问题讨论】:

    标签: python scikit-learn neural-network keras pipeline


    【解决方案1】:

    只需为 Keras-Pickle 问题添加另一种解决方法。

    它有点不完整,但允许 Keras 模型使用 pickle 存储,因此它适用于模型和包含对象。

    http://zachmoshe.com/2017/04/03/pickling-keras-models.html

    【讨论】:

      【解决方案2】:

      无法保存封装在 Scikit 分类器中的 Keras 模型GitHub Reference

      但是,有一个解决方法(或 2 个)!一种是Nassim Ben points out,使用 ModelCheckpoint 保存最佳权重并“重新创建”模型。

      在我的情况下,在做了一些研究之后,我决定换一种方式,可以说更容易:训练后,简单地做:

      grid.best_estimator_.model.save(path)
      

      这(即在保存之前添加 .model)确保访问底层 Keras 模型,保存方法可以正常工作。现在你可以简单地做

      deepnc_cont = keras.models.load_model(path)
      

      而且它有效 - 至少对我来说:)

      请注意,如果出于某种原因,我需要一个 KerasClassifier 对象(scikit 包装器),它将无法工作,因为它的构造函数要求生成模型的函数,所以我可能不得不遵循 Nassim 的路线?不过我不确定。

      【讨论】:

      • 我在某处看到了 .model 解决方案,但我认为它不适用于您的情况,因此是“坏”黑客。很高兴您找到了访问 keras 模型的解决方案。
      【解决方案3】:

      我知道这不是您要找的东西,但是……什么都没有:

      鉴于您的回调对象已保存最佳权重,您只需要模型对象。该模型在您的函数create_spec_model() 中。您唯一需要的是最佳参数。所以:

      # Save parameters of the best estimator.
      pickle.dump(grid.best_estimator_.named_steps['deepnc'].get_params(),open('params.pkl','wb'))
      

      在加载时,假设您的函数 create_spec_model() 仍在您的代码中:

      import inspect
      
      def load_model(params_path, weights_path):
          params = pickle.load(open(params_path,'rb'))
          params = {k: params[k] for k in inspect.getargspec(create_spec_model)[0] if k in params.keys()}
          model = create_spec_model(**params)
          model.load_weights(weights_path)
          return model
      

      这对你有帮助吗?

      【讨论】:

      • 我投了赞成票,因为它有效且努力,但是,在我看来,有一个更好的方法可以做到这一点,我稍后会发布:)
      • 酷,迫不及待想看!
      • 嗯,就在这里 :) 既然您已经投入研究这个问题,请告诉我您的看法?
      【解决方案4】:

      您无法使用 joblib 或 pickle 保存 keras 模型。 而是使用保存方法并显示here

      或者在你的情况下:

      path = 'models/deepn_spec_model.pkl'
      grid.best_estimator_.save(path)
      

      并加载模型:

      from keras.models import load_model
      path = 'models/deepn_spec_model.pkl'
      model = load_model(path)
      

      另外请注意,由于这不是严格意义上的 pickle 文件而是 HDF5 文件,您不妨将文件扩展名更改为“.h5”。

      【讨论】:

      • 不幸的是,这并不那么容易:(实际上,grid.best_estimator_是一个管道对象......所以我想问题真的是Keras想要保存而管道想要转储,并且那里没有办法调和吗?
      • 作为一种解决方法,您可以从named_steps(在您的情况下为'scaler'和'deepnc')获取所有估算器,并尝试通过dumpsave分别保存和腌制它们
      • 如何单独获取它们?管道不支持索引。
      • 致电pipeline.named_steps['deepnc'].save()joblib.dump(pipeline.named_steps['deepnc'], ..path..)。请参阅named_steps 属性的用法以访问内部估算器。
      • 现在这很奇怪... grid.best_estimator_.named_steps['deepnc'].save("models/deepn_spec_model.h5") 返回“AttributeError: 'KerasClassifier' object has no attribute 'save '”。这很奇怪,因为我之前已经在这个项目中保存了模型。
      猜你喜欢
      • 2021-06-01
      • 2019-02-16
      • 2020-09-11
      • 2017-06-13
      • 2020-05-31
      • 2017-12-28
      • 2020-05-13
      • 1970-01-01
      • 2019-10-22
      相关资源
      最近更新 更多