I'm working with Keras, using Sci-Kit Learn gridsearchcv and Kold and SciKeras wrappers. I would to pass the validation folders of Kfold to the fit method of the model, by means of the parameter validation_data. I tried some alternatives but I can't do it. Here's the code.
NN = KerasClassifier(
model=get_NN,
X_len = len(X_train.columns),
loss="mse",
optimizer="SGD",
epochs=300,
batch_size=4,
shuffle=True,
verbose=False,
# fit__validation_data = # Here I should pass the validation data
callbacks=[
tf.keras.callbacks.EarlyStopping(
monitor="val_loss", min_delta=0.0001, patience=15, restore_best_weights=True
)
]
)
custom_scores_monk = {
"accuracy": "accuracy",
"mse": make_scorer(mean_squared_error,greater_is_better=False)
}
NN_MONK1_GRID_DICT = {
"model__lr" : [0.5],
"model__alpha" : [0.8],
"model__hidden_activation" : ["tanh"],
"model__neurons" : [4],
"model__initializer" : ["glorot"],
"model__nesterov" : [True],
"model__penalty": [None],
"model__lambda_reg": [None],
"model__seed" : [15]
}
grid = GridSearchCV(NN,
param_grid=NN_MONK1_GRID_DICT,
scoring=custom_scores_monk,
refit="mse",
cv=CV,
return_train_score=True,
n_jobs=-1
)
Between the others alternatives, I tried writing a custom callback for updating the data set on_train_begin, but It seems to be a dirty practice, I'm not surprised It doesn't work.
class ValidationCallback(Callback):
def __init__(self, X, y, validation_split):
super().__init__()
self.X = X
self.y = y
self.validation_split = validation_split
self.count = 0
def on_train_begin(self, logs=None):
print("Training " + str(self.count))
indexes = self.validation_split[self.count]
X_val, y_val = [self.X.iloc[i] for i in indexes], [self.y.iloc[i] for i in indexes]
self.count = self.count+1
self.model.fit__validation_data = (X_val, y_val)
Instead, I'm very surprised there is no a solution for a so common task as the KFold cross validation, especially using framework as skl. In particular, this problem leads to the impossibility to use 'val_loss' as monitor value for early stopping, apart from the impossibility to plot and compare training and validation learning curves.
Do You have solutions?
I spent about a week on that and I finally found a way.
Short answer: don't do it. Just handwrite an ad-hoc method for grid search and use it.
Long answer: you can define a subclass of the SciKeras' wrapper, in order to redefine the
fitmethod passing the current fold to it. To do that, you must:random_statein your CV objecthistoryobjectsfitmethodThe provided code also uses a routine for plotting data:
If you're working on a regression task, you can do the same thing with a wrapper of (a wrapper of) a regressor:
This satisfied my curiosity and stubbornness, but it's a dirty solution (even if it's still a solution :P). How I said at the beginning: just handwrite an ad-hoc method for grid search and use it. The solution presented above doesn't allow to use the intrinsic parallelization of the Skl's GridsearchCV, so it's a lot of completely useless work.
Note: the approach that uses the callback didn't work because the parameters of the
fitmethod are passed before the callback is invoked. Thus when the callback is invoked, the settedfit__validation_datais no evaluated.