引用了:http://blog.youkuaiyun.com/qq_31456593/article/details/71335926
感知机是一个线性的分类器,不能解决非线性的分类问题比如说异或问题
下面是一个典型的感知机:
四个变量,对应四个权重,表示每个变量的重要程度,其中一个变量是作为bias存在的,
其input值始终为1,权重w0 = bias = -threshold
经过加权和之后,需要一个激励函数(activator)将值映射到{0,1}上
下面是使用阶跃函数作为activator
注意这里w0*x0其实那个threshold,不在不等式左边
如果我们将那个input值始终为1的变元代表的移动到等式的的左边可以得到
之后我们能得到真正的阶跃函数作为激励函数的表达式
我们不难发现一个训练好的感知机的组成为:
如何训练这个感知机呢?
1. 初始化感知机的参数,权值
2. 确定好迭代次数iteration和学习率rate
使用标注好的训练数据的二元组(input_vecs,labels)
1)使用predict函数计算出output
2)使用update_coeff更新参数
更新参数的方法为其中
为学习率,
是训练样本的实际值,就是label,
是感知机的输出值,上面更新参数的方法就是gradient descend
我背的的代码:
# encoding: utf-8
# 在类中自己的属性一定要加self,跟java一样
# 类自己的方法,在类中实现时,也要加self,表示作用于自己
class honor_perceptron(object):
def __init__(self, input_num, activator):
# 属性有三个,漏了activator,其实activator才是传进去的!
self.weights = [0.0 for _ in range(input_num)]
self.bias = 0.0
self.activator = activator
def __str__(self):
return 'weights:%s\tbias:%f\n' % (self.weights, self.bias)
def train(self,input_vecs,labels,iteration,rate):
for i in range(iteration):
self._one_iteration(input_vecs,labels,rate)
def _one_iteration(self,input_vecs,labels,rate):
samples = zip(input_vecs,labels)
for (input_vec,label) in samples:
output = self.predict(input_vec)
self._update_weights(input_vec,output,label,rate)
def predict(self,input_vec):
# 这里忘记代到activator里面了
# lambda表达式的括号确实有关系
# reduce累加,累乘的时候lambda表达式不要括号
return self.activator(reduce(lambda x, y:x+y,
map(lambda (x, w):x*w,
zip(input_vec,self.weights)),
0.0)+self.bias)
def _update_weights(self,input_vec,output,label,rate):
delta = label - output
self.weights = map(lambda(x,w):w + rate*delta*x,zip(input_vec,self.weights))
self.bias += rate*delta
def f(x):
return 1 if x>0 else 0
def get_train_dataset():
input_vecs = [[1, 1],[1, 0],[0, 1],[0, 0]]
labels = [1, 0, 0, 0]
return (input_vecs,labels)
def train_and_perceptron():
(input_vecs, labels) = get_train_dataset()
# 下面犯了两个错误 1.没有初始化就想训练 2.p不需要初始化不需要指定类型
# honor_perceptron p = p,train(input_vecs,labels,10,0.1)
# 应该是
p = honor_perceptron(2, f)
p.train(input_vecs,labels,10,0.1)
return p
if __name__ == '__main__':
p = train_and_perceptron()
print p
print '1 and 1 = %d' % p.predict([1, 1])
print '1 and 0 = %d' % p.predict([1, 0])
print '0 and 1 = %d' % p.predict([0, 1])
print '0 and 0 = %d' % p.predict([0, 0])
我抄的代码:
# encoding: utf-8
'''
我遇到的初级错误,函数名和for后面不写冒号:
还有main函数不会写
if __name__ == '__main__'
'''
# python继承object表示新式类
class My_perceptron(object):
def __init__(self,input_num,activator):
'''
初始化感知机
:param input_num: 输入参数的个数
:param activator: 激活函数
'''
'''python self先理解为this吧
python中的self就相当于C++中的this指针
也就是指向对象本身的指针
self.name = name 就是当前对象的成员变量name赋值为name。
'''
self.activator = activator
# for _ in range(...)里的_其实就是一个不想起名字的变量而已
self.weights = [0.0 for _ in range(input_num)]
self.bias = 0.0
def __str__(self):
'''
:return: 学习得到的权重
'''
return 'finally: weights\t:%s\nbias\t:%f\n' % (self.weights,self.bias)
# 标注好的input_vecs和label,迭代次数iteration,学习率learning rate
def train(self,input_vecs,labels,iteration,rate):
for i in range(iteration):
self._one_iteration(input_vecs,labels,rate)
print '%dth iteration: weights\t:%s\nbias\t:%f\n' % (i+1, self.weights,self.bias)
# 这样命名可能是突出这个是私有的方法吧
def _one_iteration(self,input_vecs,labels,rate):
'''
每一次迭代,更新参数
'''
# 把输入的样本和标签打包,形成的元组对应起来
samples = zip(input_vecs,labels)
# 对每个样本根据感知机的规则进行更新权重
# 1.把input_vec传进去,计算output 2.利用output和input和标签label还有rate更新参数(weights和bias)
for (input_vec,label) in samples:
# 1.
output = self.predict(input_vec)
# 2.
self._update_weights(input_vec,output,label,rate)
def predict(self,input_vec):
# python在对多个变量组成的表达式的时候常用 先zip 然后前面lambda 放在map里面
return self.activator(
reduce(lambda x,y:x+y,
map(lambda (x,w):x*w,
zip(input_vec,self.weights))
0.0) + self.bias)
# 上面的0.0估计是为了把整数转化浮点数,以防万一
def _update_weights(self,input_vec,output,label,rate):
# delta_w_i = rate * delta * input_vec_i
delta = label - output
# 你要懂打包的实质,一般情况下都是将多元的东西打包(表达式里面带有i的变元)
self.weights = map(lambda (w,x):w + rate * delta * x, zip(self.weights, input_vec))
# 写完之后犯的错误:这个是+=而不是=,公式是核心千万不能写错哦
self.bias += rate * delta
# 定义激活函数
# 注意python中条件表达式的写法
def f(x):
return 1 if x>0 else 0
# 标注好的数据直接灌进去
def get_train_dataset():
input_vecs = [[1, 1], [1, 0], [0, 1], [0, 0]]
labels = [1, 0, 0, 0]
return input_vecs, labels
def train_and_perception():
# 创建感知机
p = My_perceptron(2, f);
# 获得训练数据集
(input_vecs,labels) = get_train_dataset()
# 训练感知机
# 问题:为什么无论怎么调学习率,都是第四次收敛了???
p.train(input_vecs, labels, 10, 0.001)
return p
if __name__ == '__main__':
# 训练感知机
and_perceptron = train_and_perception()
# 输出训练之后的参数
print and_perceptron
#测试
print '1 and 1 = %d' % and_perceptron.predict([1, 1])
print '1 and 0 = %d' % and_perceptron.predict([1, 0])
print '0 and 1 = %d' % and_perceptron.predict([0, 1])
print '0 and 0 = %d' % and_perceptron.predict([0, 0])
原来的代码:
# encoding: utf-8
class Perceptron(object):
def __init__(self, input_num, activator):
'''
初始化感知器,设置输入参数的个数,以及激活函数。
激活函数的类型为double -> double
'''
self.activator = activator
# 权重向量初始化为0
self.weights = [0.0 for _ in range(input_num)]
# 偏置项初始化为0
self.bias = 0.0
def __str__(self):
'''
打印学习到的权重、偏置项
'''
return 'weights\t:%s\nbias\t:%f\n' % (self.weights, self.bias)
def predict(self, input_vec):
'''
输入向量,输出感知器的计算结果
'''
# 把input_vec[x1,x2,x3...]和weights[w1,w2,w3,...]打包在一起
# 变成[(x1,w1),(x2,w2),(x3,w3),...]
# 然后利用map函数计算[x1*w1, x2*w2, x3*w3]
# 最后利用reduce求和
# reduce实例,容易实现累加,累乘,其实就是把一个函数作用于第一个个第二个得到的结果作为第一个,然后一直这样下去。。
xx = reduce(lambda x,y:x+y,[1,2,4,5])
return self.activator(
reduce(lambda a, b: a + b,
map(lambda (x, w): x * w,
zip(input_vec, self.weights))
, 0.0) + self.bias)
def train(self, input_vecs, labels, iteration, rate):
'''
输入训练数据:一组向量、与每个向量对应的label;以及训练轮数、学习率
'''
for i in range(iteration):
self._one_iteration(input_vecs, labels, rate)
def _one_iteration(self, input_vecs, labels, rate):
'''
一次迭代,把所有的训练数据过一遍
'''
# 把输入和输出打包在一起,成为样本的列表[(input_vec, label), ...]
# 而每个训练样本是(input_vec, label)
samples = zip(input_vecs, labels)
# 对每个样本,按照感知器规则更新权重
# 这里的input_vec就是单个的[1,1],[1,0]什么的,因为遍历了嘛
for (input_vec, label) in samples:
# 计算感知器在当前权重下的输出
output = self.predict(input_vec)
# 更新权重
self._update_weights(input_vec, output, label, rate)
def _update_weights(self, input_vec, output, label, rate):
'''
按照感知器规则更新权重
'''
# 把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,...]打包在一起
# 变成[(x1,w1),(x2,w2),(x3,w3),...]
# 然后利用感知器规则更新权重
delta = label - output
# lambda表达式的用法:lambda+输入变量(必须用括号括起来)+冒号+输出的变量
# map的用法:map(函数,作用函数的输入变量),返回函数的输出
# map和lambda结合使用效率很高
# 这个weight本身就是一个二维的,因此
self.weights = map(
lambda (x, w): w + rate * delta * x,
zip(input_vec, self.weights))
# 更新bias
self.bias += rate * delta
def f(x):
'''
定义激活函数f
'''
return 1 if x > 0 else 0
def get_training_dataset():
'''
基于and真值表构建训练数据
'''
# 构建训练数据
# 输入向量列表
input_vecs = [[1,1], [0,0], [1,0], [0,1]]
# 期望的输出列表,注意要与输入一一对应
# [1,1] -> 1, [0,0] -> 0, [1,0] -> 0, [0,1] -> 0
labels = [1, 0, 0, 0]
return input_vecs, labels
def train_and_perceptron():
'''
使用and真值表训练感知器
'''
# 创建感知器,输入参数个数为2(因为and是二元函数),激活函数为f
p = Perceptron(2, f)
# 训练,迭代10轮, 学习速率为0.1
input_vecs, labels = get_training_dataset()
p.train(input_vecs, labels, 10, 0.1)
#返回训练好的感知器
return p
if __name__ == '__main__':
# 训练and感知器
and_perception = train_and_perceptron()
# 打印训练获得的权重
print and_perception
# 测试
print '1 and 1 = %d' % and_perception.predict([1, 1])
print '0 and 0 = %d' % and_perception.predict([0, 0])
print '1 and 0 = %d' % and_perception.predict([1, 0])
print '0 and 1 = %d' % and_perception.predict([0, 1])