2. 感知机
感知机(perceptron)是由美国学者 Frank Rosenblatt 在 1957 年提出的。它作为神经网络(深度学习)的起源的算法,是学习神经网络和深度学习的重要一环
- 严格地说,本章所说的感知机应该称为‘人工神经元’或‘朴素感知机’,但是因为很多基本原理是共通的,所以这里简单称为‘感知机’
2.1 感知机是什么
感知机接收多个输入信号,输出一个信号。感知机的信号会形成流,向前方传递信息。感知机的信号只有‘流’/‘不流’(1/0)两种取值。本书中,0
表示‘不传递信号’,1 表示‘传递信号’
下图是一个接收两个输入信号的感知机的例子。x1、x2 是输入信号,y 是输出信号,w1、w2
是权重。圆形是‘神经元’或‘节点’。输入信号被送往神经元时,会被分别乘以固定的权重(w1x1,w2x2)
。神经元会计算传送过来的信号的总和,只有这个总和超过了某个界限值时,才会输出 1。这也称为‘神经元被激活’。这个界限值称为阈值,用符号
θ 表示
感知机的多个输入信号都有各自固有的权重,发挥着控制各个信号的重要性的作用。也就是说,权重越大,对应该权重的信号的重要性就越高
- 权重相当于电流里所说的电阻。电阻是决定电流流动难度的参数,电阻越低,通过的电流就越大。而感知机的权重则是值越大,通过的信号就越大。在控制信号流动难度(或者流动容易度)这一点上的作用是一样的。
2.2 简单逻辑电路
2.2.1 与门(AND gate)
与门是有两个输入和一个输出的门电路。与门仅在两个输入均为 1 时输出 1,其他时候输出 0
如果用感知机来表示,怎么确定 w1、w2、θ 的值才能满足该真值表?
实际上,满足该条件的参数的选择方法有无数个。比如(w1,w2,θ)=(0.5,0.5,0.7) or (w1,w2,θ)=(0.5,0.5,0.8) or (w1,w2,θ)=(
1.0,1.0,1.0)时。设定这样的参数后,仅当 x1 和 x2 同时为 1 时,信号的加权总和才会超过给定的阈值 θ。
2.2.2 与非门(NAND gate)和或门
与非门就是颠倒了与门的输出。仅当 x1 和 x2 同时为 1 时输出 0,其他时候则输出 1
感知机表示与非门,只需要将实现与门的参数值的符号取反就可以实现
与门是‘只要有一个输入信号是 1,输出就为 1’的逻辑电路
与门、与非门、或门的感知机构造是一样的。它们只有参数的值(权重和阈值)不同。也就是说,相同构造的感知机只要调整参数的值,就可以变成不同的逻辑电路
- 这里我们人为决定感知机参数,看着真值表这种‘训练数据’,人工考虑了参数的值。而机器学习的课题就是将这个决定参数值的工作交给计算机自动进行。‘学习’是确定合适参数的过程,人要做的就是思考感知机的构造(模型),并将训练数据交给计算机。
2.3 感知机的实现
2.3.1 简单的实现
先定义一个接收参数 x1 和 x2 的 AND 函数
def AND(x1, x2):w1, w2, theta = 0.5, 0.5, 0.7tmp = x1 * w1 + x2 * w2if tmp <= theta:return 0elif tmp > theta:return 1
在函数内初始化参数 w1、w2、theta,但输入的加权总和超过阈值时返回 1,否则返回 0
print(AND(0, 0)) # 0
print(AND(0, 1)) # 0
print(AND(1, 0)) # 0
print(AND(1, 1)) # 1
2.3.2 导入权重和偏置
将之前的式子的阈值换成偏置,即 θ 换成-b
改变后,表达的内容依然完全相同。b 称为偏置,w 称为权重,感知机计算输入信号和权重的乘积,然后加上偏置,如果这个值大于 0 则输出
1,否则输出 0。
import numpy as npx = np.array([0, 1]) # 输入
w = np.array([0.5, 0.5]) # 权重
b = -0.7 # 偏置
print(w * x)np.sum(w * x)
print(np.sum(w * x) + b)
# -0.19999999999999996 大约为-0.2(由浮点小数造成的运算误差)
这里 numpy 数组乘法运算,当两个数组的元素个数相同时,各个元素分别相乘,之后 sum(w*x)计算相乘后的各个元素的总和。最后加上偏置,完成计算
2.3.3 使用权重和偏置的实现
def AND(x1, x2):x = np.array([x1, x2])w = np.array([0.5, 0.5])b = -0.7tmp = np.sum(w * x) + bif tmp <= 0:return 0else:return 1
权重 w1、w2 是控制输入信号的重要性的参数,而偏置是调整神经元被激活的容易程度(输出信号为 1 的程度)的参数。
- 偏置这个术语,有‘穿木屐’的效果,即在没有任何输入时(输入为 0 时),给输出穿上多高的木屐(加上多大的值)的意思。
继续实现与非门和或门
def NAND(x1, x2):x = np.array([x1, x2])w = np.array([-0.5, -0.5])b = 0.7tmp = np.sum(w * x) + bif tmp <= 0:return 0else:return 1def OR(x1, x2):x = np.array([x1, x2])w = np.array([0.5, 0.5])b = -0.2tmp = np.sum(w * x) + bif tmp <= 0:return 0else:return 1
2.4 感知机的局限性
2.4.1 异或门
异或门也称为逻辑异或电路。仅当 x1 或 x2 中的一方为 1 时,才会输出 1(‘异或’是拒绝其他的意思)。
前面介绍的感知机无法实现这个异或门。
我们将或门的动作形象化。或门的情况下,当权重参数(b,w1,w2)=(-0.5,1.0,1.0)时,可以用下面的式子表示
该式表示感知机会生成由直线-0.5 + x1 + x2 = 0 分割开的两个空间。其中一个空间输出 1,另一个空间输出 0
但是如何用一条直线分割出异或的 0、1 输出空间?事实上,用一条直线无法将 0、1 分开
2.4.2 线性和非线性
感知机的局限性就在于它只能表示由一条直线分割的空间。如果用曲线分割,就可以实现。由曲线分割而成的空间称为非线性空间,由直线分割而成的空间称为线性空间。线性和非线性这两个术语在机器学习领域很常见。
2.5 多层感知机
感知机的绝妙之处在于它可以‘叠加层’(通过叠加层来表示异或门或门是本节的要点)。我们暂不考虑叠加层具体是指什么,先从其他视角来思考一下异或门的问题。
2.5.1 已有门电路的组合
异或门制作方法有很多,其中之一就是与门、或门、与非门的组合。这几个门我们用下面的符号表示,图 2-9 中与非门前端的〇表示反转输出的意思
2.5.2 异或门的实现
def XOR(x1, x2):s1 = NAND(x1, x2)s2 = OR(x1, x2)y = AND(s1, s2)return yprint(XOR(0, 0)) # 0
print(XOR(0, 1)) # 1
print(XOR(1, 0)) # 1
print(XOR(1, 1)) # 0
异或门是一种多层结构的神经网络。这里,将最左边的一列称为第 0 层,中间的一列称为第一层,最右边的一列称为第 2 层。
实际上,与门、或门是单层感知机,而异或门是 2 层感知机。叠加了多层的感知机也称为多层感知机(multi-layered perceptron)
- 上图由 3 层构成,但是因为拥有权重的实际上只有两层(第 0 层到第 1 层,第 1 层和第 2 层之间),所以称为‘2 层感知机’,也有的文献认为这是由
3 层构成,所以称为‘3 层感知机’
在这种多层感知机中,第一层输出变为第二层输入,数据在之间不断传送。通过叠加层,感知机能进行更加灵活的表示。
2.6 从与非门到计算机
多层感知机可以实现比之前见到的电路更复杂的电路。比如加法运算的加法器、二进制转十进制的编码器、满足某些条件就输出 1
的电路(用于等价检验的电路)……甚至可以表示计算机
计算机是处理信息的机器。输入信息,会按照某个既定规则进行计算,然后输出,这和感知机是一样的
只需要通过与非门的组合,就能再现计算机
- 拓展阅读:《计算机系统要素:从零开始构建现代计算机》
多少层(层级多深)的感知机可以表示计算机?理论上可以说 2 层感知机就可以构建计算机。有研究证明,2 层感知机(严格地说是激活函数使用了非线性的
sigmoid 函数的感知机)可以表示任意函数。但是使用 2 层感知机的构造,通过设定合适的权重来构建计算机是非常累人的事。
实际上,用与非门等低层元件构建计算机的情况下,分阶段地制作所需的零件(模块)会比较自然,即先实现与门和或门,然后实现半加器和全加器,接着实现算数逻辑单元(ALU),然后实现
CPU。使用这种叠加了多层的构造来实现是比较自然的流程。
2.7 小结
- 感知机是具有输入和输出的算法。给定一个输入后,将输出一个既定的值
- 感知机将权重和偏置设定为参数。
- 使用感知机可以表示与门和或门等逻辑电路
- 异或门无法通过单层感知机来表示。
- 使用 2 层感知机可以表示异或门
- 单层感知机只能表示线性空间,而多层感知机可以表示非线性空间。
- 多层感知机(在理论上)可以表示计算机。