Search code examples
tensorflowkerasscikit-learnadaboostboosting

How to use a Keras model inside of sklearn's AdaBoost?


I have a Keras model and want to boost it using sklearn's AdaBootClassifier. Unfortunately I get the following error message and have no idea how to solve it. I would be very happy about any help!

ValueError Traceback (most recent call last) in () ----> 1 boosted_classifier.fit(X,y)

3 frames /usr/local/lib/python3.6/dist-packages/sklearn/ensemble/_weight_boosting.py in _boost_discrete(self, iboost, X, y, sample_weight, random_state) 602 # Only boost positive weights 603 sample_weight *= np.exp(estimator_weight * incorrect * --> 604 (sample_weight > 0)) 605 606 return sample_weight, estimator_weight, estimator_error

ValueError: non-broadcastable output operand with shape (670,) doesn't match the broadcast shape (670,670)

This is my code:

import sklearn
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import AdaBoostRegressor
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification

import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.wrappers.scikit_learn import KerasClassifier
from keras.wrappers.scikit_learn import KerasRegressor


import matplotlib.pyplot as plt
import numpy as np
import math

X_all, y_all = make_classification(n_samples=1000, n_features=50,
                           n_informative=20, n_redundant=0,
                           random_state=0, shuffle=False, class_sep=1)

X, X_test, y, y_test = train_test_split(X_all, y_all, test_size=0.33, random_state=42)

def simple_model():                                           
    # create model
    model = Sequential()
    model.add(Dense(25, input_dim=50, activation='relu'))
    model.add(Dropout(0.2, input_shape=(50,)))
    model.add(Dense(100, activation='relu'))
    model.add(Dropout(0.2, input_shape=(100,)))
    model.add(Dense(50, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    # Compile model
    model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
    return model

class MyKerasClassifier(KerasClassifier):
  def fit(self, x, y, sample_weight=None, **kwargs):
    y = np.array(y)
    if len(y.shape) == 2 and y.shape[1] > 1:
        self.classes_ = np.arange(y.shape[1])
    elif (len(y.shape) == 2 and y.shape[1] == 1) or len(y.shape) == 1:
        self.classes_ = np.unique(y)
        y = np.searchsorted(self.classes_, y)
    else:
        raise ValueError('Invalid shape for y: ' + str(y.shape))
    self.n_classes_ = len(self.classes_)
    if sample_weight is not None:
        kwargs['sample_weight'] = sample_weight
        print(type(sample_weight))
    return super(MyKerasClassifier, self).fit(x, y, **kwargs)
    #return super(KerasClassifier, self).fit(x, y, sample_weight=sample_weight)

boosted_classifier = AdaBoostClassifier(
    base_estimator=MyKerasClassifier(build_fn=simple_model, epochs=5, batch_size=32, verbose=0),
    n_estimators=2,
    random_state=0,
    algorithm="SAMME")

boosted_classifier.fit(X,y)

Solution

  • I found an easy solution for myself. I just added the following prediction function to my MyKerasClassifier Class and it works :)

      def predict(self, x, **kwargs):
        kwargs = self.filter_sk_params(Sequential.predict_classes, kwargs)
        classes = self.model.predict_classes(x, **kwargs)
        return self.classes_[classes].flatten()