20151227感知机(perceptron)
1 感知机
1.1 感知机定义
感知机是一个二分类的线性分类模型,其生成一个分离超平面将实例的特征向量,输出为+1,-1。导入基于误分类的损失函数,利用梯度下降法对损失函数极小化,从而求得此超平面,该算法有原始形式和对偶形式。
定义:假设输入空间是\(\chi \subseteq \mathbb{R}^n\),输出空间是{+1,-1},输入\(x \in \chi \)表示实例的特征向量,对应于输入空间的点;输出\(y \in Y\)表示实例的类别。则由输入空间到输出空间的如下函数f(x) = sign(wx+b)为感知机。其中\(w \in \mathbb{R}^n\)叫做权值,\(b \in \mathbb{R}\)叫做偏置,sign是符号函数即:
\[sign \left ( x \right ) = \left\{ \begin{matrix}
+1,x \geqslant 0 \\
-1, x < 0
\end{matrix}\right.\]
很明显可以看到,感知机的几何解释就是线性方程wx+b=0是一个超平面,将点分成+1,-1两类。
1.2 感知机损失函数
那么如何确定这个分离超平面呢?首先我们假设数据集线性可分,在这个目标下再定义一个损失函数,到时候将损失函数极小化就可以得到分离超平面了。
为了使得w,b联系可导,在这里采用的损失函数是误分类点到超平面的总距离。
①点\(x_0\)到超平面S距离为:
\[\frac{1}{\left \| w \right \|} \left| w \cdot x_0 +b \right| \]
②对于误分类点到超平面S距离为:
\[-\frac{1}{\left \| w \right \|} y_i \left| w \cdot x_0 +b \right| \]
③误分类点到超平面S距离之和为(其中M为误分类点的集合):
\[-\frac{1} {\left \| w \right \|} \sum_ {x_i \in M} { y_i \left| w \cdot x_0 +b \right| }\]
④则感知机损失函数定义为:
\[-\sum_{x_i \in M} { y_i \left| w \cdot x_0 +b \right|}\]
2 感知机求解
2.1 原始形式
给定训练数据集\(T=\left \{ \left(x_1,y_1\right),\left(x_2,y_2\right),\cdots,\left(x_N,y_N\right) \right \}\)
其中,\(x_i \in \chi = \mathbb{R}^n\),\(y_i \in Y= \left\{ -1,1 \right\}\),\(i=1,2,\cdots,N\),求参数w,b,使其成为以下函数极小化问题的解。其中M为误分类点的集合。
\[\underset{w,b}{min}L\left(w,b \right) = -\sum_{x_i \in M}{y_i \left( w \cdot x_i +b \right)}\]
这里采用随机梯度下降法来求解w,b。每次随机使用一个误分类点使其梯度下降。
算法步骤:
1. 选取初值w0,b0
2. 在训练集中选取数据\(\left( x_i,y_i \right)\)
3. 如果\(y_i \left( w \cdot x_i +b \right) \leqslant 0\),则:(此处\(\eta\)为学习率)
\[w \leftarrow w + \eta y_i x_i\]\[b \leftarrow b + \eta y_i\]
4. 到(2),直到训练集中没有误分类点。(此处有个疑问,如果不能线性可分怎么办,就是始终有个误分类点怎么搞?)
按照以上步骤可以发现如果有点被分错了,则会使得分离超平面超这个点这侧移动,使得距离减少。具体的代码如下。直接运行可以得到分隔的超平面和原始数据点。
# -*- coding:utf-8 -*-
########################################
# perceptron: perceptron
# Author : xuke
# Date : 2015-12-16
########################################
import matplotlib.pyplot as plt
import numpy
def sign(x,w,b):
res = b
for i in xrange(len(x)-1):
res += x[i+1]*w[i]
return res
def perceptron(data):
w = [-1]*(len(data[0])-1)
b = 2
i = 0
end_flag = 1000
end_num = 0
learn_rate=2
while(i< len(data) and end_num<end_flag):
d = data[i]
end_num += 1
if sign(d,w,b)*d[0]<=0:
b += learn_rate*d[0]
w = [ w1+d1 for w1,d1 in zip(w, [t*d[0]*learn_rate for t in d[1:]])]
i = 0
else:
i += 1
print "iter:",end_num
return w,b
def draw_line(data,w,b):
flag = ['b*','rs','g+','sb', 'db', '<b', 'pb']
for i in data:
plt.plot(i[1],i[2],flag[i[0]])
x = numpy.linspace(-10,10,100)
plt.plot(x,(b+w[0]*x)*(-1)/w[1])
plt.show()
if __name__=='__main__':
data=[
[1,4,3],
[-1,1,1],
[-1,3,1],
[1,1,3],
[1,4,6],
[-1,-1,3],
[1,3,9],
[-1,4,1],
[1,4,4],
]
w,b = perceptron(data)
print w,b
draw_line(data,w,b)
2.2 对偶形式
我们在这里可以分析下这个公式:
\[w \leftarrow w + \eta y_i x_i\]\[b \leftarrow b + \eta y_i\]
很明显我们可以得到:
\[w=\sum_{i=1}^{N}{\alpha_i y_i x_i}\] \[b=\sum_{i=1}^{N}{\alpha_i y_i}\]
如果\(\eta=1\),则这里的\(\alpha_i\)表示第i个点被分错的次数,如果这个值越大,则说明这个点越难被分对。
则这里我们可以拿出对偶形式:
输入:线性可分的数据集\(T=\left \{ \left(x_1,y_1\right),\left(x_2,y_2\right),\cdots,\left(x_N,y_N\right) \right \}\)
其中,\(x_i \in \mathbb{R}^n\),\(y_i \in Y= \left\{ -1,1 \right\}\),\(i=1,2,\cdots,N\),学习率\(\eta \left( 0 < \eta \leqslant 1\right)\)
输出:\(\alpha,b\);其中\(\alpha=\left( \alpha_1,\alpha_2,\cdots,\alpha_N \right)^T\)感知机模型\[f \left( x \right) = sign\left( \sum_{j=1}^{N}{\alpha_j y_j x_j \cdot x +b}\right)\]
1. \(\alpha \leftarrow 0,b\leftarrow 0\)
2. 在训练集中选取数据\(\left( x_i,y_i\right)\)
3. 如果\(y_i \left( \sum_{j=1}^{N}{\alpha_jy_jx_j \cdot x_i +b} \right) \leqslant 0\)
\[\alpha_i \leftarrow \alpha_i + \eta\] \[b \leftarrow b + \eta y_i\]
4. 转至(2)直到没有误分类数据
对偶形式中训练实例是以内积形式出现,在计算中可以提前计算内积矩阵Gram并存储。
3 其他
3.1疑问1:为什么单个感知机不能解决异或问题?
这里参考果壳网友回答,因为异或问题转换成二维平面就是一个分类问题。
-(0,1) +(1,1)
+(0,0) -(1,0)
但是上面的问题是无法线性可分的,因此感知机在这里不能解决异或问题。当然了单个感知机无法解决异或问题,但是多个的是能够解决的。
参考文献:
1. 《统计学习方法》李航
2. 感知机:http://blog.csdn.net/bingduanlbd/article/details/24468885
3. 为什么感知机(单层神经网络)不能解决异或问题:http://www.guokr.com/blog/793310/