Search code examples
pythonmachine-learningkerasscikit-learn

How to wrap keras models for scikit-learn stacking ensemble usages


I have a list of keras models already trained. I want to use them with StackingClassifier in scikit learn. Due to the fact that keras doesn't have predict_proba method I created a wrapper.

If use my models wrapped for VotingClassifier with soft and hard methods, it works.

But when I use stacking models, after first run, it shows me this error. I didn't found anything about it.

class KerasWrapperWithEncoder(BaseEstimator, ClassifierMixin):
    def __init__(self, keras_model, classes_):
        self.keras_model = keras_model
        self.encoder = OneHotEncoder(sparse_output=False)
        # L'encoder OneHotEncoder est passé ici
        self.classes_ = classes_  # Définit les classes disponibles

    def fit(self, X, y):
        # Models are fitted dont fit again
        y_reshaped = y.reshape(-1, 1)
        self.encoder.fit(y_reshaped)
        return self

    def predict(self, X):
        # Utilise les modèles entraînés pour faire des prédictions
        predictions = self.keras_model.predict(X)
        np_argmax = np.argmax(predictions, axis=1)
        print(predictions)
        print(np_argmax)
        return np_argmax

    def predict_proba(self, X):
        # Retourne les probabilités des classes pour les modèles de classification
        probabilities = self.keras_model.predict(X)
        print("Shape of probabilities:", probabilities.shape)  # Debug
        return probabilities


keras_wrapped_models_with_encoder = [
    (name.replace(' ', '_').replace('__', '_'), KerasWrapperWithEncoder(model, _target_classes_))
    for name, model in keras_models.items()
]

voting_clf = VotingClassifier(
         estimators=all_estimators,
         voting='soft', 
         n_jobs=3,  
         verbose=True)
voting_clf .fit(X_train, y_train) # works perfectly 

cv = StratifiedKFold(n_splits=3, shuffle=True, random_state=42)
keras_stacking_models_current_year = StackingClassifier(
    estimators=all_estimators,
    final_estimator=LogisticRegression(),
    cv=cv,
    verbose=3,
    # n_jobs=2
)


keras_stacking_models_current_year.fit(X_train, y_train) # throws error

======================================stacking_models_all_models=============================
12105/12105 [==============================] - 25s 2ms/step
Shape of probabilities: (387348, 3)
Number of classes in training fold (1) does not match total number of classes (3). Results may not be appropriate for your use case. To fix this, use a cross-validation technique resulting in properly stratified folds
_enforce_prediction_order(classes, predictions, n_classes, method)
   1457             dtype=predictions.dtype,
   1458         )
-> 1459         predictions_for_all_classes[:, classes] = predictions
   1460         predictions = predictions_for_all_classes
   1461     return predictions

ValueError: shape mismatch: value array of shape (387348,3) could not be broadcast to indexing result of shape (387348,1,3)

Solution

  • For my case, changing stacking_method to 'predict' works