tensorflow/keras 神经网络中的过度拟合和数据泄漏

Overfitting and data leakage in tensorflow/keras neural network

早上好,我是机器学习和神经网络方面的新手。我正在尝试构建一个完全连接的神经网络来解决回归问题。数据集由18个特征和1个标签组成,都是物理量。

您可以在下面找到代码。我上传了损失函数随时间演变的图(你可以在下面找到)。我不确定是否存在过度拟合。有人能解释一下为什么会过拟合吗?

import pandas as pd
import numpy as np

from sklearn.ensemble import RandomForestRegressor
from sklearn.feature_selection import SelectFromModel
from sklearn import preprocessing

from sklearn.model_selection import train_test_split

from matplotlib import pyplot as plt

import keras
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization
from tensorflow.keras.callbacks import EarlyStopping
from keras import optimizers
from sklearn.metrics import r2_score
from keras import regularizers
from keras import backend
from tensorflow.keras import regularizers
from keras.regularizers import l2

# =============================================================================
# Scelgo il test size
# =============================================================================
test_size = 0.2

dataset = pd.read_csv('DataSet.csv', decimal=',', delimiter = ";")

label = dataset.iloc[:,-1]
features = dataset.drop(columns = ['Label'])

y_max_pre_normalize = max(label)
y_min_pre_normalize = min(label)

def denormalize(y):
    final_value = y*(y_max_pre_normalize-y_min_pre_normalize)+y_min_pre_normalize
    return final_value

# =============================================================================
# Split
# =============================================================================

X_train1, X_test1, y_train1, y_test1 = train_test_split(features, label, test_size = test_size, shuffle = True)

y_test2 = y_test1.to_frame()
y_train2 = y_train1.to_frame()

# =============================================================================
# Normalizzo
# =============================================================================
scaler1 = preprocessing.MinMaxScaler()
scaler2 = preprocessing.MinMaxScaler()
X_train = scaler1.fit_transform(X_train1)
X_test = scaler2.fit_transform(X_test1)


scaler3 = preprocessing.MinMaxScaler()
scaler4 = preprocessing.MinMaxScaler()
y_train = scaler3.fit_transform(y_train2)
y_test = scaler4.fit_transform(y_test2)



# =============================================================================
# Creo la rete
# =============================================================================
optimizer = tf.keras.optimizers.Adam(lr=0.001)
model = Sequential()

model.add(Dense(60, input_shape = (X_train.shape[1],), activation = 'relu',kernel_initializer='glorot_uniform'))
model.add(Dropout(0.2))
model.add(Dense(60, activation = 'relu',kernel_initializer='glorot_uniform'))
model.add(Dropout(0.2))
model.add(Dense(60, activation = 'relu',kernel_initializer='glorot_uniform'))

model.add(Dense(1,activation = 'linear',kernel_initializer='glorot_uniform'))

model.compile(loss = 'mse', optimizer = optimizer, metrics = ['mse'])

history = model.fit(X_train, y_train, epochs = 100,
                    validation_split = 0.1, shuffle=True, batch_size=250
                    )

history_dict = history.history

loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']

y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)

y_train_pred = denormalize(y_train_pred)
y_test_pred = denormalize(y_test_pred)


plt.figure()
plt.plot((y_test1),(y_test_pred),'.', color='darkviolet', alpha=1, marker='o', markersize = 2, markeredgecolor = 'black', markeredgewidth = 0.1)
plt.plot((np.array((-0.1,7))),(np.array((-0.1,7))),'-', color='magenta')
plt.xlabel('True')
plt.ylabel('Predicted')
plt.title('Test')

plt.figure()
plt.plot((y_train1),(y_train_pred),'.', color='darkviolet', alpha=1, marker='o', markersize = 2, markeredgecolor = 'black', markeredgewidth = 0.1)
plt.plot((np.array((-0.1,7))),(np.array((-0.1,7))),'-', color='magenta')
plt.xlabel('True')
plt.ylabel('Predicted')
plt.title('Train')

plt.figure()
plt.plot(loss_values,'b',label = 'training loss')
plt.plot(val_loss_values,'r',label = 'val training loss')
plt.xlabel('Epochs')
plt.ylabel('Loss Function')
plt.legend()

print("\n\nThe R2 score on the test set is:\t{:0.3f}".format(r2_score(y_test_pred, y_test1)))

print("The R2 score on the train set is:\t{:0.3f}".format(r2_score(y_train_pred, y_train1)))
from sklearn import metrics

# Measure MSE error.  
score = metrics.mean_squared_error(y_test_pred,y_test1)
print("\n\nFinal score test (MSE): %0.4f" %(score))
score1 = metrics.mean_squared_error(y_train_pred,y_train1)
print("Final score train (MSE): %0.4f" %(score1))
score2 = np.sqrt(metrics.mean_squared_error(y_test_pred,y_test1))
print(f"Final score test (RMSE): %0.4f" %(score2))
score3 = np.sqrt(metrics.mean_squared_error(y_train_pred,y_train1))
print(f"Final score train (RMSE): %0.4f" %(score3))

编辑:

我也尝试过做特征重要性并提高 n_epochs,这些是结果:

特征重要性:

无特征重要性:

看起来你没有过拟合!您的训练和验证曲线一起下降并收敛。过度拟合的最明显迹象是这两条曲线之间的偏差,如下所示:

由于你的两条曲线是下降的并且没有发散,这表明你的神经网络训练是健康的。

然而!您的验证曲线可疑地低于训练曲线。这暗示可能存在数据泄漏(训练和测试数据以某种方式混合在一起)。有关短片的更多信息 blog post。通常,您应该 在任何其他预处理(归一化、扩充、改组等)之前拆分数据

造成这种情况的其他原因可能是某种类型的正则化(dropout、BN 等),它在计算训练准确度时处于活动状态,而在计算 Validation/Test 准确度时处于停用状态。

过度拟合是指模型没有泛化到训练数据以外的其他数据。当这种情况发生时,你将有一个非常(!)低的训练损失,但验证损失很高。你可以这样想:如果你有 N 个点,你可以拟合 N-1 多项式,这样你的训练损失为零(你的模型完美地命中了所有训练点)。但是,如果将该模型应用于其他一些数据,它很可能会产生非常高的错误(见下图)。这里红线是我们的模型,绿线是真实数据(+噪声),你可以在最后一张图片中看到我们得到了零训练误差。首先,我们的模型太简单(高 train/high 验证错误),第二个很好(低 train/low 验证错误)第三个也是最后一个太复杂,即过度拟合(非常低 train/high 验证错误)。

神经网络可以以相同的方式工作,因此通过查看您的训练与验证错误,您可以得出它是否过拟合的结论

不,这不是过度拟合,因为您的验证损失没有增加。

不过,如果我是你,我会有点怀疑。尝试对您的模型进行更多训练,并注意验证损失。

您绝对应该做的是遵守以下几点: - 数据中是否存在重复或接近重复(造成从训练到测试验证拆分的信息泄漏) - 是否有与目标变量有因果关系的特征

编辑:

通常,您在真实世界的数据集中有一些随机成分,因此在训练数据中观察到的规则对于验证数据并非 100% 正确。 您的图显示,随着火车损失的减少,验证损失甚至会减少更多。通常,您在训练中会遇到某个点,您在训练数据中观察到的规则过于具体,无法描述整个数据。那是过度拟合开始的时候。因此,很奇怪,您的验证损失不会再次增加。

当你训练更多的 epoch 时,请检查你的验证损失是否接近于零。如果是这样,我会非常仔细地检查您的数据库。

让我们假设,从训练集到验证集存在某种信息泄漏(例如通过重复记录)。您的模型会更改权重以描述非常具体的规则。当将您的模型应用于新数据时,它会惨败,因为观察到的连接并不是真正普遍的。 另一个常见的数据问题是,特征可能具有相反的因果关系。

验证损失通常低于训练误差的事情可能取决于辍学和正则化,因为它在训练时应用但不适用于 predicting/testing。

我特别强调这一点,因为数据中的一个小错误或错误可能 "fuck up" 你的整个模型。