Test Data
测试数据是一个留出数据集,只有在所有训练和调参完成后才进行一次评分,用于估算模型在新数据上的表现。内容涵盖数据集划分、规模、注意事项和代码。
测试数据也称测试集或留出集,是数据集中预留出来用于评估已完成机器学习(ML)模型的部分。测试数据不参与拟合模型权重,也不用于任何开发决策,例如架构、超参数、检查点或置信度阈值;只有这些决策都确定后才会对测试数据评分。由于模型及其开发人员从未根据测试数据进行调整,因此测试数据上的准确率、召回率或平均精度均值(mAP),能够无偏地估计模型在同一分布的新数据上的表现;团队会用这个数值判断模型是否已准备好部署。
训练集、验证集和测试集划分#
数据集通常会划分为三个互不重叠的部分,各自承担不同任务:
- 训练数据: 优化器从这些样本中学习,并通过调整权重来降低损失。
- 验证数据: 在开发期间反复评分,用于比较超参数、提前停止训练并选择最佳检查点。
- 测试数据: 在最后评分一次,以报告项目评判所依据的指标。
对于包含数千个样本的数据集,常见划分比例为 80/10/10 或 70/15/15;包含数百万个样本的数据集则可以留出几个百分点。测试集所需的大小取决于所需精度:在 n 个样本上测得准确率 p 时,标准误差为 √(p(1 − p)/n),因此 1,000 张测试图像在准确率为 90% 时给出的 95% 置信区间约为 ±1.9 个百分点,而 10,000 张图像可将其缩小到约 ±0.6 个百分点。不同领域的命名方式有所不同;由于 ImageNet测试标签不公开,许多论文会在官方验证集上报告最终 ImageNet 结果。在 Ultralytics YOLO 中,数据集 YAML 必须包含 train 和 val 路径,并可选地包含 test 路径;训练期间每个周期结束后都会对 val 评分,以选出 best.pt;而 model.val(data="data.yaml", split="test") 会在留出图像上以验证模式评估完成训练的模型。
为什么测试集必须保持未触碰#
根据评分作出的每项决策,都会让模型稍微适应这批数据。多个配置在验证集上竞争时,胜出者有一部分优势来自它恰好在这些特定样本上表现较好,因此其验证得分会高估它在其他数据上的表现。下面的 scikit-learn 实验会在一个小型噪声数据集上,为k 近邻分类器挑选最佳邻居数,并比较模型在 30 个随机数据集上的验证准确率和测试准确率:
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
val_scores, test_scores = [], []
for seed in range(30):
# A small, noisy dataset split 60/20/20 into train, validation, and test
X, y = make_classification(n_samples=400, n_features=20, n_informative=4, flip_y=0.2, random_state=seed)
X_train, X_rest, y_train, y_rest = train_test_split(X, y, test_size=0.4, random_state=seed)
X_val, X_test, y_val, y_test = train_test_split(X_rest, y_rest, test_size=0.5, random_state=seed)
# Model selection: keep the neighbor count with the best validation accuracy
scores = {k: KNeighborsClassifier(k).fit(X_train, y_train).score(X_val, y_val) for k in range(1, 51)}
best_k = max(scores, key=scores.get)
val_scores.append(scores[best_k])
# The test set is scored once, after the choice is final
test_scores.append(KNeighborsClassifier(best_k).fit(X_train, y_train).score(X_test, y_test))
print(f"Chosen model, mean of 30 runs: validation {np.mean(val_scores):.3f}, test {np.mean(test_scores):.3f}")选出的模型在验证集上的平均准确率为 0.805,在测试集上的平均准确率为 0.758,因此从 50 个候选项中选择模型,让验证集的估算值虚高了将近 5 个百分点。如果根据测试集进行调参,这个差距就会被掩盖,报告结果也会带有同样的乐观偏差,这是一种数据泄漏。公开基准通过不公开标签来防止这种情况:COCO test-dev 的结果需要将预测提交到评测服务器才能获得。对于大型语言模型(LLM),如果测试题目出现在网络规模的预训练数据中,就会污染基准;因此 LiveCodeBench 会持续加入新的竞赛题,并只评测在模型训练截止日期之后发布的题目。
构建可靠的测试集#
只有当测试集与模型将要遇到的数据相似时,测试得分才能预测实际表现,无论数据是自动驾驶汽车的街景,还是医学图像分析的扫描图像:
- 匹配部署条件: 摄像头、光照、季节、地理位置和类别分布都应反映生产环境。即使大多数驾驶都发生在晴朗天气,驾驶检测器的测试集中仍需要包含夜间、雨天和雪天场景。
- 保持独立:来自同一视频的帧、同一患者的扫描图像以及同一场景的照片应放在同一个数据集划分中。按时间排序的数据应按日期划分,以便使用未来数据测试模型。
- 跨来源测试: 在医学影像中,使用其他医院和扫描仪型号的扫描图像进行外部验证,可判断模型学到的是人体解剖结构,还是某家医院的设备特征。
- 清理标签: 测试标签中的错误会限制可测得的准确率,并可能改变模型排名,因此测试标签最值得仔细审核。
- 报告细分结果: 按类别和条件划分的指标能够揭示单一平均值所掩盖的问题。
即使重新精心构建测试集,结果也可能发生变化:研究人员按照原始收集流程重新创建 ImageNet 测试集后,发现多种模型的准确率下降了 11 至 14 个百分点;不过,模型在原始测试集上的提升也延续到了新测试集。作者将准确率下降归因于图像略难,而非测试集多年重复使用。










