跳到主要内容

神经网络与 KNN — 两个「异类」

这一章把两个「画风不同」的算法放在一起讲: 神经网络(深度学习的地基, 本章只拆第一块砖)和 KNN(什么都不学的「懒惰」算法)。 它们看似无关,其实回答同一个问题:模型到底该把力气花在训练时,还是预测时。

1. 神经网络:秘密就是「夹一层」

神经网络一直以来被认为是模仿生物体的神经系统设计出来的——名字里的「神经」由此而来;剥开这层包装,它的机制非常朴素1:在输入数据和输出结果之间,插入叫做中间层的层,从而能学习复杂的决策边界2

三个部件各司其职:左端的输入层就是输入数据本身;右端的输出层给出分类结果的概率;夹在中间的就是中间层3

主走查(上半场):从 64 个像素到 10 个概率

原书拿手写数字数据集 MNIST 的一个变体做示例:图片是 8×8 的灰度图像(每个像素只记深浅)4。网络怎么接它:

输入层:8×8=64 个像素值拉平成一条 64 维的数 ← 图像变成向量

中间层:16 个神经元(16 是人为定的超参数)

输出层:10 个数 = 这张图分别是数字 0~9 的概率

谁的概率最大,判几。原书实测正确率 95% 左右(0.9519)。

图说:数字 64、16、10 均取自原书;正确率 0.9519
是原书代码的运行输出。

三个数字里最值得记住的是 64→16:图像在输入的第一步就被拉平了,「8×8 的方格」这个二维结构没有直接进网络——这个细节第 12 章讲图像时还会回来收账。

一个神经元 = 一个逻辑回归

最小零件叫简单感知机:对特征值加权求和,过一个非线性函数(激活函数:对加权和做最后一道加工的函数),输出概率5。代个数看看它内部发生了什么(系数为演示编的):

y = f(w0 + w1x1 + w2x2)
输入 x1=1, x2=2;权重 w1=0.5, w2=−1;偏置 w0=0.3
→ 加权和:0.3 + 0.5×1 + (−1)×2 = −1.2
→ 过激活函数 f:Sigmoid(−1.2) ≈ 0.23

图说:输入与系数是编的;Sigmoid 的算法来自第 03 章。
一个感知机的结构与逻辑回归一模一样。

原书挑明:激活函数(对加权和做非线性变换的函数;对加权后的特征值之和计算输出的那个 f)取 Sigmoid 时,简单感知机与逻辑回归是等价的6。所以「神经网络」的第一块砖,就是你已经认识的东西。

夹一层,直线就变成了「区域」

单层感知机和逻辑回归一样,搞不定线性不可分的数据(两类点没法用一条直线分开的排布)7。神经网络的做法原书讲得极其具体:

设置一个区分「右上角的点和其他点」的层,再设置一个区分「左下角的点和其他点」的层,最后综合这两个结果做决定——数据是否落在被两条直线夹住的地方,就成了分类依据8

│ ╱ 直线1:右上 vs 其余
○○ │ ╱ ×××
───┼────────
│╲ ×××
│ ╲ 直线2:左下 vs 其余

两层各自报「在/不在」,输出层一综合:
「两条线都说不归我管的中间地带」= 一块斜的方形区域。
直线围出了区域——单条直线做不到的事。

图说:布局为示意;「两条直线夹住」的机制与原书一致。

这些夹在输入和输出之间的层,也叫隐藏层(数据在里头被中间加工,外界看不见)9。加层数、加宽层,就能拼出更复杂的边界——「深度」学习里那个「深度」,指的就是层数深。本章只立起这一块砖:几十层怎么训练、为什么能训练,是原书明确不展开的内容(它属于「深度学习」,不在这本入门书的射程内)。

早停法:另一种防过拟合的姿势

网络一大就容易过拟合。原书给了一个与第 02 章正则化气质完全不同的解法:Early Stopping(早停法)——再从训练数据里划一部分当评估数据,训练中盯着评估数据的损失,一旦它开始恶化(出现过拟合趋势),立刻停止训练10

正则化是「改变学什么」,早停是「学一半就喊停」。两者可以同时用,原书在防过拟合清单里把它们并列11

2. KNN:把「不学习」推到极致

KNN(K 近邻)是「一种与众不同的机器学习算法:它只是机械地记住所有的数据」12。原书这半句调侃精确命中了它的本质:训练阶段不做任何计算,把计算全部推迟到预测阶段13

预测一条新数据时只有三步14:

① 算距离:新数据与每一条训练数据算距离
② 取近邻:挑出最近的 k 条
③ 投票:k 条里哪个标签多,判哪个

主走查(下半场):k=3 的现场表决

设新来一个未知点,拿它的 3 个最近邻(离它最近的 3 条训练数据)投票(k=3,取自原书图 2-45 的设定;坐标为演示编的)15:

未知点 (?, ?)
↓ 算出与全部训练点的距离,最近 3 名:
×(距离 0.4) ○(距离 0.7) ×(距离 0.9)
↓ 开票:× 得 2 票,○ 得 1 票
判决:×

没有参数、没有训练、没有损失函数——训练数据本身就是「模型」。k 是超参数;二元分类时 k 通常取奇数,免得票数打平16

k 就是旋钮:松紧之间

k 拧的是决策边界的「松紧」。原书拿同一份数据换了三个 k 值17:

k边界长相诊断
1出现一座座「飞地」——单个点把自己周围圈成孤岛过拟合
5边界平滑,飞地消失较好
30大片区域里混进异类点,「边界过于宽松导致错误判断」欠拟合(学得太粗,连训练数据都照顾不好)

和第 02 章的 α、第 04 章的 γ 一样,k 也要靠验证数据调出来。

两个硬伤:大数据慢,高维失灵

原书给 KNN 划了两条明确的能力边界18:

  1. 数据量大,预测就慢:分类时要在全部训练数据里做近邻搜索(找最近的点),还得把所有数据存在内存里。树结构能加速搜索,但结论不变——不适合大规模数据;
  2. 维数一高,近邻就失灵:KNN 起作用的前提是「训练数据足够多时,未知数据附近总有训练点」,原书称之为渐近假设;维数一高,空间膨胀得比数据快,「附近」再也没有邻居——高维的音频、图像数据得换方法19

第二条在今天仍有回响:所有靠「找最像的条目」吃饭的方法(向量检索——在海量库里找最像的那条;推荐系统的近邻召回),都欠这份几何账(补充:不在书里,来自通用知识)。

3. 两个异类的对照组:力气花在哪一刻

把两个算法并排放,看见的是同一枚硬币的两面:

神经网络KNN
训练时重:反复更新权重零:原样背下数据
预测时轻:一遍前向计算重:与全部数据比距离
模型大小固定(那些权重)随数据量线性膨胀
新数据来了用学到的规律直接判每次都重新比一遍

这个权衡没有免费午餐,但有个大方向:训练贵一次、预测便宜亿万次的方案,更适合「预测次数远多于训练次数」的真实业务——神经网络之所以吞下了高昂的训练成本,正是因为它把成本预付了(补充:不在书里,来自通用知识)。

4. 作者的判断与证据

说法性质依据
Sigmoid 激活时感知机与逻辑回归等价数学事实,书内明说书内陈述6
两条直线夹出区域可分线性不可分数据书内给出构造性方案(分右上/左下两层)书内讲解8
中间层 16 维、正确率 95%书内代码运行结果输出 0.951920
k=1 飞地、k=30 混淆书内图示对照,没给数字证据图示17
渐近假设在维数多时不成立作者陈述,未给证明(「维数灾难」的严格论证超出本书)书内陈述19
神经网络模仿生物作者注明这是「一直以来人们都认为」——即类比说法,不是机制承重墙书内措辞1

5. 边界与局限

  • 本章的神经网络停在「一个隐藏层 + 手写数字」:多层怎么训、误差怎么层层退回去调参数、图像专用的局部结构怎么保,原书一概未讲——本书定位如此,不算缺陷,但读者要清楚天花板在哪。
  • 原书没有提 KNN 的距离度量选择(欧氏距离之外的选项)与特征尺度问题:两个特征一个 01、一个 010000,距离会被大数值特征垄断,必须先做尺度统一(补充:不在书里,来自通用知识)。
  • Early Stopping 与第 11 章的验证数据是同一件事的两种用法:一个用来停训练,一个用来选模型。
  • 版本提示:示例用 MLPClassifier(hidden_layer_sizes=(16,))KNeighborsClassifier()(默认 k=5),输出分别为 0.9519 与 0.93332021

6. 可带走的

  1. 神经网络 = 输入层 + 中间层(隐藏层)+ 输出层;秘密就是「夹一层」;
  2. 一个感知机 = 一个逻辑回归(取 Sigmoid 激活时严格等价);
  3. 两条直线夹出区域,线性不可分数据就分开了——「深度」的全部起点;
  4. 隐藏层的宽度是超参数:宽了能学复杂边界,也容易过拟合;
  5. 早停法:盯评估数据的损失,恶化就停——防过拟合的第二种姿势;
  6. KNN 什么都不学:训练零计算,预测时算距离、取 k 个近邻、投票;
  7. k 拧边界的松紧:1 飞地、5 平滑、30 混淆;二元分类取奇数防平票;
  8. KNN 两大硬伤:大数据查询慢,高维近邻失灵(渐近假设破产);
  9. 训练贵/预测贵的权衡:神经网络预付成本,换每次预测便宜——业务形态决定选谁。

7. 原文地图

主题原书章原文位置
模仿生物的来历2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:4(搜「模仿生物体的神经网络」)
夹中间层、学复杂边界2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:11(搜「能够学习复杂的决策边界」)
输入层/输出层2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:18(搜「左端的层叫作输入层」) · text/13-ch02-08-2-8-8.txt:19(搜「右端的层叫作输出层」)
MNIST 8×8 灰度2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:26(搜「8 × 8 的灰度图像」)
64 维输入、16 维中间层2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:41(搜「64 维向量」) · text/13-ch02-08-2-8-8.txt:43(搜「中间层的维度是超参数」) · text/13-ch02-08-2-8-8.txt:44(搜「中间层为 16 维」)
输出 10 个概率2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:47(搜「10 个数字的概率」)
感知机、权重偏置激活函数2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:62(搜「进行识别的模型」) · text/13-ch02-08-2-8-8.txt:67(搜「称为权重,将常数项」) · text/13-ch02-08-2-8-8.txt:68(搜「叫作激活函数」)
与逻辑回归等价2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:87(搜「和逻辑回归是等价的」)
线性不可分、两条线夹2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:91(搜「无法进行正确分类」) · text/13-ch02-08-2-8-8.txt:101(搜「叫作中间层或隐藏层」) · text/13-ch02-08-2-8-8.txt:102(搜「被两条直线夹住」)
Early Stopping2.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:150(搜「进入过拟合状态前停止训练」) · text/13-ch02-08-2-8-8.txt:156(搜「就停止训练,结束学习」)
accuracy 0.95192.8 算法8:神经网络text/13-ch02-08-2-8-8.txt:142(搜「0.95185」)
KNN 机械记住所有数据2.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:2(搜「机械地记住」)
训练不算、预测才算2.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:10(搜「训练阶段不进行任何计算」)
三步与 k=3 表决2.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:33(搜「进行多数表决,将结果作为分类结果」) · text/14-ch02-09-2-9-9-knn.txt:35(搜「最近邻点 k 的数量为 3」)
k 取奇数2.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:46(搜「取 k 为奇数」)
k=1/5/30 对比2.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:74(搜「像飞地一样的决策边界」) · text/14-ch02-09-2-9-9-knn.txt:76(搜「边界过于宽松导致的错误判断」)
大数据慢、近邻搜索2.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:88(搜「分类将变慢」) · text/14-ch02-09-2-9-9-knn.txt:91(搜「不适合处理大规模的训练数据」)
渐近假设2.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:93(搜「叫作渐近假设」)
make_moons 0.93332.9 算法9:KNNtext/14-ch02-09-2-9-9-knn.txt:66(搜「0.93333」)

Footnotes

  1. 出处:「2.8 算法8:神经网络」第 4 段(text/13-ch02-08-2-8-8.txt:4,搜「模仿生物体的神经网络」)。 2

  2. 出处:「2.8 算法8:神经网络」第 11 段(text/13-ch02-08-2-8-8.txt:11,搜「能够学习复杂的决策边界」)。

  3. 出处:「2.8 算法8:神经网络」第 18 段(text/13-ch02-08-2-8-8.txt:18,搜「左端的层叫作输入层」)与第 19 段(text/13-ch02-08-2-8-8.txt:19,搜「右端的层叫作输出层」)。

  4. 出处:「2.8 算法8:神经网络」第 25 段(text/13-ch02-08-2-8-8.txt:25,搜「MNIST 包含从 0 到 9」)与第 26 段(text/13-ch02-08-2-8-8.txt:26,搜「8 × 8 的灰度图像」)。示例代码实际用 scikit-learn 内置的 load_digits,即 MNIST 的 8×8 缩小版。

  5. 出处:「2.8 算法8:神经网络」第 62 段(text/13-ch02-08-2-8-8.txt:62,搜「进行识别的模型」);权重的叫法与激活函数的定义在第 67~68 段(text/13-ch02-08-2-8-8.txt:68,搜「叫作激活函数」)。

  6. 出处:「2.8 算法8:神经网络」第 87 段(text/13-ch02-08-2-8-8.txt:87,搜「和逻辑回归是等价的」)。 2

  7. 出处:「2.8 算法8:神经网络」第 90~91 段(text/13-ch02-08-2-8-8.txt:91,搜「无法进行正确分类」)。

  8. 出处:「2.8 算法8:神经网络」第 100~103 段(text/13-ch02-08-2-8-8.txt:102,搜「被两条直线夹住」)。 2

  9. 出处:「2.8 算法8:神经网络」第 101 段(text/13-ch02-08-2-8-8.txt:101,搜「叫作中间层或隐藏层」)。

  10. 出处:「2.8 算法8:神经网络」第 150 段(text/13-ch02-08-2-8-8.txt:150,搜「进入过拟合状态前停止训练」)与第 152~154 段(text/13-ch02-08-2-8-8.txt:156,搜「就停止训练,结束学习」)。

  11. 出处:「4.1 评估方法」专栏第 689~698 段(text/23-ch04-01-4-1.txt:697,搜「Early Stopping」)。清单并列:增加训练数据、减少特征值、正则化、Early Stopping、集成学习。

  12. 出处:「2.9 算法9:KNN」第 2 段(text/14-ch02-09-2-9-9-knn.txt:2,搜「机械地记住」)。

  13. 出处:「2.9 算法9:KNN」第 10 段(text/14-ch02-09-2-9-9-knn.txt:10,搜「训练阶段不进行任何计算」)。

  14. 出处:「2.9 算法9:KNN」第 30~32 段(text/14-ch02-09-2-9-9-knn.txt:33,搜「进行多数表决,将结果作为分类结果」)。

  15. 出处:「2.9 算法9:KNN」第 35 段(text/14-ch02-09-2-9-9-knn.txt:35,搜「最近邻点 k 的数量为 3」);原书图 2-45 的判决是「×2,○1,所以多数表决的预测结果为 ×」。

  16. 出处:「2.9 算法9:KNN」第 46 段(text/14-ch02-09-2-9-9-knn.txt:46,搜「取 k 为奇数」)。

  17. 出处:「2.9 算法9:KNN」第 73~76 段(text/14-ch02-09-2-9-9-knn.txt:74,搜「像飞地一样的决策边界」;text/14-ch02-09-2-9-9-knn.txt:76,搜「边界过于宽松导致的错误判断」)。 2

  18. 出处:「2.9 算法9:KNN」第 88~91 段(text/14-ch02-09-2-9-9-knn.txt:88,搜「分类将变慢」;text/14-ch02-09-2-9-9-knn.txt:91,搜「不适合处理大规模的训练数据」)。

  19. 出处:「2.9 算法9:KNN」第 92~94 段(text/14-ch02-09-2-9-9-knn.txt:93,搜「叫作渐近假设」)。 2

  20. 出处:「2.8 算法8:神经网络」第 142 段(text/13-ch02-08-2-8-8.txt:142,搜「0.95185」);「结果的正确率都在 95% 左右」在第 123 段(搜「正确率都在 95%」)。 2

  21. 出处:「2.9 算法9:KNN」第 66 段(text/14-ch02-09-2-9-9-knn.txt:66,搜「0.93333」);默认 k=5 在第 50 段(搜「默认值 5」)。