Cross-Validation
交叉验证会在同一数据集的 k 个轮换划分上训练并评估模型,以估算泛化能力。介绍 K 折交叉验证的步骤、变体、数据泄漏和代码。
交叉验证通过在同一数据集的不同划分上多次训练和评估模型,并汇总各次评分,来估计模型在未见数据上的表现。在 k 折交叉验证中,数据会被分成 k 个大小相等的部分,称为折;每一折都会轮流作为验证数据,模型则在其余 k − 1 折上训练。k 次评分的均值用于估计模型性能,而评分的离散程度则显示该估计受哪些样本恰好进入验证集的影响有多大。当数据过少,无法通过单次留出划分得到可靠评分时,交叉验证是标准评估方法;在不使用测试数据的情况下比较算法和调优超参数时,也广泛使用交叉验证。
K 折交叉验证的工作原理#
数据集会先随机打乱一次,然后分成 k 折,通常为 5 折或 10 折。在 k 轮中的每一轮,模型都会在 k − 1 折上重新训练,并在剩余的一折上评分,因此每个样本恰好用于验证一次、用于训练 k − 1 次。随后计算 k 次评分的平均值,并报告其标准差。交叉验证选出模型或一组超参数后,通常会使用这些设置在全部训练数据上重新训练最终模型。留一交叉验证是 k 等于样本数的极端情况;这种方法会在每一轮中尽可能多地使用数据进行训练,但需要训练的模型数量与样本数相同。
解读交叉验证评分#
各折之间的离散程度与均值同样具有参考价值。下面的 scikit-learn脚本使用内置的乳腺癌数据集运行 5 折交叉验证:
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
# 569 labeled tumor samples with 30 features each
X, y = load_breast_cancer(return_X_y=True)
# The scaler sits inside the pipeline, so each round fits it on that round's training folds only
model = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
# 5 stratified folds: each sample is validated exactly once
folds = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
scores = cross_val_score(model, X, y, cv=folds)
print("Fold accuracies:", scores.round(3))
print(f"Mean {scores.mean():.3f} +/- {scores.std():.3f}")五折的准确率介于 0.956 和 1.000 之间,均值为 0.979,标准差为 0.014。如果只进行一次 80/20 划分,报告的会是这五个数字中的任意一个,最大相差 4.4 个百分点。将缩放器放在流水线中,可以确保验证折不会参与数据预处理统计;如果先缩放整个数据集,就会导致每个验证折中的信息泄漏到训练过程中。
选择交叉验证变体#
普通 k 折假设样本彼此独立且可以互换。如果事实并非如此,随机划分就会泄漏信息,或产生无法代表任务的折:
- 分层 k 折:使每一折中的类别比例与整个数据集相同;如果稀有类别可能在某一折中缺失,这一点就很重要。
- 分组 k 折:将同一组的所有示例(例如同一名患者、同一段视频或同一采集地点的数据)放在同一个折中,确保模型不会在与训练图像近重复的样本上进行验证。分层分组 k 折会同时满足这两项约束。
- 时间序列划分:每一轮只使用过去的数据进行训练,并在随后时间段的数据上验证,同时逐轮扩展训练窗口,因为打乱按时间排序的数据会让模型看到未来信息。
- 嵌套交叉验证:在每个外层折中运行内层交叉验证循环来调优超参数,因此外层评分不会因为在同一批折上调优和评估而虚高。
深度学习中的交叉验证#
将深度网络训练 k 次会使计算成本增加 k 倍,因此 ImageNet和 COCO等大型数据集会使用固定的验证集划分,因为其规模已经足以得到稳定评分。对于只有几百到几千张图像的小型视觉数据集,交叉验证很有价值,因为单个验证集划分中每个类别的样本可能少得可怜。Ultralytics K 折交叉验证指南使用 scikit-learn 的 KFold将检测数据集分成五折,为每一折写入训练和验证图像列表以及数据集 YAML,并在每一折上训练一个 YOLO26模型。由于检测图像通常包含多个类别,因此无法根据单个标签进行分层;该指南还会记录每一折中各类别的验证标签与训练标签之比。










