如何正确绘制训练集和验证集的损失曲线?

3

我希望用Scikit绘制训练和验证集的损失曲线,就像Keras一样。我选择了一个具体的回归问题数据集,该数据集可在以下位置找到:

http://archive.ics.uci.edu/ml/machine-learning-databases/concrete/compressive/

所以,我已经将数据转换为CSV格式,我的程序的第一个版本如下: 模型1
df=pd.read_csv("Concrete_Data.csv")
train,validate,test=np.split(df.sample(frac=1),[int(.8*len(df)),int(.90*len(df))])
Xtrain=train.drop(["ConcreteCompStrength"],axis="columns")
ytrain=train["ConcreteCompStrength"]
Xval=validate.drop(["ConcreteCompStrength"],axis="columns")
yval=validate["ConcreteCompStrength"]
mlp=MLPRegressor(activation="relu",max_iter=5000,solver="adam",random_state=2)
mlp.fit(Xtrain,ytrain)

plt.plot(mlp.loss_curve_,label="train")
mlp.fit(Xval,yval)                           #doubt
plt.plot(mlp.loss_curve_,label="validation") #doubt
plt.legend()

生成的图表如下:

enter image description here

在这个模型中,我怀疑标记部分是否正确,因为据我所知,人们应该将验证或测试集分开,所以也许fit函数在那里不正确。我得到的分数是0.95。
第二个模型:
在这个模型中,我尝试使用验证分数如下:
df=pd.read_csv("Concrete_Data.csv")
train,validate,test=np.split(df.sample(frac=1),[int(.8*len(df)),int(.90*len(df))])
Xtrain=train.drop(["ConcreteCompStrength"],axis="columns")
ytrain=train["ConcreteCompStrength"]
Xval=validate.drop(["ConcreteCompStrength"],axis="columns")
yval=validate["ConcreteCompStrength"]
mlp=MLPRegressor(activation="relu",max_iter=5000,solver="adam",random_state=2,early_stopping=True)
mlp.fit(Xtrain,ytrain)

plt.plot(mlp.loss_curve_,label="train")
plt.plot(mlp.validation_scores_,label="validation")   #line changed
plt.legend()

对于这个模型,我必须将早停止的部分设置为true,并且要绘制验证分数,但是图形结果有点奇怪:

enter image description here

我得到的分数是0.82,但我看到这种情况发生在模型更容易预测验证集中的数据而不是训练集中时。我相信这是因为我使用了validation_scores_部分,但我找不到任何关于这个特定指令的在线参考。
在Scikit中,调整超参数的正确方法是如何绘制这些损失曲线?
更新:我已经按照建议编写了模块,如下所示:
mlp=MLPRegressor(activation="relu",max_iter=1,solver="adam",random_state=2,early_stopping=True)
training_mse = []
validation_mse = []
epochs = 5000
for epoch in range(1,epochs):
    mlp.fit(X_train, Y_train) 
    Y_pred = mlp.predict(X_train)
    curr_train_score = mean_squared_error(Y_train, Y_pred) # training performances
    Y_pred = mlp.predict(X_valid) 
    curr_valid_score = mean_squared_error(Y_valid, Y_pred) # validation performances
    training_mse.append(curr_train_score) # list of training perf to plot
    validation_mse.append(curr_valid_score) # list of valid perf to plot
plt.plot(training_mse,label="train")
plt.plot(validation_mse,label="validation")
plt.legend()

但所得的图形是两条平直的线:

enter image description here

这里似乎有些东西我没搞明白。

2个回答

3

模型不应该拟合验证集。通常,验证集用于决定使用哪些超参数,而不是参数值。

标准的训练方式是将数据集分成三部分:

  • 训练集
  • 验证集
  • 测试集

例如,可以将数据集按 80%,10%,10% 的比例划分。

通常情况下,您会选择一个神经网络(包括多少层、节点数以及激活函数),然后只在训练集上进行训练,然后在验证集和测试集上检查结果。

以下是伪代码以更清晰地说明这一点:

for model in my_networks:       # hyperparameters selection
    model.fit(X_train, Y_train) # parameters fitting
    model.predict(X_valid)      # no train, only check on performances

在验证集上保存模型的表现并选择最佳模型(验证集上得分最高的模型),然后在测试集上检查结果:

model.predict(X_test) # this will be the estimated performance of your model

如果您的数据集足够大,您也可以使用类似交叉验证的方法。

无论如何,记住:

  • 参数是神经网络的权重
  • 您使用训练集来拟合参数
  • 超参数是定义网络架构(层、节点、激活函数)的参数
  • 通过在验证集上检查模型结果,您可以选择最佳超参数
  • 在选择了最佳参数和最佳超参数后,通过在测试集上测试模型来获得模型性能

要获得与 keras 相同的结果,您应该了解当您在默认参数下调用模型的 fit() 方法时,训练会在固定的 epoch 数量(200),您定义的 epoch 数量(在此例中为 5000)或当您定义一个 early_stopping 时停止。

max_iter: int,默认值为 200

最大迭代次数。对于随机求解器(‘sgd’,‘adam’),请注意这决定了每个数据点将被使用多少次,而不是渐变步骤的数量。求解器迭代直到收敛(由 ‘tol’ 决定)或迭代次数达到此数字为止。

scikit page上检查您的模型定义和参数

要获得与 keras 相同的结果,您可以固定训练 epoch(例如每次训练 1 步),在验证集上检查结果,然后再次训练,直到达到所需的 epoch 数量。

例如,像这样做(如果您的模型使用 mse):

epochs = 5000

mlp = MLPRegressor(activation="relu",
                   max_iter=1,
                   solver="adam",
                   random_state=2,
                   early_stopping=True)
training_mse = []
validation_mse = []
for epoch in epochs:
    mlp.fit(X_train, Y_train) 
    Y_pred = mlp.predict(X_train)
    curr_train_score = mean_squared_error(Y_train, Y_pred) # training performances
    Y_pred = mlp.predict(X_valid) 
    curr_valid_score = mean_squared_error(Y_valid, Y_pred) # validation performances
    training_mse.append(curr_train_score)                  # list of training perf to plot
    validation_mse.append(curr_valid_score)                # list of valid perf to plot

@Little,不要在循环中每次都定义模型,否则它会重新初始化网络。你需要逐步学习你的模型,在每个时期都有改进。 - Nikaido
@Little 请注意,我的示例仅测试网络及其渐进式训练。如果我想测试其他网络,则需要在外部添加另一个循环,每次迭代(和初始化)一个具有新结构(超参数)的新网络。 - Nikaido
@小伙伴,可能在for循环中你应该使用"partial_fit"而不是"fit"。 - Nikaido
1
现在使用部分拟合后,它可以工作了。但是对于像500这样少量的时期来说,它更加明显。非常感谢您的耐心支持 : ) ,最后一个问题,您是否建议在这种情况下坚持使用Keras?它似乎比scikit更容易绘制这些图形。有什么建议吗? - Little
1
@Little,这取决于情况。如果你需要进行深度学习,那么使用keras会更好。如果你处理的是小数据,我认为scikit learn更好。请记住,keras适用于神经网络。Scikit learn并不专注于某一特定模型,而是涵盖了许多不同的模型。这取决于你的目标。欢迎您:)。别忘了接受最佳答案! - Nikaido
显示剩余9条评论

1

我有同样的问题:按照建议使用该模块时,得到了两条平行线,我只需向MLPRegressor参数中添加warm_start=True来解决问题,如MLPRegressor- 1.17.9. 更多控制与warm_start中所述。

mlp=MLPRegressor(activation="relu",max_iter=1,solver="adam",random_state=2,early_stopping=True, warm_star=True)

现在得到的图形是正确的: 训练和验证损失曲线


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接