感知机
感知机的定义:感知机是个线性二分类模型。其目的是学习一个超平面,可以将特征空间中的实例分为正负两类。
感知机算法有两种形式:原始形式与对偶形式。
从下图可以形象的看出感知机是一个什么东西:(那条斜线就是感知机学习到的超平面,这个超平面将两类点分离)
sign函数(感知机的模型)
函数原型:
可以从上面看出sign函数非常符合感知机的定义,所以其可以作为感知机的一种模型。将x换成feature、参数w的线性组合即可以作为感知机模型 (也就是上图的那条超平面) 。
例如上图的那个模型,感知机可以写为:sign ( w*x + b )
感知机的数据集
感知机的数据集如下:
对于其数据集的限制有:其中 xi ∈ X = Rn,yi ∈ Y = {+1,-1},i = 1,2,…,N
然后根据这些数据求得符合这些数据的模型参数w,b。通过学习得到的感知机模型,对于新的输入实例给出其对应的输出类别。
感知机的学习策略
既然感知机是线性可分的,那么就定义一个经验损失函数,使得损失最小的时候就达到了我们需要的模型效果了。
于是我们将点到超平面的距离作为损失,使得所有点到超平面的距离和最小即学习到最好的超平面。
为什么不将分类错误的点的数量作为损失?
个数是一个离散值,离散值是不可导的,所以不可以使用梯度下降。
但是距离是一个连续的,可导。
所以,以上告诉我们一个选择损失函数的原则,可导、连续!
点到直线的距离为一下公式:
改一改就可以变成一下公式:
但是我们使用的是函数间距,也就是不要分母,只要后面那个分子。
所以我们得到以下模型为 sign( w*x + b) 的损失函数(即感知机的学习策略)
其中 xi ∈ X = Rn,yi ∈ Y = {+1,-1},i = 1,2,…,N
式子中的负号的含义为:
误点正数化
因为当点为正确点的时候,有两种情况:正点(其y为+1,w*x+b为正数)、负点(其y为-1,w*x+b为负数)它们的乘积都大于0。
只有当点为误点的时候,它们的乘积才为负数,正数化是为了可以使得损失函数存在极小值,才能梯度下降损失函数
感知机的学习算法
在感知机中我们使用随机梯度下降作为学习的算法。
感知机的算法是为了找到给定数据集使得损失函数最小的解。
注意!在梯度下降的过程中并不是一次将所有的误分类点都梯度下降,而是一次随机选择一个点使其梯度下降。(这和梯度下降也符合,因为就算有批量的存在,在梯度下降时也是一个样本对应一个输出向量中的一个元素,而反向传播是根据该元素向前进行传播的,传播结果是所有传播的累加和)
以上损失函数计算出来梯度为:
(计算过程为:)
梯度更新结果为(梯度更新的原始形式为:w = w - lr*导数):
感知机完整的学习过程
一个感知机完整的学习流程图
输入为:训练数据集 T = {(x1, y1), (x2, y2), (x3, y3), …, (xN, yN)},其中 xi ∈ X = Rn,yi ∈ Y = {+1,-1},i=1,2,…,N;学习率范围为(0< lr <=1)
输出为:w,b;感知机模型 f(x) = sign( w*x + b)
由于模型是我们人为已经确定了的,所以不需要将数据代入损失函数中再求反向传播,我们直接通过公式求导得到导数公式,然后直接更新梯度即可!
相应的实例
实例的实现过程
手写执行过程:
注意!按照他书上面的求解过程求出来的只是感知机的解空间中的一个模型,不一定是最好的,因为损失并不一定是最小的,所以要求最优化还得继续梯度下降!
代码实现
导包:
import torch
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.pyplot import MultipleLocator
准备数据:
x1 = torch.tensor([3, 3])
x2 = torch.tensor([4, 3])
x3 = torch.tensor([1, 1])
y1 = torch.tensor([1])
y2 = torch.tensor([1])
y3 = torch.tensor([-1])
x = [x1, x2, x3]
y = [y1, y2, y3]
def init_plt(figsize):
plt.figure(figsize=figsize)
x_major_locator=MultipleLocator(1)
y_major_locator=MultipleLocator(1)
ax=plt.gca()
ax.set_aspect(1)
ax.xaxis.set_major_locator(x_major_locator)
ax.yaxis.set_major_locator(y_major_locator)
plt.xlim(-5.5, 5.5)
plt.ylim(-5.5, 5.5)
ax = plt.gca()
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
plt.xticks(np.linspace(-5, 5, 11))
plt.yticks(np.linspace(-5, 5, 11))
x_ = [i[0] for i in x]
x__ = [i[1] for i in x]
init_plt((5, 5))
plt.scatter(x_, x__)
plt.show()
模型:
def net(w, b, x):
return torch.matmul(w, x) + b
初始化参数:
w = torch.tensor([0, 0])
b = torch.tensor([0])
损失函数:
def loss(w, b, x, y):
return net(w, b, x) * y
梯度下降,开始学习训练:
flag = True
i = 0
while(flag):
num = 0
i += 1
for feature, label in zip(x, y):
result = 'epoch: {}, w: ({},{}), b: {}, x: ({},{}), y: {}'.format(i, w[0].item(), w[1].item(), b[0].item(), feature[0].item(), feature[1].item(), label[0].item())
if loss(w, b, feature, label) <= 0:
w = w + feature * label
b = b + label
print(result+', OK?: NO')
break
else:
print(result+', OK?: YES')
num += 1
if num >= 3:
break
训练结果输出:
epoch: 1, w: (0,0), b: 0, x: (3,3), y: 1, OK?: NO
epoch: 2, w: (3,3), b: 1, x: (3,3), y: 1, OK?: YES
epoch: 2, w: (3,3), b: 1, x: (4,3), y: 1, OK?: YES
epoch: 2, w: (3,3), b: 1, x: (1,1), y: -1, OK?: NO
epoch: 3, w: (2,2), b: 0, x: (3,3), y: 1, OK?: YES
epoch: 3, w: (2,2), b: 0, x: (4,3), y: 1, OK?: YES
epoch: 3, w: (2,2), b: 0, x: (1,1), y: -1, OK?: NO
epoch: 4, w: (1,1), b: -1, x: (3,3), y: 1, OK?: YES
epoch: 4, w: (1,1), b: -1, x: (4,3), y: 1, OK?: YES
epoch: 4, w: (1,1), b: -1, x: (1,1), y: -1, OK?: NO
epoch: 5, w: (0,0), b: -2, x: (3,3), y: 1, OK?: NO
epoch: 6, w: (3,3), b: -1, x: (3,3), y: 1, OK?: YES
epoch: 6, w: (3,3), b: -1, x: (4,3), y: 1, OK?: YES
epoch: 6, w: (3,3), b: -1, x: (1,1), y: -1, OK?: NO
epoch: 7, w: (2,2), b: -2, x: (3,3), y: 1, OK?: YES
epoch: 7, w: (2,2), b: -2, x: (4,3), y: 1, OK?: YES
epoch: 7, w: (2,2), b: -2, x: (1,1), y: -1, OK?: NO
epoch: 8, w: (1,1), b: -3, x: (3,3), y: 1, OK?: YES
epoch: 8, w: (1,1), b: -3, x: (4,3), y: 1, OK?: YES
epoch: 8, w: (1,1), b: -3, x: (1,1), y: -1, OK?: YES