首页 › S 模型训练 › S6 评估验证 › 02

S6-02 · 交叉验证:小数据怎么评估才可靠

实战阶段约 120 分钟阶段:S6 评估验证

阶段:S6-评估验证 | 预计耗时:60-75 分钟(5 折自动跑)| 前置:S6-01 混淆矩阵与类别指标 代码:本篇代码要你自己敲成 model-learn/s6_cross_validation.py

学习目标

  1. 理解单次划分评估的方差问题:换一个划分方式,分数可能差 1-2 个点
  2. 会写 k 折交叉验证:5 折 × 1 epoch,报告 mean ± std
  3. 建立"报分数必报区间"的习惯——以后你汇报任何指标都要带上

核心知识

1. 单次划分的运气成分

5000 样本随机分一次,恰好多分到几道难题/易题,分数就波动。你的网格搜索里"第一名 vs 第二名差 0.3 个点"——可能只是划分运气(S5-03 任务 2 埋的伏笔在这兑现)。

2. k 折交叉验证(k=5)

把数据切 5 份,每轮:4 份训练 + 1 份验证,轮流当验证
5 个分数 → 报告 mean ± std
  • 优点:每个样本都当过一次验证、结果更稳
  • 代价:算力 ×5——所以只在小数据上用(你的场景正合适)
  • 调参 + 评估的正确姿势:网格搜索在 CV 上选组合 → 最终结构训练完,test 只碰一次

3. std 的直觉

std ≈ "换个划分你平均会飘多少"。两个模型的分差 < std 时,它们其实打平——这个判断能力值钱。

实验任务

任务 1:写 5 折脚本(35 分钟)

# s6_cross_validation.py —— 5 折交叉验证
import torch
from torch.utils.data import DataLoader, Subset

idx = torch.randperm(5000, generator=torch.Generator().manual_seed(42))
folds = [idx[i*1000:(i+1)*1000] for i in range(5)]

scores = []
for k in range(5):
    val_idx = folds[k]
    train_idx = torch.cat([folds[j] for j in range(5) if j != k])
    torch.manual_seed(42)                    # 模型种子固定,只有数据划分在变
    model = build_small_cnn()
    # ... 在 train_idx(4000) 上训 1 epoch,在 val_idx(1000) 上评
    scores.append(acc)
    print(f"fold {k+1}: acc={acc:.4f}")

t = torch.tensor(scores)
print(f"5折结果: mean={t.mean():.4f}  std={t.std():.4f}")

任务 2:对照单次划分(15 分钟)

从 S5-03 网格搜索的排行榜里挑一个配置(或随便一个):单次划分报的分 vs 5 折 mean±std——分差有多大?把"mean±std"写法记成肌肉记忆。

任务 3:判断打平(15 分钟)

配置 A:acc 98.1%;配置 B:acc 97.8%,CV 得到 std=0.4%。A 真的更好吗?(答:0.3 个点的差距 < 0.4 的 std,统计上打平,应选更便宜/更简单的 B。)

验收标准

衔接下一阶段

会评估了 → S7-01 不收敛排查清单:进入排查阶段——这次轮到你来当侦探。

小测验(2 题)

答完立即判分,错题给解析;得分存本地。实验与实操题不上网测:回对话找老师验收。