qinghuan
← 回到知识探索

AI 直觉 / 常见误区

分界线越会绕弯,分类就越好吗?

用一个故意标错的点,看清训练题全对为什么不等于遇到新题也可靠。

展开本文目录
  1. 先动手看看
  2. 为了答对旧题,多画一个小圈
  3. 旧点和新点,分开计数
  4. 三份样本,各做一件事
  5. 去画布里看弯曲,但别只挑好看的图
  6. 记住这三点
  7. 别把例子用过头
  8. 自己试一小步
  9. 查原始资料
  10. 找一份资料继续练
开始前,会这些就够了
  • 能看懂平面坐标和两种类别
  • 认识 Python 函数与比较运算

给平面上的两类点画分界线,绕得足够细,好像总能把每个点包进正确区域。可任务通常不是重新回答已经看过的点,而是判断之后出现的新点。为了迁就一个偶然的标错,弯出来的一小圈可能恰好让附近的新点都判断错误。

下面是人为设计的教学场景,不是真实数据集:本来的规则很简单,x 小于零属于零类,其余属于一类;我们故意把一个训练点的标签写反,再比较两条事先写好的规则。

旧题全对,新题也会更好吗?

这九个点由我们特意安排。真实规则是 x ≥ 0 为一类,但训练点 T5 的记录标签故意写成了零类。

左侧判零类,x = 0 与右侧判一类。

直线分类规则底色表示规则预测。训练点是标有 T 的圆点,验证点是标有 V 的方点;点的颜色对应记录标签。下方表格列出全部坐标、标签和预测。规则判零类规则判一类xy-2-1012T1,训练点,坐标 (-2, -1),记录标签 0,预测 0,符合标签T1T2,训练点,坐标 (-2, 1),记录标签 0,预测 0,符合标签T2T3,训练点,坐标 (2, -1),记录标签 1,预测 1,符合标签T3T4,训练点,坐标 (2, 1),记录标签 1,预测 1,符合标签T4T5,训练点,坐标 (1, 0),记录标签 0,预测 1,不符标签T5V1,验证点,坐标 (1, 0.2),记录标签 1,预测 1,符合标签V1V2,验证点,坐标 (1, -0.2),记录标签 1,预测 1,符合标签V2V3,验证点,坐标 (-1, 0),记录标签 0,预测 0,符合标签V3V4,验证点,坐标 (2, 0),记录标签 1,预测 1,符合标签V4

圆形 T1–T5 是训练点,方形 V1–V4 是验证点;蓝色点的记录标签为 0,棕色为 1。底色是规则预测,点的记录标签可能与底色不符。

训练点符合标签:4 / 5;验证点符合标签:4 / 4。

直线没有迁就写错标签的 T5,却答对了这四个验证点。

两组样本分开计数;坐标可与上图对应
点用途坐标记录标签预测对照
T1训练(-2, -1)00符合
T2训练(-2, 1)00符合
T3训练(2, -1)11符合
T4训练(2, 1)11符合
T5训练(1, 0)01不符
V1验证(1, 0.2)11符合
V2验证(1, -0.2)11符合
V3验证(-1, 0)00符合
V4验证(2, 0)11符合

这里没有运行训练算法,只切换两条事先写好的规则。小量自制样本说明一种失败可能;不能推出复杂边界总不好,也不能用 4 / 4 承诺现实准确率。

为了答对旧题,多画一个小圈

第一条规则只按 x 是否大于等于零分类,相当于一条竖直分界线。第二条保留这条线,又在坐标 (1, 0) 周围挖出半径零点六的小圆,把圆内点都判为零类。这个额外的小圈正好照顾到被标错的训练点。

训练集上,带小圈的规则更好看;但新点若落在小圈内、标签仍遵循原来的规则,就会被它误判。这种过度迎合训练样本中的偶然细节、在新样本上表现较差的情况,叫过拟合。这里知道哪个点标错,是因为数据由我们构造;真实任务不能看见异常就随意改标签。

旧点和新点,分开计数

先看每条规则在训练样本里答对几题,再看预先准备的验证点。验证点没有拿来写小圈的条件。代码只是比较两条手写规则,没有运行训练算法,也没有证明所有复杂模型都会失败。

验证集的用途是帮助比较方案。下面样本很少、又由我们特意安排,只能说明这种失败有可能发生;不能把这里的四分之四理解为真实任务的可靠性保证。

小实验 · python
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;如果你根据它不停挑方案,它在这次练习里就承担了验证的作用。更弯的线有时确实必要,例如内圈与外圈两类点根本不能用一条直线分开。要问的是新样本有没有改善,而不是线条看起来够不够复杂;颜色深浅也不是经过校准的现实正确率。

记住这三点

  • 训练题全对,仍可能是在迁就噪声;要观察未参与拟合的新样本。
  • 验证帮助选方案,测试留作最终评估;反复据此调参会改变它的实际用途。
  • 复杂边界可以有用,是否过拟合要看数据与评估,不能只看图的形状。

别把例子用过头

  • 本例的噪声、规则和验证点均为人为构造,只演示一种可能,不是性能实验。
  • 训练与验证的分数不同不一定全因过拟合,样本少、数据差异等也会造成差距。
  • 增加模型规模或训练次数并非必然让新样本更差,也不能保证一定更好。

自己试一小步

能否造一组让弯曲边界有必要、但仍需要新样本检验的点?

  1. 设计内圈与外圈两类点,先画出几条候选分界。
  2. 在比较之前另留一些位置作为验证点,记录你依据哪一份结果选方案。
  3. 确定规则后再生成一小组最终检查点;若据此改规则,明确说明最终检查需要重做。

做到这些,就算完成

  • 能说明直线为什么难以分开这组数据,而不是只给训练分数。
  • 候选规则、选型依据和最后检查分开记录。
  • 没有从少量自制样本推导真实模型的准确率承诺。

查原始资料

想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。

找一份资料继续练

先选一项,按下面的范围继续学;不必从头读完整门课程。