模型选择和交叉验证:正确的方法

机器算法验证 交叉验证 模型选择
2022-01-24 18:56:28

CrossValidated 中有很多关于模型选择和交叉验证的主题。这里有几个:

然而,这些线程的答案是相当通用的,并且主要强调了交叉验证和模型选择的特定方法的问题。

为了使事情尽可能具体,例如,我们正在使用带有 RBF 内核的 SVM: ,并且我有一个特征X和标签y的数据集,我想K(x,x)=(γ|xx|)2

  1. 找到我的模型的最佳可能值(γC
  2. 使用我的数据集训练 SVM(用于最终部署)
  3. 估计泛化误差和围绕该误差的不确定性(方差)

为此,我会亲自进行网格搜索,例如,我尝试 的所有可能组合。为简单起见,我们可以假设以下范围:Cγ

  • C{10,100,1000}
  • γ{0.1,0.2,0.5,1.0}

更具体地说,使用我的完整数据集,我执行以下操作:

  1. 对于每个 ( ,折交叉验证(例如 )的迭代(例如 100 次随机重复)折上训练我的 SVM并评估左侧折叠错误,遍历所有折叠。总的来说,我收集了 100 x 10 = 1000 个测试错误。CγKK=10K1K
  2. 对于每个这样的 ( , ) 对,我计算这 1000 个测试错误的均值和方差。CγμM,σM

现在我想选择最佳模型(最佳内核参数),用于在完整数据集上训练我的最终 SVM。我的理解是,选择具有最低误差均值和方差 的模型是正确的选择,并且这个模型的是我在训练时对模型的泛化误差偏差和方差的最佳估计完整的数据集。μMσMμMσM

但是,在阅读了上述线程中的答案后,我的印象是,这种选择最佳 SVM 进行部署和/或估计其错误(泛化性能)的方法是有缺陷的,并且有更好的方法来选择最佳 SVM 并报告其错误。如果是这样,它们是什么?我正在寻找一个具体的答案。

坚持这个问题,我如何具体选择最佳模型正确估计其泛化误差

2个回答

我在 JMLR 中的论文解决了这个确切的问题,并说明了为什么问题中建议的程序(或至少一个非常类似的程序)会导致乐观的有偏差的性能估计:

Gavin C. Cawley, Nicola LC Talbot,“论模型选择中的过度拟合和性能评估中的后续选择偏差”,机器学习研究杂志,11(7 月):2079-2107,2010。(www

要记住的关键是交叉验证是一种用于估计生成模型的方法的泛化性能的技术,而不是模型本身的泛化性能。因此,如果选择内核参数是生成模型过程的一部分,您还需要交叉验证模型选择过程,否则您最终会得到一个乐观的有偏差的性能估计(就像您提出的程序一样)。

假设您有一个函数 fit_model,它接收由属性 X 和所需响应 Y 组成的数据集,并返回该数据集的拟合模型,包括超参数的调整(在本例中为内核和正则化参数)。这种超参数的调整可以通过多种方式执行,例如最小化 X 和 Y 上的交叉验证误差。

第 1 步 - 使用函数 fit_model 将模型拟合到所有可用数据。这为您提供了将在操作或部署中使用的模型。

第 2 步 - 绩效评估。使用所有可用数据执行重复交叉验证。在每一折中,数据被划分为训练集和测试集。使用训练集拟合模型(记录拟合模型的超参数值)并评估测试集的性能。使用所有测试集的平均值作为性能估计(也许还可以查看值的分布)。

第 3 步 - 超参数设置的可变性 - 对第 3 步中收集的超参数值进行分析。但是我应该指出,超参数并没有什么特别之处,它们只是已估计的模型参数(间接) 从数据中。为了计算/数学上的方便,它们被视为超参数而不是参数,但事实并非如此。

在这里使用交叉验证的问题是训练和测试数据不是独立样本(因为它们共享数据),这意味着对性能估计和超参数方差的估计很可能是有偏差的(即小于每个折叠中真正独立的数据样本)。如果这在计算上是可行的,我可能会使用引导程序而不是重复的交叉验证,并将结果模型打包。

关键是要获得无偏的性能估计,无论您用来生成最终模型 (fit_model) 的任何过程都必须在交叉验证过程的每一折中独立地重复完整。

使用具有固定超参数()的 SVM 是一种机器学习算法。γC

优化这些超参数并使用这些超参数训练 SVM 的过程也只是一种机器学习算法它不仅优化了 SVM 的内部参数(支持向量),还优化了超参数。

现在你有两个问题[可以独立解决]:

阅读交叉验证滥用(报告最佳超参数值的性能)以确保您不会混淆它们。


针对您问题的具体问题的特定(可能不是最佳)解决方案:

k = 5
loss_CV = zeros(k)
for i in 1:k 
    Xi_train, Xi_test = folds(X,k)[i]
    loss = zeros((3,3))
    for lambda in {0.1,0.2,0.5,1.0}
        for C in {10,100,1000}
            for j in 1:k
                Xj_train, Xj_test = folds(Xi_train,k)[j]
                model = SVM(Xj_train,lambda, C)
                loss[lambda,C] += test_error(model,Xj_test)
    lambda, C = argmax(loss)
    model = SVM(Xi_train,lambda, C)
    loss_CV += test_error(model,Xi_test)

loss = zeros((3,3))
for lambda in {0.1,0.2,0.5,1.0}
    for C in {10,100,1000}
        for j in 1:k
            Xj_train, Xj_test = folds(Xi_train,k)[j]
            model = SVM(Xj_train,lambda, C)
            loss[lambda,C] += test_error(model,Xj_test)
lambda, C = argmax(loss)
model = SVM(Xi_train,lambda, C)

在这里,model将是您的“最佳模型”和loss_CV“对其泛化误差的正确估计”(虽然偏向上,但您不能吃蛋糕也不能吃)。