感知机 (Perceptron)
- 提出时间:1957 年
- 提出者:弗兰克·罗森布拉特 (Frank Rosenblatt) —— 美国康奈尔航空实验室的心理学家。
- 灵感原型:生物神经元(基于 1943 年提出的 McCulloch-Pitts 神经元模型)。
- 算法本质:一种二类线性分类器。
- 简单说,就是在一个平面上画一条直线,把东西分成“是”和“否”两类。
- 硬件载体:最初不是纯软件,而是一台名为 Mark I Perceptron 的庞大机器(用电位器和电机模拟权重调节)。
感知机的运行原理非常简单,可以用一个公式概括:加权求和,然后过阈值。
在《深度学习入门》这本书里,作者为了让你适应后续神经网络的写法,将数学公式分成了两个阶段。我们直接看最成熟的那个版本(引入偏置 bbb 后的版本)。
1. 核心数学公式
感知机接收两个输入信号 x1,x2x_1, x_2x1,x2,最终输出一个信号 yyy(0 或 1)。
y={0(b+w1x1+w2x2≤0)1(b+w1x1+w2x2>0)y = \\begin{cases} 0 & (b + w_1x_1 + w_2x_2 \\le 0) \\\\ 1 & (b + w_1x_1 + w_2x_2 > 0) \\end{cases}y={01(b+w1x1+w2x2≤0)(b+w1x1+w2x2>0)
这个公式虽然只有两行,但它包含了三个关键部分,我们逐一拆解:
2. 公式拆解(三个变量的含义)
A. 输入信号 (xxx)
- 符号:x1,x2x_1, x_2x1,x2
- 含义:外界传递给神经元的信息。比如“天气是否晴朗(1/0)”、“是否有空(1/0)”。
B. 权重 (www) —— “控制信号的重要性”
- 符号:w1,w2w_1, w_2w1,w2 (Weight)
- 含义:权重的绝对值越大,对应的输入信号对结果的影响就越大。
- 如果 w1=0.5w_1 = 0.5w1=0.5,w2=2.0w_2 = 2.0w2=2.0,说明 x2x_2x2 比 x1x_1x1 重要得多。
- 物理类比:水管的粗细。权重越大,水管越粗,流过去的水(信号)就越多。
C. 偏置 (bbb) —— “控制兴奋的难易度”
- 符号:bbb (Bias)
- 含义:这是一个常数,它决定了神经元被激活的门槛。
- 注意公式里的 b+⋯>0b + \\dots > 0b+⋯>0。如果 bbb 是一个很大的负数(例如 −100-100−100),那么 w1x1+w2x2w_1x_1 + w_2x_2w1x1+w2x2 必须非常大才能把结果拉到 0 以上。这就叫“很难激活”。
- 如果 bbb 是正数,哪怕没有输入,神经元也可能处于激活状态。
- 书中的变化:书里最开始用的是 θ\\thetaθ (阈值),公式是 w1x1+w2x2>θw_1x_1 + w_2x_2 > \\thetaw1x1+w2x2>θ。后来把 θ\\thetaθ 移到左边变成了 −θ- \\theta−θ,也就是现在的 bbb。这是为了方便后续用矩阵计算。
3. 向量形式(NumPy 写法)
既然你已经学了 NumPy,感知机的公式其实可以写得更优雅。
如果我们把输入和权重看作向量:
- 输入向量 x=[x1,x2]\\mathbf{x} = [x_1, x_2]x=[x1,x2]
- 权重向量 w=[w1,w2]\\mathbf{w} = [w_1, w_2]w=[w1,w2]
那么公式就变成了点积 (Dot Product) 加上偏置:
A=w⋅x+bA = \\mathbf{w} \\cdot \\mathbf{x} + bA=w⋅x+b
y={0(A≤0)1(A>0)y = \\begin{cases} 0 & (A \\le 0) \\\\ 1 & (A > 0) \\end{cases}y={01(A≤0)(A>0)
这一步非常关键!因为它把物理上的“信号传输”变成了数学上的“矩阵运算”。
总结
感知机就是在做一件事:
计算 XXX 和 WWW 的加权和,加上偏置 bbb,如果结果大于 0,就输出 1;否则输出 0。
这就是所谓的“线性分类器”的数学本质。你现在能理解为什么偏置 bbb 这么重要了吗?

问得好!这个 “1” (偏置输入) 其实是深度学习里一个非常经典的**“数学障眼法”**。
简单来说:为了让计算更统一,我们虚构了一个永远是 1 的输入节点。
我们可以分两步来拆解这个设计:
1. 为什么要强行加个“1”?
你看原本的公式是这样的:
y=(w1x1+w2x2)+by = (w_1x_1 + w_2x_2) + by=(w1x1+w2x2)+b
这里有个尴尬的地方:
- w1w_1w1 和 w2w_2w2 都有对应的 xxx 相乘。
- bbb 是孤零零的一个常数,没有 xxx 和它配对。
这在数学写法上不够“整齐”。于是,数学家们想了个办法:给 bbb 也配一个伴侣!
因为 b×1=bb \\times 1 = bb×1=b,所以公式可以改写成:
y=w1x1+w2x2+b⋅1y = w_1x_1 + w_2x_2 + \\mathbf{b \\cdot 1}y=w1x1+w2x2+b⋅1
2. 图解的变化
为了配合这个新公式,我们在画图时:
- 把 偏置 bbb 看作是一个特殊的 权重 (Weight)。
- 把这个 “1” 看作是一个特殊的 输入 (Input)。
这样一来,图里的每一个箭头就都变成了 “输入 ×\\times× 权重” 的形式。
- 普通输入:x1,x2x_1, x_2x1,x2 (是变化的)
- 偏置输入:111 (永远固定是 1)
- 偏置权重:bbb (这也是我们要学习的参数)
💡 一个生活中的类比
想象你在搞一次考试:
- 题目得分:x1x_1x1 是答对的题数,w1w_1w1 是每题的分数。这是 w1x1w_1x_1w1x1。
- 卷面起步分:老师规定,只要名字写对了,就先送你 10 分。
这个 10 分 (bbb) 怎么算进总分里?
你可以把它想象成:有一道特殊的“送分题”(输入永远是 1),但这道题的分值是 10 分(权重是 bbb)。
⚠️ 代码里的区别
在《深度学习入门》这本书的代码实现(NumPy)里,你会发现作者为了让你看懂,并没有刻意去构造这个“1”的数组,而是直接写成了:
Python
import numpy as np
x = np.array([0, 1]) # 输入
w = np.array([0.5, 0.5]) # 权重
b = -0.7 # 偏置
# 作者直接把 b 单独加上去了,这更符合直觉
y = np.sum(w*x) + b
但在更高级的框架(比如 TensorFlow 或 PyTorch)或者书后面讲到矩阵运算时,这个“虚构的 1”经常会被整合进矩阵里,让所有运算都变成单纯的矩阵乘法(Dot Product),以此来提升计算速度。
所以,看到那个“1”,你就把它当成是专门用来承载 bbb 的一个“虚拟插座”就好了。
与门 (AND Gate) 是感知机能实现的最简单的逻辑电路之一。在《深度学习入门》第二章,这也是你遇到的第一个“用参数控制逻辑”的例子。
它的逻辑非常直观:只有当两个输入 x1x_1x1 和 x2x_2x2 都是 1 时,才会输出 1;否则输出 0。
1. 它的“真值表” (Truth Table)
这是我们在设计感知机参数时的“目标清单”:
| 0 | 0 | 0 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 1 | 1 |
2. 如何用感知机实现?
我们需要找到一组 权重 (w1,w2w_1, w_2w1,w2) 和 偏置 (bbb),代入感知机公式:
y={0(b+w1x1+w2x2≤0)1(b+w1x1+w2x2>0)y = \\begin{cases} 0 & (b + w_1x_1 + w_2x_2 \\le 0) \\\\ 1 & (b + w_1x_1 + w_2x_2 > 0) \\end{cases}y={01(b+w1x1+w2x2≤0)(b+w1x1+w2x2>0)
让它满足上面的真值表。
思考过程(解谜时间):
- 也就是 w1+w2+b>0w_1 + w_2 + b > 0w1+w2+b>0。
- 也就是 w1+b≤0w_1 + b \\le 0w1+b≤0 且 w2+b≤0w_2 + b \\le 0w2+b≤0。
满足条件的解(这组解不唯一):
书中给出的经典参数是:
- w1=0.5w_1 = 0.5w1=0.5
- w2=0.5w_2 = 0.5w2=0.5
- b=−0.7b = -0.7b=−0.7
我们来验算一下:
- (0, 0): 0+0−0.7=−0.70 + 0 – 0.7 = -0.70+0−0.7=−0.7 (≤0\\le 0≤0) →\\rightarrow→ 输出 0 ✅
- (1, 0): 0.5+0−0.7=−0.20.5 + 0 – 0.7 = -0.20.5+0−0.7=−0.2 (≤0\\le 0≤0) →\\rightarrow→ 输出 0 ✅
- (0, 1): 0+0.5−0.7=−0.20 + 0.5 – 0.7 = -0.20+0.5−0.7=−0.2 (≤0\\le 0≤0) →\\rightarrow→ 输出 0 ✅
- (1, 1): 0.5+0.5−0.7=0.30.5 + 0.5 – 0.7 = 0.30.5+0.5−0.7=0.3 (>0> 0>0) →\\rightarrow→ 输出 1 ✅
3. 几何意义(画条线)
如果我们在平面坐标系上画出来,与门其实就是画一条直线,把 (1,1)(1, 1)(1,1) 这个点单独圈出来,把它和另外三个点 (0,0),(0,1),(1,0)(0,0), (0,1), (1,0)(0,0),(0,1),(1,0) 分开。
这条直线就是 0.5×1+0.5×2−0.7=00.5x_1 + 0.5x_2 – 0.7 = 00.5x1+0.5x2−0.7=0。
与非门 (NAND Gate) 的全称是 Not AND。
顾名思义,它就是与门 (AND) 的“唱反调”版本。它的输出结果和与门完全相反。
1. 它的逻辑:专门“拆散”一对
- 与门:只有两人都同意 (1,1)(1, 1)(1,1),结果才通过 (1)(1)(1)。
- 与非门:只有两人都同意 (1,1)(1, 1)(1,1),结果才不通过 (0)(0)(0);其他情况统统通过 (1)(1)(1)。
看看它的真值表:
| 0 | 0 | 1 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 0 |
2. 参数怎么变?(甚至不需要动脑算)
你还记得刚才与门的参数吗?
- w1=0.5w_1 = 0.5w1=0.5
- w2=0.5w_2 = 0.5w2=0.5
- b=−0.7b = -0.7b=−0.7
要实现与非门,最简单的方法就是把所有符号反过来(乘以 −1-1−1):
- w1=−0.5w_1 = -0.5w1=−0.5
- w2=−0.5w_2 = -0.5w2=−0.5
- b=0.7b = 0.7b=0.7
我们来快速验算一下那个“特殊情况” (1,1)(1, 1)(1,1):
(−0.5×1)+(−0.5×1)+0.7=−0.3(-0.5 \\times 1) + (-0.5 \\times 1) + 0.7 = -0.3(−0.5×1)+(−0.5×1)+0.7=−0.3
结果是 −0.3-0.3−0.3(≤0\\le 0≤0),所以输出 0。没毛病!
3. 深度学习的一个重要启示
在《深度学习入门》这本书里,作者特意把 AND、NAND、OR 放在一起讲,是为了告诉你一个深刻的道理:
感知机的“构造”是完全一样的。
你看,无论是 AND 还是 NAND,模型的形状(代码逻辑)没有任何改变。改变的只是 参数(权重和偏置)。
- 这就好比同一个收音机,只是旋钮(参数)拧到了不同的位置,就能收到不同的频道(功能)。
- 深度学习的训练过程,其实就是在自动寻找这些旋钮的最佳位置。
或门 (OR Gate) 是感知机三兄弟里最“随和”、“宽容”的一个。
它的逻辑很简单:只要有一点信号(输入里有一个 1),我就让你过(输出 1)。
只有在彻底没信号(两个输入都是 0)的时候,它才会拒绝(输出 0)。
1. 它的“真值表”
看看它有多容易被激活:
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 1 | 1 |
2. 怎么调参数?(找感觉)
我们再回头看看公式:
y={0(b+w1x1+w2x2≤0)1(b+w1x1+w2x2>0)y = \\begin{cases} 0 & (b + w_1x_1 + w_2x_2 \\le 0) \\\\ 1 & (b + w_1x_1 + w_2x_2 > 0) \\end{cases}y={01(b+w1x1+w2x2≤0)(b+w1x1+w2x2>0)
想象一下:
- 权重 (www) 还是保持 0.50.50.5 不变(只要有输入,就有贡献)。
- 偏置 (bbb) 应该怎么变?
- 在 与门 (AND) 里,我们要很严格,只有两份 0.50.50.5 加起来才能抵消 bbb(b=−0.7b=-0.7b=−0.7)。
- 在 或门 (OR) 里,我们要很宽松,只要有一份 0.50.50.5,就应该能抵消 bbb,让结果大于 0。
所以,bbb 的负值必须变小(门槛变低)。
比如把 bbb 设为 −0.2-0.2−0.2。
验算一下:
- (1, 0): 0.5+0−0.2=0.30.5 + 0 – 0.2 = 0.30.5+0−0.2=0.3 (>0> 0>0) →\\rightarrow→ 输出 1 ✅
- (0, 0): 0+0−0.2=−0.20 + 0 – 0.2 = -0.20+0−0.2=−0.2 (≤0\\le 0≤0) →\\rightarrow→ 输出 0 ✅
3. 暴风雨前的宁静
到现在为止,我们学了 AND、NAND、OR。
你发现没有?它们都有一个共同点:
都能用一条直线把结果分开。
在平面图上,无论是切掉 (0,0)(0,0)(0,0),还是切掉 (1,1)(1,1)(1,1),只要画一条直线就能把“输出 0 的点”和“输出 1 的点”完美分割开。这在数学上叫 “线性可分”。
这绝对是《深度学习入门》这本书里的第一个高潮,也是人工智能历史上著名的“至暗时刻”。
我们之前学的 AND、NAND、OR 门,仿佛无所不能。但到了 异或门 (XOR Gate) 这里,单层感知机就像撞上了一堵墙。
让我们来看看为什么这堵墙这么硬。
1. 什么是异或 (XOR)?
XOR 全称是 Exclusive OR(互斥或)。
它的逻辑是:只有当两个输入不同的时候,才输出 1。 如果两个输入一样(都是 0 或者都是 1),它就拒绝(输出 0)。
真值表 (Truth Table):
| 0 | 0 | 0 | 相同,拒绝 |
| 1 | 0 | 1 | 不同,通过 |
| 0 | 1 | 1 | 不同,通过 |
| 1 | 1 | 0 | 相同,拒绝 |
2. 为什么感知机搞不定它?
为了理解这个问题,我们必须把这四个点画在坐标轴上。
- 圆圈 (○) 代表输出 0 的点:(0,0)(0, 0)(0,0) 和 (1,1)(1, 1)(1,1)。
- 三角 (△) 代表输出 1 的点:(1,0)(1, 0)(1,0) 和 (0,1)(0, 1)(0,1)。
核心冲突:直线 vs. 曲线
感知机的数学公式 y=w1x1+w2x2+by = w_1x_1 + w_2x_2 + by=w1x1+w2x2+b 在几何上代表什么?
它代表一条 直线。
- 不管你怎么调整 www(斜率)和 bbb(截距),它永远是一条直挺挺的线。
请你试想一下:
你能画一条直线,把图中的两个 ○ 和两个 △ 完美分开吗?
- 如果你把直线画在 (0,0)(0,0)(0,0) 和 (1,0)(1,0)(1,0) 之间,那 (1,1)(1,1)(1,1) 这个 ○ 就被错分到 △ 那边去了。
- 不管你怎么旋转这条线,总有一个点会“跑错阵营”。
这就是感知机的致命局限性:它只能解决线性可分的问题。 而 XOR 是一个典型的 非线性 问题。
3. 历史上的“AI 寒冬”
这件事在历史上非常有名。
1969 年,AI 界的泰斗 马文·明斯基 (Marvin Minsky) 和 西摩·派普特 (Seymour Papert) 写了一本书叫《感知机》。他们在书中从数学上严格证明了:单层感知机甚至连简单的 XOR 逻辑都无法实现。
这一结论给当时热火朝天的神经网络研究泼了一盆冰水。大家觉得:“搞了半天,这东西连个简单的逻辑电路都比不上,还能指望它像人脑一样思考?”
于是,神经网络的研究进入了长达十几年的冰河期 (AI Winter)。
4. 怎么破局?(多层感知机)
虽然一条直线分不开,但如果我们能画两条直线呢?或者画一条曲线呢?
这就是《深度学习入门》接下来要讲的精彩部分:叠加层数。
虽然单层感知机搞不定 XOR,但我们可以组合已有的门来解决它。
逻辑电路里有一个著名的公式:
XOR=(NAND)+(OR)+(AND)\\text{XOR} = (\\text{NAND}) + (\\text{OR}) + (\\text{AND})XOR=(NAND)+(OR)+(AND)
意思是:我们可以把 NAND、OR、AND 这三个简单的感知机像搭积木一样叠起来。
神奇的事情发生了:通过多层结构的组合,直线变成了曲线(或者说多条直线的组合),原本分不开的区域现在可以分开了!
为了让你看着更踏实,我把这个逻辑像剥洋葱一样彻底拆解给你看,证明它是如何“天衣无缝”的。
1. 拆解证明:为什么这三个门拼起来就是 XOR?
我们用真值表来一步步推导。请盯着中间那两列(也就是第一层的输出 s1s_1s1 和 s2s_2s2):
公式逻辑:y=AND(s1,s2)y = \\text{AND}(s_1, s_2)y=AND(s1,s2),其中 s1=NANDs_1 = \\text{NAND}s1=NAND,s2=ORs_2 = \\text{OR}s2=OR。
| 0 | 0 | 1 | 0 | 0 | ✅ (相同为0) |
| 1 | 0 | 1 | 1 | 1 | ✅ (不同为1) |
| 0 | 1 | 1 | 1 | 1 | ✅ (不同为1) |
| 1 | 1 | 0 | 1 | 0 | ✅ (相同为0) |
2. 直观理解:它们在“吵架”还是“合作”?
你可以把这三个门想象成三个安检员,它们在筛选符合“异或(XOR)”条件的人(条件是:必须一男一女,不能两个男也不能两个女)。
- OR 门(安检员 A)说:“你们两个至少要有一个人是男的(是 1),否则别想过!”
- 结果:把 (0,0)(0, 0)(0,0) 拦住了。
- NAND 门(安检员 B)说:“你们两个不能同时都是男的(都是 1),否则别想过!”
- 结果:把 (1,1)(1, 1)(1,1) 拦住了。
- AND 门(最终 Boss)说:“安检员 A 和 B 都放行的人,我才放行。”
- 最终结果:只有 (1,0)(1, 0)(1,0) 和 (0,1)(0, 1)(0,1) 这种“一男一女”的情况,才能同时通过 A 和 B 的检查,最终被 Boss 放行。
这就是**“组合”**的力量。
3. 这在书中的意义
你在图片里看到的这段文字,核心想表达的是:
单层感知机(一个门)是线性的,像一把直尺,解决不了 XOR 问题。
多层感知机(把门叠起来)是非线性的,像一把剪刀,能把需要的区域剪出来。
你现在学的这个结构:
输入 -> [NAND, OR] -> [AND] -> 输出
正是最简单的 2 层神经网络。
所以,结论是:完全正确,尽管放心大胆地往下学! 第三章会告诉你,这种“搭积木”的思想是如何演变成现代能识别猫狗、能写代码的超级 AI 的。
总结
- 局限性:单层感知机只能画直线(线性分类),无法处理非线性分布的数据(如 XOR)。
- 解决方法:多层感知机 (Multi-layer Perceptron, MLP)。
- 这一步跨越非常重要,因为它标志着我们从简单的“逻辑门”迈向了真正的“神经网络”。
- 现在的深度学习,其实就是叠加了无数层的感知机。
实现代码:
import numpy as np
# 1. 定义与门 (AND)
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5]) # 权重
b = –0.7 # 偏置
# 核心公式:w*x + b
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
# 2. 定义与非门 (NAND)
def NAND(x1, x2):
x = np.array([x1, x2])
w = np.array([–0.5, –0.5]) # 权重变负(与AND相反)
b = 0.7 # 偏置变正
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
# 3. 定义或门 (OR)
def OR(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5]) # 权重
b = –0.2 # 偏置(门槛降低)
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
# ==========================================
# 测试部分 (验证真值表)
# ==========================================
print("— AND 门测试 —")
print(f"AND(0, 0) -> {AND(0, 0)}")
print(f"AND(1, 0) -> {AND(1, 0)}")
print(f"AND(0, 1) -> {AND(0, 1)}")
print(f"AND(1, 1) -> {AND(1, 1)}")
print("\\n— NAND 门测试 —")
print(f"NAND(0, 0) -> {NAND(0, 0)}")
print(f"NAND(1, 0) -> {NAND(1, 0)}")
print(f"NAND(0, 1) -> {NAND(0, 1)}")
print(f"NAND(1, 1) -> {NAND(1, 1)}")
print("\\n— OR 门测试 —")
print(f"OR(0, 0) -> {OR(0, 0)}")
print(f"OR(1, 0) -> {OR(1, 0)}")
print(f"OR(0, 1) -> {OR(0, 1)}")
print(f"OR(1, 1) -> {OR(1, 1)}")
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
print("\\n— XOR 门测试 —")
print(f"XOR(0, 0) -> {XOR(0, 0)}") # 0
print(f"XOR(1, 0) -> {XOR(1, 0)}") # 1
print(f"XOR(0, 1) -> {XOR(0, 1)}") # 1
print(f"XOR(1, 1) -> {XOR(1, 1)}") # 0
(1, 0) -> {NAND(1, 0)}“)
print(f"NAND(0, 1) -> {NAND(0, 1)}”)
print(f"NAND(1, 1) -> {NAND(1, 1)}")
print(“\\n— OR 门测试 —”)
print(f"OR(0, 0) -> {OR(0, 0)}“)
print(f"OR(1, 0) -> {OR(1, 0)}”)
print(f"OR(0, 1) -> {OR(0, 1)}“)
print(f"OR(1, 1) -> {OR(1, 1)}”)
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
print(“\\n— XOR 门测试 —”)
print(f"XOR(0, 0) -> {XOR(0, 0)}“) # 0
print(f"XOR(1, 0) -> {XOR(1, 0)}”) # 1
print(f"XOR(0, 1) -> {XOR(0, 1)}“) # 1
print(f"XOR(1, 1) -> {XOR(1, 1)}”) # 0



