【问题标题】:Cross Validation in KerasKeras 中的交叉验证
【发布时间】:2018-06-13 14:07:16
【问题描述】:

我正在 Keras 中实现多层感知器,并使用 scikit-learn 执行交叉验证。为此,我受到问题 Cross Validation in Keras

中的代码的启发
from sklearn.cross_validation import StratifiedKFold

def load_data():
    # load your data using this function

def create model():
    # create your model using this function

def train_and_evaluate__model(model, data[train], labels[train], data[test], labels[test)):
    # fit and evaluate here.

if __name__ == "__main__":
    X, Y = load_model()
    kFold = StratifiedKFold(n_splits=10)
    for train, test in kFold.split(X, Y):
        model = None
        model = create_model()
        train_evaluate(model, X[train], Y[train], X[test], Y[test])

在我对神经网络的研究中,我了解到神经网络的知识表示是在突触权重中,并且在网络跟踪过程中,权重会被更新,从而降低网络错误率并提高其性能。 (就我而言,我使用的是监督学习)

为了更好地训练和评估神经网络性能,一种常用的方法是交叉验证,它返回数据集的分区用于模型的训练和评估。

我的疑惑是……

在这段代码中sn-p:

for train, test in kFold.split(X, Y):
    model = None
    model = create_model()
    train_evaluate(model, X[train], Y[train], X[test], Y[test])

我们为每个生成的分区定义、训练和评估一个新的神经网络?

如果我的目标是针对整个数据集微调网络,为什么定义单个神经网络并使用生成的分区对其进行训练是不正确的?

也就是说,为什么这段代码是这样的?

for train, test in kFold.split(X, Y):
    model = None
    model = create_model()
    train_evaluate(model, X[train], Y[train], X[test], Y[test])

不是这样吗?

model = None
model = create_model()
for train, test in kFold.split(X, Y):
    train_evaluate(model, X[train], Y[train], X[test], Y[test])

我对代码工作原理的理解是否错误?还是我的理论?

【问题讨论】:

    标签: machine-learning keras scikit-learn neural-network cross-validation


    【解决方案1】:

    如果我的目标是为整个数据集微调网络

    不清楚您所说的“微调”是什么意思,甚至不清楚您执行交叉验证(CV)的目的是什么;一般来说,CV 服务于以下目的之一:

    • 模型选择(选择超参数的值)
    • 模型评估

    由于您没有为代码中的超参数选择定义任何搜索网格,您似乎正在使用 CV 来获得模型的预期性能(错误、准确性等)。

    无论如何,无论出于何种原因使用 CV,第一个 sn-p 都是正确的;你的第二个sn-p

    model = None
    model = create_model()
    for train, test in kFold.split(X, Y):
        train_evaluate(model, X[train], Y[train], X[test], Y[test])
    

    将在不同的分区上按顺序训练您的模型(即在分区 #1 上训练,然后在分区 #2 上继续训练等),这实际上只是在您的整个数据集上进行训练,它肯定不是交叉验证...

    也就是说,CV 之后的最后一步 通常只是暗示(并且初学者经常会错过)是,在您对所选择的超参数和/或模型性能感到满意之后您的 CV 程序,您返回并再次训练您的模型,这次使用整个可用数据。

    【讨论】:

      【解决方案2】:

      您可以将 Scikit-Learn API 的包装器与 Keras 模型一起使用。

      给定输入 xy,这是重复 5 折交叉验证的示例:

      from sklearn.model_selection import RepeatedKFold, cross_val_score
      from tensorflow.keras.models import * 
      from tensorflow.keras.layers import * 
      from tensorflow.keras.wrappers.scikit_learn import KerasRegressor
      
      def buildmodel():
          model= Sequential([
              Dense(10, activation="relu"),
              Dense(5, activation="relu"),
              Dense(1)
          ])
          model.compile(optimizer='adam', loss='mse', metrics=['mse'])
          return(model)
      
      estimator= KerasRegressor(build_fn=buildmodel, epochs=100, batch_size=10, verbose=0)
      kfold= RepeatedKFold(n_splits=5, n_repeats=100)
      results= cross_val_score(estimator, x, y, cv=kfold, n_jobs=2)  # 2 cpus
      results.mean()  # Mean MSE
      

      【讨论】:

        【解决方案3】:

        如果您阅读了有关嵌套交叉验证的信息,我认为您的许多问题都会得到解答。这是“微调”模型超参数的好方法。这里有一个线程:

        https://stats.stackexchange.com/questions/65128/nested-cross-validation-for-model-selection

        需要注意的最大问题是“偷看”或循环逻辑。本质上 - 您希望确保在训练期间没有用于评估模型准确性的数据出现。

        如果您正在运行诸如 PCA 或 ICA 之类的东西来进行特征提取,这可能会出现问题。如果做这样的事情,你必须确保在你的训练集上运行 PCA,然后将训练集的变换矩阵应用到测试集。

        【讨论】:

          【解决方案4】:

          注释掉的函数使这一点变得不那么明显,但其想法是在迭代折叠时跟踪模型性能,最后提供那些较低级别的性能指标或平均的全局性能。例如:

          train_evaluate 函数理想情况下会为每个分割输出一些准确度分数,可以在最后合并。

          def train_evaluate(model, x_train, y_train, x_test, y_test):
              model.fit(x_train, y_train)
              return model.score(x_test, y_test)
          
          X, Y = load_model()
          kFold = StratifiedKFold(n_splits=10)
          scores = np.zeros(10)
          idx = 0
          for train, test in kFold.split(X, Y):
              model = create_model()
              scores[idx] = train_evaluate(model, X[train], Y[train], X[test], Y[test])
              idx += 1
          print(scores)
          print(scores.mean())
          

          所以是的,您确实希望为每个折叠创建一个新模型,因为本练习的目的是确定您的模型在设计时如何在所有数据段上执行,而不仅仅是一个特定的段,可能会或可能不会让模型表现良好。

          当与超参数的网格搜索一起应用时,这种方法会变得特别强大。在这种方法中,您使用交叉验证拆分训练具有不同超参数的模型,并跟踪拆分和整体的性能。最后,您将能够更好地了解哪些超参数可以让模型表现最佳。有关更深入的解释,请参阅sklearn Model Selection,并特别注意交叉验证和网格搜索部分。

          【讨论】:

          • 嘿!我现在知道了!我混淆了交叉验证过程的逻辑,但现在它是有道理的。非常感谢您的帮助! :D
          【解决方案5】:

          测试模型性能的主要思路是执行以下步骤:

          1. 在训练集上训练模型。
          2. 在训练过程中未使用的数据上评估您的模型,以模拟新的数据到达。

          所以基本上 - 你最终应该测试你的模型的数据应该模仿你将从客户端/应用程序获得的第一个数据部分,以应用你的模型。

          这就是交叉验证如此强大的原因 - 它使整个数据集中的每个数据点都可以用作新数据的模拟。

          现在 - 回答您的问题 - 每个交叉验证都应遵循以下模式:

          for train, test in kFold.split(X, Y
               model = training_procedure(train, ...)
               score = evaluation_procedure(model, test, ...)
          

          因为毕竟,您将首先训练您的模型,然后将其用于新数据。在您的第二种方法中-您不能将其视为对培训过程的模仿,因为例如在第二折中,您的模型将保留第一折中的信息 - 这不等同于您的训练过程。

          当然 - 您可以应用使用 10 次连续训练的训练程序来微调网络。但这不是交叉验证——你需要使用上面的某种模式来评估这个过程。

          【讨论】:

          • 啊啊啊啊我明白了!我混淆了交叉验证过程的逻辑,但现在它是有道理的。非常感谢!
          猜你喜欢
          • 2017-04-10
          • 2020-10-25
          • 2021-09-26
          • 2018-11-27
          • 2017-05-04
          • 2022-06-15
          • 2017-04-12
          • 1970-01-01
          • 2021-01-17
          相关资源
          最近更新 更多