二、感知机
感知机(perceptron)是二类分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别,取+1 , -1 二值。感知机对应于输入空间(特征空间)中将实例划分为正负两类的分离超平面,属于判别模型。感知机学习旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知器模型。
感知机学习算法具有简单而易于实现的优点,分为原始形式和对偶形式,是神经网络与支持向量机的基础。
2.1感知机模型
假设输入空间(特征空间)是 X⊆Rn ,输出空间是 y={+1,−1} ,由输入空间到输出空间的如下函数
感知机的几何解释:线性方程
2.2 感知机学习策略
2.2.1数据集的线性可分性
如果存在某个超平面
S
即
2.2.2感知机学习策略
假设训练数据集是线性可分的,感知机学习的目标是求得一个能够将训练集正实例点和负实例点完全正确分开的分离超平面。为了找出这样的超平面,即确定感知机模型参数
ω,b
,需要确定一个学习策略,即定义(经验)损失函数并将损失函数极小化。
损失函数的定义为
其中, M 为误分类点的集合。这个损失函数就是感知机学习的经验风险函数。
2.3感知机学习算法
感知机学习问题转化为求解以上损失函数的最优化问题,最优化的方法是随机梯度下降法。本节叙述感知机学习的具体算法,包括原始形式和对偶形式,并证明在训练数据线性可分条件下感知机学习算法的收敛性。
2.3.1感知机学习算法的原始形式
输入:训练数据集
输出:
ω,b
;感知机模型
f(x)=sign(ω⋅x+b)
(1)选取初值 ω0,b0
(2)在训练集中选取数据 (xi,yi)
(3)如果 yi(ω⋅x+b)≤0
w=w+ηyixi
b=b+ηyi
(4)转至(2),直到训练集中没有误分类点
import os
import sys
# An example in that book, the training set and parameters' sizes are fixed
training_set = []
w = []
b = 0
lens = 0
n = 0
# update parameters using stochastic gradient descent
def update(item):
global w, b, lens, n
for i in range(lens):
w[i] = w[i] + n * item[1] * item[0][i]
b = b + n * item[1]
print w, b # you can uncomment this line to check the process of stochastic gradient descent
# calculate the functional distance between 'item' an the dicision surface
def cal(item):
global w, b
res = 0
for i in range(len(item[0])):
res += item[0][i] * w[i]
res += b
res *= item[1]
return res
# check if the hyperplane can classify the examples correctly
def check():
flag = False
for item in training_set:
if cal(item) <= 0:
flag = True
update(item)
if not flag: #False
print "RESULT: w: " + str(w) + " b: "+ str(b)
tmp = ''
for keys in w:
tmp += str(keys) + ' '
tmp = tmp.strip()
modelFile.write(tmp + '\n')
modelFile.write(str(b) + '\n')
modelFile.write(str(lens) + '\n')
modelFile.write(str(n) + '\n')
modelFile.close()
os._exit(0)
flag = False
if __name__=="__main__":
if len(sys.argv) != 4:
print "Usage: python perceptron.py n trainFile modelFile"
exit(0)
n = float(sys.argv[1])
trainFile = file(sys.argv[2])
modelFile= file(sys.argv[3], 'w')
lens = 0
for line in trainFile:
chunk = line.strip().split(' ')
lens = len(chunk) - 1
tmp_all = []
tmp = []
for i in range(1, lens+1):
tmp.append(int(chunk[i]))
tmp_all.append(tmp)
tmp_all.append(int(chunk[0]))
training_set.append(tmp_all)
trainFile.close()
for i in range(lens):
w.append(0)
for i in range(1000):
check()
print "The training_set is not linear separable. "
2.3.2算法的收敛性
对于线性可分数据集,感知机学习算法原始形式收敛,即经过有限次迭代可以得到一个将训练数据集完全正确划分的分离超平面及感知机模型。
2.3.3感知机学习算法的对偶模式
对偶形式的基本想法是,将
w
和
假设对于误分类的点
(xi,yi)
共n次修改
ω,b
的值,则
ω,b
关于
(xi,yi)
的增量分别是
αiyixi
和
αyi
,这里
αi=niη
.从学习过程中不难看出,最后学习到的
ω,b
可以分别表示为
感知机学习算法的对偶模式
输入:线性可分的数据集 T={(x1,y1),(x2,y2),⋯,(xN,yN)} ,其中 xi∈RN , yi∈{−1,+1} ,学习率 η(0<η≤1) ;
输出: α,b ;感知机模型 f(x)=sign(∑Nj=1ajyjxj+b)
其中 α=(α1,α2,⋯,αN)T
(1) α=0,b=0
(2)在训练集中选取数据 (xi,yi)
(3)如果 yi(∑Nj=1αjyjxj⋅xi+b)≤0
αi=αi+η
b=b+ηyi
(4)转至(2),直到训练集中没有误分类数据
import os
import sys
# An example in that book, the training set and parameters' sizes are fixed
training_set = []
w = []
a = []
b = 0
lens = 0
n = 0
Gram = []
def calInnerProduct(i, j):
global lens
res = 0
for p in range(lens):
res += training_set[i][0][p] * training_set[j][0][p]
return res
def AddVector(vec1, vec2):
for i in range(len(vec1)):
vec1[i] = vec1[i] + vec2[i]
return vec1
def NumProduct(num, vec):
for i in range(len(vec)):
vec[i] *= num
return vec
def createGram():
global lens
for i in range(len(training_set)):
tmp = []
for j in range(0, len(training_set)):
tmp.append(calInnerProduct(i, j))
Gram.append(tmp)
# update parameters using stochastic gradient descent
def update(k):
global a, b, n
a[k] += n
b = b + n * training_set[k][1]
print a, b # you can uncomment this line to check the process of stochastic gradient descent
# calculate the functional distance between 'item' an the dicision surface
def cal(k):
global a, b
res = 0
for i in range(len(training_set)):
res += a[i] * int(training_set[i][1]) * Gram[i][k]
res += b
res *= training_set[k][1]
return res
# check if the hyperplane can classify the examples correctly
def check():
global w, a
flag = False
for i in range(len(training_set)):
if cal(i) <= 0:
flag = True
update(i)
if not flag: #False
for i in range(len(training_set)):
w = AddVector(w, NumProduct(a[i] * int(training_set[i][1]), training_set[i][0]))
print "RESULT: w: ", w, " b: ", b
tmp = ''
for keys in w:
tmp += str(keys) + ' '
tmp = tmp.strip()
modelFile.write(tmp + '\n')
modelFile.write(str(b) + '\n')
modelFile.write(str(lens) + '\n')
modelFile.write(str(n) + '\n')
modelFile.close()
os._exit(0)
flag = False
if __name__=="__main__":
if len(sys.argv) != 4:
print "Usage: python perceptron_duality.py n trainFile modelFile"
exit(0)
n = float(sys.argv[1])
trainFile = file(sys.argv[2])
modelFile= file(sys.argv[3], 'w')
lens = 0
for line in trainFile:
chunk = line.strip().split(' ')
lens = len(chunk) - 1
tmp_all = []
tmp = []
for i in range(1, lens+1):
tmp.append(int(chunk[i]))
tmp_all.append(tmp)
tmp_all.append(int(chunk[0]))
training_set.append(tmp_all)
trainFile.close()
createGram()
for i in range(len(training_set)):
a.append(0)
for i in range(lens):
w.append(0)
for i in range(1000):
check()
print "The training_set is not linear separable. "
对偶形式中训练实例仅以内积的形式出现。为了方便,可以预先将训练集中的实例间的内积计算出并以矩阵的形式存储,这个矩阵就是所谓的
Gram
矩阵