我可以向 KerasClassifier 发送回调吗? [英] Can I send callbacks to a KerasClassifier?

查看:19
本文介绍了我可以向 KerasClassifier 发送回调吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果耐心达到我设置的数字,我希望分类器运行得更快并早点停止.在下面的代码中,它进行了 10 次拟合模型的迭代.

I want the classifier to run faster and stop early if the patience reaches the number I set. In the following code it does 10 iterations of fitting the model.

import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.callbacks import EarlyStopping, ModelCheckpoint
from keras.constraints import maxnorm
from keras.optimizers import SGD
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load dataset
dataframe = pandas.read_csv("sonar.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
X = dataset[:,0:60].astype(float)
Y = dataset[:,60]
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)

calls=[EarlyStopping(monitor='acc', patience=10), ModelCheckpoint('C:/Users/Nick/Data Science/model', monitor='acc', save_best_only=True, mode='auto', period=1)]

def create_baseline(): 
    # create model
    model = Sequential()
    model.add(Dropout(0.2, input_shape=(33,)))
    model.add(Dense(33, init='normal', activation='relu', W_constraint=maxnorm(3)))
    model.add(Dense(16, init='normal', activation='relu', W_constraint=maxnorm(3)))
    model.add(Dense(122, init='normal', activation='softmax'))
    # Compile model
    sgd = SGD(lr=0.1, momentum=0.8, decay=0.0, nesterov=False)
    model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
    return model

numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=calls)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)
print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

这是由此产生的错误-

RuntimeError: Cannot clone object <keras.wrappers.scikit_learn.KerasClassifier object at 0x000000001D691438>, as the constructor does not seem to set parameter callbacks

我在下面更改了cross_val_score-

I changed the cross_val_score in the following-

numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=calls)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params={'callbacks':calls})
print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))

现在我收到此错误-

ValueError: need more than 1 value to unpack

此代码来自此处.该代码是迄今为止我使用过的最准确的代码.问题是代码中的任何地方都没有定义 model.fit() .也需要永远适应.fit() 操作发生在 results = cross_val_score(...) 并且没有参数可以在那里抛出回调.

This code came from here. The code is by far the most accurate I've used so far. The problem is that there is no defined model.fit() anywhere in the code. It also takes forever to fit. The fit() operation occurs at the results = cross_val_score(...) and there's no parameters to throw a callback in there.

我该怎么做?另外,我如何运行在测试集上训练的模型?

How do I go about doing this? Also, how do I run the model trained on a test set?

我需要能够保存训练好的模型以备后用...

I need to be able to save the trained model for later use...

推荐答案

阅读 从这里,这是 KerasClassifier 的源代码,您可以将 fit 的参数传递给它,它们应该被使用.我没有你的数据集,所以我无法测试它,但你可以告诉我这是否有效,如果无效,我会尝试调整解决方案.改变这一行:

Reading from here, which is the source code of KerasClassifier, you can pass it the arguments of fit and they should be used. I don't have your dataset so I cannot test it, but you can tell me if this works and if not I will try and adapt the solution. Change this line :

estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=300, batch_size=16, verbose=0, callbacks=[...your_callbacks...])))

对正在发生的事情的一个小解释:KerasClassifier 正在获取 fitpredictscore 的所有可能参数,并在每个参数时相应地使用它们方法被调用.他们制作了一个函数,用于过滤应进入上述每个可在管道中调用的函数的参数.我猜在 StratifiedKFold 步骤中有几个 fitpredict 调用,每次都在不同的分割上进行训练.

A small explaination of what's happening : KerasClassifier is taking all the possibles arguments for fit, predict, score and uses them accordingly when each method is called. They made a function that filters the arguments that should go to each of the above functions that can be called in the pipeline. I guess there are several fit and predict calls inside the StratifiedKFold step to train on different splits everytime.

为什么需要永远拟合并且拟合 10 次是因为如您所问的那样,一次拟合要进行 300 次迭代.所以 KFold 在不同的折叠上重复这个步骤:

The reason why it takes forever to fit and it fits 10 times is because one fit is doing 300 epochs, as you asked. So the KFold is repeating this step over the different folds :

  • 调用 fit 并使用给 KerasClassifier 的所有参数(300 次迭代和批量大小 = 16).它对 9/10 的数据进行训练,并使用 1/10 作为验证.
  • calls fit with all the parameters given to KerasClassifier (300 epochs and batch size = 16). It's training on 9/10 of your data and using 1/10 as validation.

好的,所以我花时间下载数据集并尝试您的代码...首先,您需要纠正网络中的一些"问题:

Ok, so I took the time to download the dataset and try your code... First of all you need to correct a "few" things in your network :

  • 您的输入有 60 个特征.您在数据准备中清楚地显示了它:

  • your input have a 60 features. You clearly show it in your data prep :

X = dataset[:,:60].astype(float)

那你为什么会有这个:

model.add(Dropout(0.2, input_shape=(33,)))

请改为:

model.add(Dropout(0.2, input_shape=(60,)))

  • 关于您的目标/标签.您将目标从原始代码 (binary_crossentropy) 更改为 categorical_crossentropy.但是你没有改变你的 Y 数组.因此,要么在您的数据准备中执行此操作:

  • About your targets/labels. You changed the objective from the original code (binary_crossentropy) to categorical_crossentropy. But you didn't change your Y array. So either do this in your data preparation :

    from keras.utils.np_utils import to_categorical
    encoded_Y = to_categorical(encoder.transform(Y))
    

    或将您的目标改回 binary_crossentropy.

    现在网络的输出大小:最后一个密集层上的输出大小为 122?您的数据集显然有 2 个类别,那么您为什么要尝试输出 122 个类别?它不会匹配目标.请将最后一层改回:

    Now the network's output size : 122 on the last dense layer? your dataset obviously has 2 categories so why are you trying to output 122 classes? it won't match the target. Please change back your last layer to :

    model.add(Dense(2, init='normal', activation='softmax'))
    

    如果您选择使用categorical_crossentropy,或

    model.add(Dense(1, init='normal', activation='sigmoid'))
    

    如果你回到binary_crossentropy.

    既然你的网络已经编译好了,我就可以开始解决问题了.

    So now that your network compiles, I could start to troubleshout.

    这是您的解决方案

    所以现在我可以得到真正的错误信息.事实证明,当您在 cross_val_score() 函数中提供 fit_params=whatever 时,您将这些参数提供给管道.为了知道您想将这些参数发送到管道的哪一部分,您必须像这样指定它:

    So now I could get the real error message. It turns out that when you feed fit_params=whatever in the cross_val_score() function, you are feeding those parameters to a pipeline. In order to know to which part of the pipeline you want to send those parameters you have to specify it like this :

    fit_params={'mlp__callbacks':calls}
    

    您的错误是说该过程无法将 'callbacks'.split('__', 1) 解包为 2 个值.它实际上是在寻找将其应用到的管道步骤的名称.

    Your error was saying that the process couldn't unpack 'callbacks'.split('__', 1) into 2 values. It was actually looking for the name of the pipeline's step to apply this to.

    它现在应该可以工作了:)

    It should be working now :)

    results = cross_val_score(pipeline, X, encoded_Y, cv=kfold, fit_params={'mlp__callbacks':calls})
    

    但是,你应该知道这里发生了什么......交叉验证实际上调用了 create_baseline() 函数从头开始重新创建模型 10 次,并在不同部分训练它 10 次数据集.所以它没有像你说的那样做 epochs,它做了 300 个 epochs 10 次.使用这个工具的后果是什么:由于模型总是不同的,这意味着 fit() 方法在不同的模型上应用了 10 次,因此,回调也应用了 10 次不同的时间和 ModelCheckpoint() 保存的文件被覆盖,你会发现自己只有上次运行的最佳模型.

    BUT, you should be aware of what's happening here... the cross validation actually calls the create_baseline() function to recreate the model from scratch 10 times an trains it 10 times on different parts of the dataset. So it's not doing epochs as you were saying, it's doing 300 epochs 10 times. What is also happening as a consequence of using this tool : since the models are always differents, it means the fit() method is applied 10 times on different models, therefore, the callbacks are also applied 10 different times and the files saved by ModelCheckpoint() get overriden and you find yourself only with the best model of the last run.

    这与您使用的工具密不可分,我看不出有任何解决办法.这是因为使用了不同的通用工具,这些工具并未特别考虑与所有可能的配置一起使用.

    This is intrinsec to the tools you use, I don't see any way around this. This comes as consequence to using different general tools that weren't especially thought to be used together with all the possible configurations.

    这篇关于我可以向 KerasClassifier 发送回调吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆