开始前,会这些就够了
- 能看懂平面坐标和两种类别
- 认识 Python 函数与比较运算
给平面上的两类点画分界线,绕得足够细,好像总能把每个点包进正确区域。可任务通常不是重新回答已经看过的点,而是判断之后出现的新点。为了迁就一个偶然的标错,弯出来的一小圈可能恰好让附近的新点都判断错误。
下面是人为设计的教学场景,不是真实数据集:本来的规则很简单,x 小于零属于零类,其余属于一类;我们故意把一个训练点的标签写反,再比较两条事先写好的规则。
旧题全对,新题也会更好吗?
这九个点由我们特意安排。真实规则是 x ≥ 0 为一类,但训练点 T5 的记录标签故意写成了零类。
左侧判零类,x = 0 与右侧判一类。
圆形 T1–T5 是训练点,方形 V1–V4 是验证点;蓝色点的记录标签为 0,棕色为 1。底色是规则预测,点的记录标签可能与底色不符。
训练点符合标签:4 / 5;验证点符合标签:4 / 4。
直线没有迁就写错标签的 T5,却答对了这四个验证点。
| 点 | 用途 | 坐标 | 记录标签 | 预测 | 对照 |
|---|---|---|---|---|---|
| T1 | 训练 | (-2, -1) | 0 | 0 | 符合 |
| T2 | 训练 | (-2, 1) | 0 | 0 | 符合 |
| T3 | 训练 | (2, -1) | 1 | 1 | 符合 |
| T4 | 训练 | (2, 1) | 1 | 1 | 符合 |
| T5 | 训练 | (1, 0) | 0 | 1 | 不符 |
| V1 | 验证 | (1, 0.2) | 1 | 1 | 符合 |
| V2 | 验证 | (1, -0.2) | 1 | 1 | 符合 |
| V3 | 验证 | (-1, 0) | 0 | 0 | 符合 |
| V4 | 验证 | (2, 0) | 1 | 1 | 符合 |
这里没有运行训练算法,只切换两条事先写好的规则。小量自制样本说明一种失败可能;不能推出复杂边界总不好,也不能用 4 / 4 承诺现实准确率。
为了答对旧题,多画一个小圈
第一条规则只按 x 是否大于等于零分类,相当于一条竖直分界线。第二条保留这条线,又在坐标 (1, 0) 周围挖出半径零点六的小圆,把圆内点都判为零类。这个额外的小圈正好照顾到被标错的训练点。
训练集上,带小圈的规则更好看;但新点若落在小圈内、标签仍遵循原来的规则,就会被它误判。这种过度迎合训练样本中的偶然细节、在新样本上表现较差的情况,叫过拟合。这里知道哪个点标错,是因为数据由我们构造;真实任务不能看见异常就随意改标签。
旧点和新点,分开计数
先看每条规则在训练样本里答对几题,再看预先准备的验证点。验证点没有拿来写小圈的条件。代码只是比较两条手写规则,没有运行训练算法,也没有证明所有复杂模型都会失败。
验证集的用途是帮助比较方案。下面样本很少、又由我们特意安排,只能说明这种失败有可能发生;不能把这里的四分之四理解为真实任务的可靠性保证。
training = [(-2, -1, 0), (-2, 1, 0), (2, -1, 1), (2, 1, 1), (1, 0, 0)]
validation = [(1, 0.2, 1), (1, -0.2, 1), (-1, 0, 0), (2, 0, 1)]
def straight(x, y):
return int(x >= 0)
def with_circle(x, y):
if (x - 1) ** 2 + y ** 2 <= 0.6 ** 2:
return 0
return straight(x, y)
for name, rule in [('straight', straight), ('with circle', with_circle)]:
train_ok = sum(rule(x, y) == label for x, y, label in training)
valid_ok = sum(rule(x, y) == label for x, y, label in validation)
print(f'{name}: training {train_ok}/{len(training)}, validation {valid_ok}/{len(validation)}')怎样运行:保存为 boundary.py,用 Python 3 运行:python boundary.py。只用内置功能,不安装机器学习库。
运行后对照结果
straight: training 4/5, validation 4/4
with circle: training 5/5, validation 2/4三份样本,各做一件事
训练集用来调整模型里的参数;验证集帮助选择网络大小、训练多久等方案;测试集留在方案确定后做最后评估。区别在使用方式,不是文件名叫了 test 就自动公正。如果反复按测试结果换方案,那些样本实际上已经参与了选择。
这也不意味着分成三份就万事大吉。样本是否足够、是否接近将来要处理的情况,同样重要。本文先抓住一个判断习惯:报告旧题分数时,也要交代新题怎么选、有没有被拿来调过方案。
去画布里看弯曲,但别只挑好看的图
打开 Playground,保留当前数据,先记录 Training loss 和 Test loss,再点几次 Step,观察背景分界与两个数值怎样变化。之后只改一个设置,例如增加一层,再重新训练并记录。若重新生成数据或随机初始化不同,也要写下来,不能把两次差异全归给层数。
页面把留出误差叫 Test loss;如果你根据它不停挑方案,它在这次练习里就承担了验证的作用。更弯的线有时确实必要,例如内圈与外圈两类点根本不能用一条直线分开。要问的是新样本有没有改善,而不是线条看起来够不够复杂;颜色深浅也不是经过校准的现实正确率。
记住这三点
- 训练题全对,仍可能是在迁就噪声;要观察未参与拟合的新样本。
- 验证帮助选方案,测试留作最终评估;反复据此调参会改变它的实际用途。
- 复杂边界可以有用,是否过拟合要看数据与评估,不能只看图的形状。
别把例子用过头
- 本例的噪声、规则和验证点均为人为构造,只演示一种可能,不是性能实验。
- 训练与验证的分数不同不一定全因过拟合,样本少、数据差异等也会造成差距。
- 增加模型规模或训练次数并非必然让新样本更差,也不能保证一定更好。
自己试一小步
能否造一组让弯曲边界有必要、但仍需要新样本检验的点?
- 设计内圈与外圈两类点,先画出几条候选分界。
- 在比较之前另留一些位置作为验证点,记录你依据哪一份结果选方案。
- 确定规则后再生成一小组最终检查点;若据此改规则,明确说明最终检查需要重做。
做到这些,就算完成
- 能说明直线为什么难以分开这组数据,而不是只给训练分数。
- 候选规则、选型依据和最后检查分开记录。
- 没有从少量自制样本推导真实模型的准确率承诺。
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- 机器学习速成课:过拟合 (新标签页)↗
支持训练拟合与新样本表现的区别、过拟合和欠拟合的概念。
- 机器学习速成课:划分数据集 (新标签页)↗
支持训练、验证、测试分工,以及反复使用留出数据选择方案的局限。
- Playground:神经网络交互画布 (新标签页)↗
支持单步训练、训练与测试误差显示、预测背景和颜色含义。
找一份资料继续练
先选一项,按下面的范围继续学;不必从头读完整门课程。
MLU Explain:一步步看决策树怎样分类 (新标签页)↗
只读建树到“不要分得太深”这段,沿一个点走过判断规则,再观察迁就训练点会怎样改变分界。
查看学习准备与访问说明 →scikit-learn:同一个人的数据,该分到哪一边 (新标签页)↗
交两份虚构记录的切分清单,分别检查组不重叠和时间顺序。
查看学习准备与访问说明 →