1.感知机模型
如图为人体神经网络图,输入信号从树突传入,在细胞核处汇总,输出信号从轴突处传出传入其他神经元,从而构成了一个人体的神经网络。而感知机其类似于一个神经元。
一个单层感知机与人体神经元类似,
x
1
,
x
2
,
x
3
x_{1},x_{2},x_{3}
x1,x2,x3为输入结点,及神经元的输入信号,
w
1
,
w
2
,
w
3
w_{1},w_{2},w_{3}
w1,w2,w3为各输入结点的权重,可以理解为神经元各个树突的电阻,到达细胞核后通过进行汇总,通过一个激活函数处理后进行输出。其中,w和b称为感知机模型参数,w 叫做权重,b叫做偏置,f为激活函数,其表达式为:
s
i
g
n
(
x
)
=
{
1
,
x
>
=
0
−
1
,
x
<
0
(1)
sign(x)= \begin{cases} 1,x>=0\\ -1, x<0 \end{cases} \tag{1}
sign(x)={1,x>=0−1,x<0(1)
为了方便矩阵运算,将添加一个输入恒为1的输入信号x_{0},其对应的权重w_{0}即为偏置项b。多个感知机组合起来就构成了神经网络。
从感知机的激活函数的输出来看,感知机可以处理过后的输入信号进行分类。输出为1是一类,输出为-1又是一类。从几何上来看,感知机学习的目标是对一个线性可分得数据集T求得一个能对T中的正负样本进行正确划分的一个超平面,参数w即为该超平面的法向量,偏置b为超平面的截距。这个超平面将数据集划分为两个部分,位于平面两部分的点被分成了正负两类。
2.感知机的学习策略
对于误分类的样本数据(x,y)来说,
(
y
^
−
y
)
(
w
x
+
b
)
>
0
(\hat{y}-y)(wx+b)>0
(y^−y)(wx+b)>0恒成立。应为当
w
x
+
b
>
=
0
wx+b>=0
wx+b>=0时,模型输出值为1,而样本实际值为-1,反之,当
w
x
+
b
<
0
wx+b<0
wx+b<0时,模型输出为-1,而实际值为1,将两种情况带入可以得到
(
y
^
−
y
)
(
w
x
+
b
)
>
0
(\hat{y}-y)(wx+b)>0
(y^−y)(wx+b)>0恒成立。由此,对于给定数据集T,其损失函数可定义为
L
(
w
,
b
)
=
∑
x
i
∈
M
(
y
i
^
−
y
i
)
(
w
x
i
+
b
)
L(w,b)=\sum_{x_{i}∈M}{(\hat{y_{i}}-y_{i})}(wx_{i}+b)
L(w,b)=xi∈M∑(yi^−yi)(wxi+b)
M为误分类点集合
x显然损失函数是非负的,如果没有误分类点,损失函数值是0.误分类点越少,损失函数就越小。
则要求参数w,b,就可以通过求解损失函数最小值点来得出参数。故而最小化问题进一步转化为:
m
i
n
w
L
(
w
)
=
m
i
n
w
∑
x
∈
M
(
y
i
^
−
y
i
)
w
x
i
min_{w}L(w)=min_{w}\sum_{x∈M}{(\hat{y_{i}}-y_{i})wx_{i}}
minwL(w)=minwx∈M∑(yi^−yi)wxi
3.感知机的学习算法
感知机学习算法是由误分类驱动的,具体采用随梯度下降法。首先,任意选取一个超平面
w
0
b
0
w_{0}b_{0}
w0b0,然后采用梯度下降法不断地极小化代价函数。极小化的过程不是一次使M中所有的误分类点的梯度下降,而是随机选取一个误差分类点使其梯度下降。
假设误分类样本集合M固定时,那么可以求得损失函数的梯度为:
L
(
w
)
=
∑
x
i
∈
M
(
y
i
^
−
y
i
)
x
i
L(w)=\sum_{x_{i}∈M}({\hat{y_{i}}-y_{i}})x_{i}
L(w)=xi∈M∑(yi^−yi)xi
通过梯度下降w法梯度更新公式为:
w
=
w
−
α
(
y
i
^
−
y
i
)
x
i
=
w
+
α
(
y
i
−
y
^
)
x
i
w=w-\alpha (\hat{y_{i}}-y_{i})x_{i}=w+\alpha{(y_{i}-\hat{y})x_{i}}
w=w−α(yi^−yi)xi=w+α(yi−y^)xi
所以感知机的学习算法为:
①选取初值
w
0
w_{0}
w0
②在数据集中选取
(
x
0
,
y
0
)
(x_{0},y_{0})
(x0,y0)
③如果
(
y
i
−
y
i
^
)
(
x
i
w
+
b
)
<
=
0
(y_{i}-\hat{y_i})(x_{i}w+b)<=0
(yi−yi^)(xiw+b)<=0则
w
=
w
+
Δ
w
w=w+\Delta w
w=w+Δw
④转置②,直至训练集没有误分类点
4.代码实现
import numpy as np
import matplotlib.pyplot as plt
import random
x=np.array([[1,3,3],
[1,4,3],
[1,1,1],
[1,0,2]])
y=np.array([[1],
[1],
[-1],
[-1]])
w=np.random.random([3,1])#生成一个3行1列的矩阵
lr=0.01#学习率
epochs=100#最大迭代次数
O=0
def plot():
#正样本
x1 = [3,4]
y1 = [3,3]
#负样本
x2 = [1,0]
y2 = [1,2]
#计算分界线的斜率以及截距
k = -w[1]/w[2]
d = -w[0]/w[2] #w0+w1*x+w2*y=0
print('k=',k)
print('d=',d)
xdata=(0,5)
plt.plot(xdata,xdata*k+d,'r')
plt.scatter(x1,y1,c='b')
plt.scatter(x2,y2,c='y')
plt.show()
Δ
w
=
−
α
(
y
i
^
−
y
i
)
x
i
=
α
(
y
i
−
y
i
^
)
x
i
\Delta{}w=-\alpha(\hat{y_{i}}-y_{i})x_{i}=\alpha(y_{i}-\hat{y_{i}})x_{i}
Δw=−α(yi^−yi)xi=α(yi−yi^)xi
w
=
w
+
Δ
w
w=w+\Delta w
w=w+Δw
def gard():
global x,y,lr,w
O=np.sign(np.dot(x,w))#预测输出
#print(O)
for i in range(x.shape[0]):
a=x[i,:,np.newaxis].reshape(1,-1)
b=O[i,:,np.newaxis].reshape(1,-1)
if(np.dot(a,w)[0,0]*(y[i]-b)[0,0]<0):
a=x[i,:,np.newaxis].reshape(1,-1)
b=O[i,:,np.newaxis].reshape(1,-1)
w_c=a.T.dot(y[i]-b)#
w=w+lr*w_c#更新梯度
break
#print(w)
return w
w=np.random.random([3,1])#生成一个3行1列的矩阵
for i in range(5000):
w=gard()
O=np.sign(np.dot(x,w))
if(O==y).all():
#print(O)
#print(i)
# if(i%10==0):
# plot()
# #print(w)
# #print(O)
break
plot()
k= [-0.09968292]
d= [2.60720738]