只用 20 条训练数据:训练准确率 1.0000,测试只有 0.8888。 给到 1000 条,训练还是 0.9940,测试涨到 0.9925。 训练那一列永远贴着 1.00,看不出来任何问题——数据够不够,只能看测试那一列。
第二章把模型跑起来了。这一节开始往里喂东西——先搞清楚「数据集」到底是什么,以及多少条才算够。
一、数据集不是一个集合,是三个
训练集、验证集、测试集。 三份数据必须互不重叠,各干一件事:训练集用来改参数,验证集用来挑超参数,测试集只用来最后报数。 常见的错法是把验证集当测试集用——反复在同一个集合上试参数、看哪个最好,试了五十次之后, 那个集合的信息已经漏进你的决策里了,它报出来的数就不再是「没见过的新数据上有多好」。 所以规矩是:验证集可以用很多次,测试集只用一次。测试集用过一次之后就该锁起来, 想再调参就得重新划一份。 比例上,小数据集常用 6:2:2 或 8:1:1,大数据集可以 98:1:1。 验证集和测试集要小到「够判断就行」,不必多。
二、训练集要多少条
这个问题没有通用答案,但它有一个可操作的判断方法:看测试准确率什么时候停止上涨。 Demo 里扫了七档。 20 条的时候训练准确率 1.0000、测试 0.8888,差距 11 个百分点——这是标准的过拟合: 模型把 20 条背下来了,到新数据上就露馅。 给到 1000 条,测试到 0.9925,涨了 10 个百分点。 但训练准确率从头到尾都在 0.99 到 1.00 之间,一点信息都没给。 这就是这一节最重要的一句话:只看训练集上的表现,你永远不知道数据够不够。它一定是好看的, 因为模型有足够的自由度把见过的都记住。 给到 2000 条,测试反而略降到 0.9900。 不是数据变差了,是这一档已经进入平台区,剩下的是任务本身的噪声上限。 到了这个区间,该去提质量,不该再堆数量。
三、还要看「最少的那个类」
总数够不等于分布够。Demo 第二列是训练集里最少那个类的样本数:20 条时只有 5 条。 这 5 条的问题很实际:如果另一类有 15 条,模型全猜多的那一边就能拿 75% 的准确率。 准确率这个指标本身,在类别不平衡的时候会骗人。 所以看数据集要连着看三项:总条数、各类条数、最少那个类的条数。 第三项差三倍以上,就该做重采样或者调整损失权重。 分类任务看类别分布,生成任务看什么?看长度分布和句式分布。都是「分布」,不是「总量」。
四、数据质量和数据量,先管哪个
答案很明确:先管质量。 Demo 里 20 条干净数据能到 0.8888,而如果你有 2000 条里有 30% 标注错的数据, 模型学到的是那 30% 的错法——错的样本不是噪声,是错误的目标。 经验顺序是:先扩到能跑起来的量(几百条),再清一遍质量(去重、查标注一致性、剔掉模板化的), 最后才考虑继续扩量。 扩量是把已有的偏差放大,不是把偏差平均掉。 这句话值得记住。
五、动手 Demo:20 条:训练 1.0000、测试 0.8888;1000 条:测试 0.9925
造一批「圆内一类、圆外一类」的数据——这条边界一条直线分不开,但用二次特征就能表达。 固定测试集,让训练集从 20 条涨到 2000 条,看训练准确率和测试准确率各自怎么变。
X = rg.uniform(-1.5, 1.5, (n, 2))
y = ((X ** 2).sum(1) > 1.0).astype(int) # 圆内 0、圆外 1
def feat(A): # 二次特征
a, b = A[:, 0], A[:, 1]
return np.stack([a, b, a * a, a * b, b * b], 1)
Xte, yte = F[-800:], y[-800:] # 测试集固定不动
for m in (20, 50, 100, 200, 500, 1000, 2000):
W, b = train(Xtr_all[:m], ytr_all[:m])
print(m, acc(W, b, Xtr_all[:m], ytr_all[:m]), acc(W, b, Xte, yte))
实跑输出:
--------------------------------------------------------------------
数据集:训练集给多少条,才叫「够了」
--------------------------------------------------------------------
训练条数 最少的类 训练准确率 测试准确率
--------------------------------------------
20 5 1.0000 0.8888
50 13 1.0000 0.9075
100 31 0.9900 0.9650
200 71 0.9950 0.9838
500 178 0.9940 0.9862
1000 371 0.9940 0.9925
2000 684 0.9885 0.9900
看第三列和第四列:**训练准确率从头到尾贴着 1.00,只有测试那一列在动。**
20 条的时候训练 1.0000、测试 0.8888——差了 11.12 个百分点,这就是过拟合。
最好的一档是 0.9925(1000 条),比 20 条时高 10.37 个百分点;再多到 2000 条反而略降到 0.9900。
这张表最重要的一条结论不是「数据越多越好」,而是:
**只看训练准确率,你永远不知道数据够不够。** 它一直是 1.00,看不出任何问题。
再看第二列。20 条的时候最少的类只有 5 条——**这个数比总数更要命。**
如果一个类 5 条、另一个类 15 条,模型会偏向多的那一边,
因为「全猜多的那个」也能拿到 75% 的准确率。
所以看数据集先看两件事:**总数够不够,最少的类够不够。**
表里七行,第三列几乎不动,第四列一直在动。训练 20 条时 1.0000、2000 条时 0.9885; 测试从 0.8888 一路涨到 0.9925。 20 条那一行最能说明问题:训练 1.0000、测试 0.8888,差 11.12 个百分点。 模型把 20 个点全记住了,记住的是「这 20 个点」而不是「这条边界」。 最好的一档是 0.9925(1000 条),比 20 条时高 10.37 个百分点。 再多到 2000 条反而略降到 0.9900——这就是平台区,剩下的差距是任务本身的噪声,堆数据填不平。 第二列是训练集里最少那个类的条数。 20 条时只有 5 条,这个数比总数更要命:一个类 5 条、另一个 15 条,模型全猜多的那边也能拿 75%。 要说明的是:这里用的是二次特征加逻辑回归,不是神经网络,所以「容量」是固定的。 换成大模型, 小数据下的过拟合会更严重——参数越多,记住 20 个点越容易。 但两列的走势是同一个规律。
30 秒实验
- 把训练集顺序打乱再取前 m 条(现在是取前 m 条),看曲线抖不抖。 小数据下抖动特别大,这就是「换一批数据结果就变」的原因。
- 把测试集从 800 条减到 100 条,看同一档训练量下测试准确率的波动。 测试集太小,报出来的数本身就不稳。
- 故意把训练集里 10% 的标签改错,看测试准确率掉多少。 你会发现掉得比「少给 10% 数据」严重得多——错的比少的更伤。
常见误区
- 「训练准确率高就是模型好」。训练准确率 1.0000 只说明模型记住了训练集,不说明它学到了规律。 要看测试集。
- 「数据越多越好」。到平台区之后堆数据几乎没用,该做的是提质量、查标注、去重。
- 「验证集和测试集可以混用」。测试集用一次就该锁起来。 反复在上面调参,等于把它的信息漏进决策里,报出来的数不再可信。
自测三问(点开对答案)
1. 为什么训练准确率一直 1.00 却不能说明模型好? —— 因为它只反映「模型记不记得住见过的数据」。参数够多的话记住 20 条很容易,但记住不等于学会。 **判断好坏只能看没见过的新数据。** 2. 20 条时训练 1.0000、测试 0.8888,这个现象叫什么? —— 过拟合。模型把训练集的细节(包括噪声)都学了进去,在新数据上泛化不了。 训练与测试的差距就是过拟合的程度。 3. 为什么「最少的那个类有多少条」比总数更要紧? —— 因为模型会偏向样本多的类。 一个类 5 条、另一个 15 条,全猜多的那边就有 75% 准确率,看起来还行,实际完全没用。知道自己需要多少数据了,接下来的问题是:数据从哪来。 下一节讲公开数据集,但重点不是去哪下,是下完怎么体检。
- ☐ (本节完,下一节 3.1.2 获取公开数据集的常用途径)