【问题标题】:Overfitting and data leakage in tensorflow/keras neural networktensorflow/keras 神经网络中的过拟合和数据泄露
【发布时间】:2020-01-22 09:39:52
【问题描述】:

早上好,我是机器学习和神经网络的新手。我正在尝试构建一个完全连接的神经网络来解决回归问题。数据集由 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,结果如下:

功能重要性:

没有重要的功能:

【问题讨论】:

  • 不,根据您的曲线,这里没有过度拟合。如您所见,损失非常接近。在过拟合模型中,验证损失远高于训练损失。因为模型过拟合训练数据并且不能很好地预测新数据(验证数据集)
  • 当你的模型太复杂(特征太少,或者模型有很多层)并且对训练数据集学习得很好时,就会出现过拟合,你可以通过正则化、dropout层、更多数据等来防止它方法
  • @AdForte 好的,谢谢!但是我知道如果训练损失超过了验证损失,那就是过拟合了,所以这是错误的吗?
  • 是的,过拟合很糟糕,但是我们可以从曲线中看到你的模型,对我来说似乎很好
  • 这不是一个真正的编程问题,它与本网站无关。

标签: python neural-network anaconda spyder figure


【解决方案1】:

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

由于您的两条曲线在下降并且没有发散,这表明您的 NN 训练是健康的。

但是!您的验证曲线可疑地低于训练曲线。这暗示可能存在数据泄漏(训练和测试数据以某种方式混合)。更多关于简短的信息blog post。一般来说,您应该在进行任何其他预处理(规范化、扩充、改组等)之前拆分数据

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

【讨论】:

  • 感谢您的回答,如果训练损失曲线低于(但接近)验证损失曲线或相反,这是否重要?
  • 这是另一个问题,甚至值得单独问!确实很奇怪。我怀疑我可能会发生一些数据泄漏(用于验证的训练数据,用于训练的验证数据,......)。确保在进行任何洗牌之前将训练和验证数据集分开,并且分开洗牌。
  • @ibarrond 我也假设信息泄露。通常,当我看到有人以这种学习曲线接近我时,他的管道中有一些错误或有问题的数据。一般来说,验证损失低于训练损失可能是因为在训练时应用了正则化,而不是在预测中?尽管如此,进一步减少的 val 损失似乎很可疑。
  • @GabrieleValvo 看起来您的验证曲线仍低于训练曲线。在tf文档中查了一下,我相信在计算训练准确率时需要明确关闭dropout。在这个 github 问题上有一些关于如何这样做的提示:github.com/tensorflow/tensorflow/issues/19420
  • 我不会说验证低于训练是一个问题(公关默认)。我同意应该考虑一下,但是当差距不大时,我认为还可以。测试/训练拆分可能(确实)是错误的,但也可能只是碰巧验证更接近模型。
【解决方案2】:

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

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

【讨论】:

  • 谢谢,您的回答很有用。所以火车损失是否超过了我上传的图片中的验证损失并不重要?
  • 其实这应该是极少数情况(我之前没有注意到)。你可以说训练损失应该总是小于验证(因为模型正在适应训练数据)。但是,如果验证集(以某种方式)更接近模型,则可能会发生这种情况,但是由于这个微小的差异,我认为没有问题
  • 我在主要问题上添加了一些其他情节,你怎么看?
  • 我问你一个问题:如果你比较训练损失和验证,你会看到什么?
【解决方案3】:

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

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

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

编辑:

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

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

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

验证损失通常低于训练错误可能取决于 dropout 和正则化,因为它在训练时应用,但不用于预测/测试。

我强调这一点,因为数据中的一个小错误或错误可能会“搞砸”你的整个模型。

【讨论】:

  • Kleine Boesing 感谢您的回答,我尝试增加 n_epochs,结果是 val_loss e trainign_loss 比以前收敛更多。数据集是物理量的采样结果,所以目标是连接到特征的(不是所有的特征都具有相同的重要性,我要做特征重要性)。如果您指的是样本之类的记录,则有 8500 个样本。我不明白你为什么怀疑??
  • 所以训练损失是否超过(但接近)val损失并不重要?因为我知道当训练损失低于 val 损失时模型是好的(没有过度拟合)。你同意? p.s 我知道这不是正确的地方,但我想在评论中上传图片,你知道我该怎么做吗?谢谢。
  • 我试图查看数据集中是否有一些重复,但我也没有找到它,因为它是在不同物理条件下采样的数据集的并集。我不明白这句话“验证损失通常低于训练错误的事情可能取决于辍学和正则化,因为它在训练时应用但不用于预测/测试。”。您认为我可以尝试做什么?
  • 我在主要问题上添加了一些其他情节,你怎么看?
猜你喜欢
  • 2021-07-07
  • 2018-12-09
  • 1970-01-01
  • 1970-01-01
  • 2017-11-27
  • 2018-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多