感知机
感知机
感知机算法是很多算法的鼻祖,比如支持向量机算法,神经网络与深度学习。在学习感知机的构造时可以学习到深度学习的重要思想。在这里我们只是初步了解一下它。
1. 了解感知机
我们先给出一个准确的定义:
感知机是二分类的线性模型,其输入是实例的特征向量,输出的是事例的类别,分别是+1和-1,属于判别模型。
假设训练数据集是线性可分的,感知机学习的目标是求得一个能够将训练数据集正实例点和负实例点完全正确分开的分离超平面。如果是非线性可分的数据,则最后无法获得超平面
哇哦, 我们来看看这到底是什么,我们可以先看一些二维的例子。
我理解感知机是一种算法,这个算法接受多个输入信号,输出一个信号,输出的信号只有流与不流(1/0)两种状态。
<img src="https://i.loli.net/2019/06/13/5d020dd7909b144484.png" width="30%">
在上图中 、 是输入信号, 是输出信号, 、 是权重。其中的圆圈代表神经元,也叫节点。
当感知机收到两个信号时会被分别呈上一个权重,神经元计算送来信号的总和,当这个总和超过了某个临界值时神经元就被激活,输出 1 。这个极限值被称为阈值。用符号 表示。感知机也可以使用下面的数学方式来描述:
感知机的每个输入信号都有自己固定的权重,这些权重控制着各个信号的重要性的作用。其实权重可以类比电阻来理解,不管是电阻还是权重都是起到控制信号流动难易程度的作用。
2. 实现几个感知机
下面让我们考虑实现几个简单的感知机。在下面我们会使用 Python 实现 与门、非门、或门,并且发现这种感知机的局限性。实际上感知机是通过学习确定参数的,在这里我们代替电脑完成学习的过程。
与门(and)
与门仅在两个输入均为 1 时输出 1 ,其他时候输出 0。
<img src="https://i.loli.net/2019/06/13/5d0218878aade65285.png" width="30%">
我们需要做的就是确定可以满足上面真值表的参数 、 与 实际上参数的选择是无限多的,我们手动找到一个:
def AND(x1, x2):
w1, w2, theta = 0.5, 0.5, 0.7
tmp = x1*w1 + x2*w2
if tmp <= theta:
return 0
if tmp > theta:
return 1
我们来测试一下它:
print(AND(0,0))
print(AND(0,1))
print(AND(1,0))
print(AND(1,1))
0
0
0
1
和我们预想的输出一样。
为了与以后我们的习惯保持一致,我们对上面的实现进行一个修改,首先我们修改我们的模型为:
在上面的例子中我们将阈值移到式子的左边,并且令 我们称参数 b 为偏置,偏置的值决定了,神经元被激活的难易程度。
另外我们采用 Numpy 数组进行乘法运算以提高效率,这在以后大量数据同时运算中具有重要意义。
接下来我们重新实现一下 AND
import numpy as np
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
print(AND(0,0))
print(AND(0,1))
print(AND(1,0))
print(AND(1,1))
0
0
0
1
结果是一样的,接着我们继续实现与非门和或门,他们都是仅仅权重和偏置与与门不同:
与或门(NAND)
NAND是Not AND的意思,与非门就是颠倒了与门的输出。用真值表表示的话, 仅当x 1 和x 2 同时为1时输出0,其他时候则输出1。
<img src="https://i.loli.net/2019/06/13/5d021f52d566961488.png" width="30%">
实现如下:
import numpy as np
def NAND(x1, x2):
x = np.array([x1, x2])
w = np.array([-0.5, -0.5]) # 所有权重与偏置取了一个负值
b = 0.7
tmp = np.sum(w*x) + b
if tmp <= 0:
return 0
else:
return 1
print(NAND(0,0))
print(NAND(0,1))
print(NAND(1,0))
print(NAND(1,1))
1
1
1
0
或门(OR)
或门是只要有一个输入信号是 1 就输出 1 的逻辑电路。
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(OR(0,0))
print(OR(0,1))
print(OR(1,0))
print(OR(1,1))
0
1
1
1
3. 感知机的局限性
为了看到感知机的局限性,我们先来看一个例子:异或门,异或门的意思是当且仅当两个输入一方为 1 时输出 1.
实际上使用前面的感知机是无法实现这个异或门的为了说明这一点,我们将或门的动作形象化,当参数为(b, , ) = (-0.5, 1.0, 1.0) 时感知机可以使用下面的式子表示出来:
你可能也看出来了整个平面被一条直线分割成了两个空间,一个空间输出 1,一个空间输出 0。
<img src="https://i.loli.net/2019/06/14/5d038558a4f1a46243.png" width = '40%' />
但是当我们尝试使用一条直线分开图中的(1,0)(0,1)两个点时问题就出现了,无论如何我们都无法分开他们。问题就出现在了我们的一个限制条件“使用一条直线”,如果我们将这个限制条件去掉的话,问题就可以解决了,比如说下面这样:
<img src="https://i.loli.net/2019/06/14/5d038d3ab477f20774.png" width = '50%' />
为了解决这个问题,我们可以使用多层感知机,也就是使用前面已经制作好的与门、与非门进行组合。(我们实际上是使用了两条直线)
实际上神经网络最强大的地方就在于隐藏层使用了多层结构,这意味着神经网络可以描述复杂的非线性变换。我们之后会看到这一点。
我们可以将感知机按照下面的方式组合以实现异或门的功能:
<img src="https://i.loli.net/2019/06/14/5d039167285a058951.png" width = '50%'/>
<img src="https://i.loli.net/2019/06/14/5d0391ad617e811969.png" width = '50%'/>
我们先来确认一下上面的组合是否真的实现了异或门的功能,我们将 作为与非门的输出, 将 作为或门的输出,填入真值表中,可以发现确实符合真值表的输出。
<img src="https://i.loli.net/2019/06/14/5d0392456013940004.png" width = '40%' />
下面我们使用 Python 来实现它。
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
print(XOR(0,0))
print(XOR(0,1))
print(XOR(1,0))
print(XOR(1,1))
0
1
1
0
如果我们使用节点的表示方法来表示,如下图所示:
<img src="https://i.loli.net/2019/06/14/5d0393d9ec5c233586.png" width = '40%' />
上面的例子说明了通过单层感知机无法表示的东西,通过叠加层就可以实现,这意味着,通过加深层数,感知机可以进行非线性的表示。