趋近智
正如我们在学习曲线中看到的那样,仅仅最小化训练数据上的损失并不能保证在未见过的数据上表现良好。我们需要可靠的途径来估算模型在部署前的泛化能力。这需要仔细划分数据,以模拟遇到新示例的情形。
深度学习 (deep learning)中,尤其是在大型数据集上,最常见的策略是将可用数据分为三个不同的数据集:
典型的划分比例可能是训练集占70%,验证集占15%,测试集占15%,但这些百分比会根据数据集的总大小而显著不同。对于非常大型的数据集(数百万个示例),验证集和测试集所占的比例可能小得多(例如,各占1%),但其绝对数量仍足以提供可靠的评估。
留出法的主要优点是其简单性和计算效率。然而,在验证集上获得的性能估计可能对特定的随机划分敏感,特别是当数据集不是很大时。“幸运”或“不幸运”的划分可能会对模型真实能力产生误导性印象。
K折交叉验证是一种有用的方法,尤其在数据稀缺或需要可靠泛化性能评估时。它通过使用多次数据划分来减少评估结果的方差,从而提供模型性能的更稳定估计。
其工作原理如下:
K折交叉验证图示。训练数据被分成 k 个折。在每次迭代中,一个折作为验证集(红色),而其他折用于训练(蓝色)。每次迭代的性能指标被平均。
K折交叉验证的优点:
K折交叉验证的缺点:
分层K折: 在处理分类问题时,特别是当类别不平衡时,重要的是每个折都能保留与完整数据集近似的每个类别的样本百分比。分层K折交叉验证确保这种分层,从而得到更可靠的评估。
尽管由于成本原因,K折交叉验证在深度学习中较少用于最终模型训练,但它是一种非常有用的方法,可用于:
无论是使用简单的留出划分还是准备交叉验证,都需要仔细实现。像 Scikit-learn 这样的库提供了方便的功能。
import torch
from sklearn.model_selection import train_test_split, StratifiedKFold
import numpy as np
# 假设 X_data 包含你的特征,y_data 包含你的标签(作为 NumPy 数组或张量)
# 示例模拟数据
X_data = np.random.rand(1000, 20) # 1000 samples, 20 features
y_data = np.random.randint(0, 2, 1000) # 1000 binary labels
# --- 留出划分 ---
# 首先,划分为训练+验证集和测试集
X_train_val, X_test, y_train_val, y_test = train_test_split(
X_data, y_data, test_size=0.15, random_state=42, stratify=y_data # 分类问题使用 stratify 参数进行分层
)
# 然后,将训练+验证集划分为实际的训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(
X_train_val, y_train_val, test_size=0.1765, # 大约是原始数据的 15% (0.15 / (1-0.15))
random_state=42, stratify=y_train_val # 保持分层
)
print(f"留出划分大小:训练集={len(X_train)}, 验证集={len(X_val)}, 测试集={len(X_test)}")
# 输出:留出划分大小:训练集=700, 验证集=150, 测试集=150 (近似比例)
# --- K折交叉验证设置(使用分层K折)---
n_splits = 5
skf = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=42)
print(f"\n{n_splits}折交叉验证索引(使用原始训练+验证数据):")
# 注意:这里我们使用 X_train_val,因为测试集总是保持独立。
fold_num = 1
for train_index, val_index in skf.split(X_train_val, y_train_val):
print(f"折 {fold_num}:")
print(f" 训练样本: {len(train_index)}, 验证样本: {len(val_index)}")
# 在真实的交叉验证循环中,你会使用这些索引来选择数据:
# X_train_fold, X_val_fold = X_train_val[train_index], X_train_val[val_index]
# y_train_fold, y_val_fold = y_train_val[train_index], y_train_val[val_index]
# ... 然后在这些折特定的数据集上训练和评估模型
fold_num += 1
# 如果训练需要,转换为 PyTorch 张量
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train, dtype=torch.long) # 假设是分类标签
X_val_tensor = torch.tensor(X_val, dtype=torch.float32)
y_val_tensor = torch.tensor(y_val, dtype=torch.long)
X_test_tensor = torch.tensor(X_test, dtype=torch.float32)
y_test_tensor = torch.tensor(y_test, dtype=torch.long)
使用 Scikit-learn 创建留出划分并生成 K折交叉验证的索引。
random_state确保可复现性,stratify保持类别比例。
请记住:
shuffle=True 时默认会这样做。选择正确的验证策略很重要。它使我们能够可靠地评估泛化性能,诊断过拟合 (overfitting)等问题,并在模型开发过程中做出明智的决策,最终产生在实际遇到的数据上表现良好的模型。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造