Search code examples
pythontensorflowkerasscikit-learncross-validation

Why am I having different accuracy results for the same network configuration when I am using Scikit-Learn Keras model function?


I used the scikit-learn classifier API for Keras i.e, "tf.keras.wrappers.scikit_learn.KerasClassifier" while building my DNN. I had a mean cv score of 53%. When I performed the same classification without using the Keraswrapper function my average cv score came out to be 24.23% though I have used the same architecture and hyperparameters. I have followed the code from Jason Brownlee's "Deep Learning with Python" book. Without using wrapper function my code is:

from keras.models import Sequential
from keras.layers import Dense
from sklearn.model_selection import StratifiedKFold
import numpy
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)

kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
cvscores = []

for train, test in kfold.split(X, y):
 model = Sequential()
 model.add(Dense(128, input_dim=76636, kernel_initializer='uniform', activation='relu'))
 model.add(Dense(64, activation='relu', kernel_initializer='uniform'))  
 model.add(Dense(2, kernel_initializer='uniform', activation='softmax'))
 # Compile model
 model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
 #Fit the model
 model.fit(X[train], y[train], epochs=50, batch_size=512, verbose=0)
 #Evaluate the model
 scores = model.evaluate(X[test], y[test], verbose=0)
 #print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
 cvscores.append(scores[1] * 100)

print("%.2f%% (+/- %.2f%%)" % (numpy.mean(cvscores), numpy.std(cvscores)))

I get the following output: 24.23% (+/- 2.35%)

When I use Keraswrapper function my code is:

from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score
import numpy

# Function to create model, required for KerasClassifier
def create_model():
 # create model
 model = Sequential()
 model.add(Dense(128, input_dim=76636, kernel_initializer='uniform', activation='relu'))
 model.add(Dense(64, activation='relu', kernel_initializer='uniform'))  
 model.add(Dense(2, kernel_initializer='uniform', activation='softmax'))
 # Compile model
 model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
 return model

# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)

model = KerasClassifier(build_fn=create_model, nb_epoch=50, batch_size=512, verbose=0)

# evaluate using 10-fold cross validation
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
results = cross_val_score(model, X, y, cv=kfold)
print(results.mean())

The output is: 0.5315796375274658


Solution

  • I ran your code on pima-indians-diabetes.csv dataset and I couldn't recreate the issue you are facing. There was minor difference in the result but that could be explained by the numpy.std(cvscores).

    Below are the run details -

    Without using wrapper function :

    %tensorflow_version 2.x
    from keras.models import Sequential
    from keras.layers import Dense
    from sklearn.model_selection import StratifiedKFold
    import numpy
    
    # load pima indians dataset
    dataset = np.loadtxt("/content/pima-indians-diabetes.csv", delimiter=",")
    
    # split into input (X) and output (Y) variables
    X = dataset[:,0:8]
    y = dataset[:,8]
    
    # fix random seed for reproducibility
    seed = 7
    numpy.random.seed(seed)
    
    kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
    cvscores = []
    
    for train, test in kfold.split(X, y):
     model = Sequential()
     model.add(Dense(128, input_dim=8, kernel_initializer='uniform', activation='relu'))
     model.add(Dense(64, activation='relu', kernel_initializer='uniform'))  
     model.add(Dense(2, kernel_initializer='uniform', activation='softmax'))
     # Compile model
     model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
     #Fit the model
     model.fit(X[train], y[train], epochs=50, batch_size=512, verbose=0)
     #Evaluate the model
     scores = model.evaluate(X[test], y[test], verbose=0)
     #print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
     cvscores.append(scores[1] * 100)
    
    print("%.2f%% (+/- %.2f%%)" % (numpy.mean(cvscores), numpy.std(cvscores)))
    

    Output -

    WARNING:tensorflow:6 out of the last 11 calls to <function Model.make_train_function.<locals>.train_function at 0x7fc2c1468ae8> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    WARNING:tensorflow:7 out of the last 30 calls to <function Model.make_test_function.<locals>.test_function at 0x7fc2c4579d90> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    WARNING:tensorflow:7 out of the last 11 calls to <function Model.make_test_function.<locals>.test_function at 0x7fc2c1604d08> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    48.70% (+/- 5.46%)
    

    Using wrapper function :

    from keras.models import Sequential
    from keras.layers import Dense
    from keras.wrappers.scikit_learn import KerasClassifier
    from sklearn.model_selection import StratifiedKFold
    from sklearn.model_selection import cross_val_score
    import numpy
    
    # load pima indians dataset
    dataset = np.loadtxt("/content/pima-indians-diabetes.csv", delimiter=",")
    
    # split into input (X) and output (Y) variables
    X = dataset[:,0:8]
    y = dataset[:,8]
    
    # Function to create model, required for KerasClassifier
    def create_model():
     # create model
     model = Sequential()
     model.add(Dense(128, input_dim=8, kernel_initializer='uniform', activation='relu'))
     model.add(Dense(64, activation='relu', kernel_initializer='uniform'))  
     model.add(Dense(2, kernel_initializer='uniform', activation='softmax'))
     # Compile model
     model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
     return model
    
    # fix random seed for reproducibility
    seed = 7
    numpy.random.seed(seed)
    
    model = KerasClassifier(build_fn=create_model, nb_epoch=50, batch_size=512, verbose=0)
    
    # evaluate using 10-fold cross validation
    kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
    results = cross_val_score(model, X, y, cv=kfold)
    print(results.mean())
    

    Output -

    WARNING:tensorflow:5 out of the last 13 calls to <function Model.make_test_function.<locals>.test_function at 0x7fc2c4b79ea0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    WARNING:tensorflow:5 out of the last 107 calls to <function Model.make_train_function.<locals>.train_function at 0x7fc2d31262f0> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    WARNING:tensorflow:6 out of the last 14 calls to <function Model.make_test_function.<locals>.test_function at 0x7fc2c4b79a60> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    WARNING:tensorflow:6 out of the last 109 calls to <function Model.make_train_function.<locals>.train_function at 0x7fc2c4cc4268> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    WARNING:tensorflow:7 out of the last 15 calls to <function Model.make_test_function.<locals>.test_function at 0x7fc2c15a4268> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has experimental_relax_shapes=True option that relaxes argument shapes that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/tutorials/customization/performance#python_or_tensor_args and https://www.tensorflow.org/api_docs/python/tf/function for  more details.
    0.4320685863494873