I'm running some experiments with a simple Neural Network using Keras and Sklearn and I'm running into some unexpected results.
In my first experiment, the NN has one hidden layer with 64 neurons, and I'm using the StratifiedKFold class to run a KFold with 5 splits.
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import StratifiedKFold
import numpy as np
import tensorflow as tf
import random
seed = 7
random.seed(seed)
np.random.seed(seed)
tf.random.set_seed(seed)
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
for train, test in kfold.split(X, Y):
model = Sequential()
model.add(Dense(64, input_dim=12, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
model.summary()
model.fit(X_train[train], Y[train], epochs=10,verbose=1)
y_pred=model.predict(X_train[test])
mse_value, mae_value=model.evaluate(X_train[test], Y[test], verbose=1)
print(mse_value)
On the first fold, I get the following information printed:
Model: "sequential_169"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_342 (Dense) (None, 64) 832
_________________________________________________________________
dense_343 (Dense) (None, 1) 65
=================================================================
Total params: 897
Trainable params: 897
Non-trainable params: 0
_________________________________________________________________
Epoch 1/10
163/163 [==============================] - 0s 520us/step - loss: 23.5748 - mae: 4.6046
Epoch 2/10
163/163 [==============================] - 0s 503us/step - loss: 1.9301 - mae: 1.0770
Epoch 3/10
163/163 [==============================] - 0s 502us/step - loss: 1.0503 - mae: 0.8026
Epoch 4/10
163/163 [==============================] - 0s 492us/step - loss: 0.7895 - mae: 0.6828
Epoch 5/10
163/163 [==============================] - 0s 503us/step - loss: 0.6499 - mae: 0.6171
Epoch 6/10
163/163 [==============================] - 0s 524us/step - loss: 0.5652 - mae: 0.5795
Epoch 7/10
163/163 [==============================] - 0s 506us/step - loss: 0.5806 - mae: 0.5819
Epoch 8/10
163/163 [==============================] - 0s 506us/step - loss: 0.4949 - mae: 0.5497
Epoch 9/10
163/163 [==============================] - 0s 493us/step - loss: 0.4864 - mae: 0.5418
Epoch 10/10
163/163 [==============================] - 0s 492us/step - loss: 0.4942 - mae: 0.5455
41/41 [==============================] - 0s 474us/step - loss: 0.4861 - mae: 0.5457
0.48606643080711365
...
Note that the loss goes from 23.5748 to 0.4942 while training.
In my second experiment, I use the GridSearchCV class to perform a grid search on the number of layers to use. (To demonstrate my problem, I'm just trying one layer). I'm also passing the same kfold strategy as in the previous experiment to the constructor of GridSearchCV.
from tensorflow.keras.wrappers.scikit_learn import KerasRegressor
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import GridSearchCV
import tensorflow as tf
import random
seed = 7
random.seed(seed)
np.random.seed(seed)
tf.random.set_seed(seed)
def create_model(hidden_layers=1):
# Initialize the constructor
model = Sequential()
# Add hidden layers
for i in range(hidden_layers):
if i == 0:
model.add(Dense(64, input_dim=12, activation='relu'))
else:
model.add(Dense(64, activation='relu'))
# Add an output layer
model.add(Dense(1))
model.compile(optimizer='rmsprop', loss='mse', metrics=["mae"])
model.summary()
return model
model = KerasRegressor(build_fn=create_model, epochs=10, verbose=1)
param_grid = dict(hidden_layers=[1])
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
grid = GridSearchCV(estimator=model, param_grid=param_grid,
scoring=["neg_mean_absolute_error", "neg_mean_squared_error", "r2"],
refit="r2",
n_jobs=1, cv=kfold)
grid_result = grid.fit(X, Y)
With this method, on the first fold, I get the following output:
Model: "sequential_180"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_364 (Dense) (None, 64) 832
_________________________________________________________________
dense_365 (Dense) (None, 1) 65
=================================================================
Total params: 897
Trainable params: 897
Non-trainable params: 0
_________________________________________________________________
Epoch 1/10
163/163 [==============================] - 0s 527us/step - loss: 9.8205 - mae: 2.3366
Epoch 2/10
163/163 [==============================] - 0s 479us/step - loss: 1.0685 - mae: 0.8089
Epoch 3/10
163/163 [==============================] - 0s 503us/step - loss: 0.9351 - mae: 0.7488
Epoch 4/10
163/163 [==============================] - 0s 503us/step - loss: 0.9602 - mae: 0.7560
Epoch 5/10
163/163 [==============================] - 0s 502us/step - loss: 1.0195 - mae: 0.7830
Epoch 6/10
163/163 [==============================] - 0s 494us/step - loss: 0.9774 - mae: 0.7761
Epoch 7/10
163/163 [==============================] - 0s 489us/step - loss: 0.9569 - mae: 0.7413
Epoch 8/10
163/163 [==============================] - 0s 488us/step - loss: 0.9772 - mae: 0.7794
Epoch 9/10
163/163 [==============================] - 0s 464us/step - loss: 0.8716 - mae: 0.7259
Epoch 10/10
163/163 [==============================] - 0s 494us/step - loss: 0.8687 - mae: 0.7248
41/41 [==============================] - 0s 380us/step
...
Here the loss function behaves really differently from the first experiment; going from 9.8205 to 0.8687.
Since I'm:
- Setting all random seeds to the same value
seed = 7
random.seed(seed)
np.random.seed(seed)
tf.random.set_seed(seed)
- Using the same KFold method:
kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed)
- The neural networks have indeed the same architecture:
Model: "sequential_XXX"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_XXX (Dense) (None, 64) 832
_________________________________________________________________
dense_XXY (Dense) (None, 1) 65
=================================================================
Total params: 897
Trainable params: 897
Non-trainable params: 0
- The epochs and batch sizes are the same.
I would expect both neurons to obtain the same results (at least in the first fold), but I'm getting different results in the loss function.
How is it possible that the NN from the first experiment behaves differently than the one from the second?
EDIT
The problem was that I was training with X_train on the first experiment and with X on the second. X_train was the scaled version of X.
Having said that, Marco's points regarding seeds also apply. Please refer to his answer.