如何实现一个感知器

对于一个进入深度学习的进步菜鸟来说,刚开始的庞大的知识库让我觉得无所适从,但是经过后期的调整和规划,已经决定把从前认为麻烦的事情都要尝试一遍,挖掘一下自身的潜能,送给想要学习或者正在进入学习状态的同志们一句话:无论遇到多大困难,都要平心静气的继续下去,就像此时的我,已经在准备写第二遍(之前第一遍的内容丢失)。相信坚持就是胜利!话不多说,进入正题。

在实现感知器之前,一定要有耐心的看一下感知器的基础理论(两遍最佳,第二遍往往有最深的感悟),推荐官方文档:https://www.zybuluo.com/hanbingtao/note/433855

简单的来说感知器:一个二元分类器,就是把输入向量映射到输出值f(x)(二元的值0或1)上。

当然,对于怎么实现一个感知器,前提是需要有一个非常清楚的思想(编程最重要的就是编程思想,写代码的能力可以慢慢的练习),没有思想无法往下进行。

在构建一个模型之前,我先把涉及到的公式全部写一下(虽然我觉得写起来很麻烦,但是为了清楚的理解每一步需要做什么?为什么要这么做?尤其是后边提到的预测函数和更新权重函数都是要联系公式的)

  1. y=f(Wx+b) W是权值  b是偏置量(bias)→其实可写成y=f(WTx)  因为可以b可以处理成W0*x0
  2. Wi←Wi+ΔWi
  3. b←b+Δb
  4. ΔWi=η(t-y)xi    η是学习率(learning-rate),t是真实值(label),y是预测值(output)
  5. Δb=η(t-y)

现在要进入程序的大门:

  1. 初始化一个感知器:输入参数的个数和激活函数。个人觉得权重向量的初始化应该在一个对称范围内随机取值,比如这样的形式[-1,1],而他的代码中是将权重向量初始化为0,个人觉得这一步不太恰当(后续请教一下师兄,再来更新)
  2. 训练函数:输入训练数据,一组向量、和每个向量对应的label值、训练轮数、学习率。
  3. 迭代函数:一次迭代把所有的训练数据(input_vec,label)过一遍。在感知器规则下更新权重。
  4. 预测函数:输入向量,输出感知结果,也就是y
  5. 更新权重函数的权重:这一步就用到了 湖蓝色标记的公式 。可结合代码和公式加以理解。

涉及到的map()函数的详细用法,请结合官方文档:http://www.runoob.com/python/python-func-map.html

涉及到的lambda匿名函数的用法,结合CSDN上的文档:https://blog.csdn.net/u010602026/article/details/67662004

涉及到的zip()函数的用法,结合 http://www.cnblogs.com/frydsh/archive/2012/07/10/2585370.html

 

  1 #!/usr/bin/env python
  2 # -*- coding: UTF-8 -*-
  3 
  4 import functools as fc
  5 
  6 
  7 class Perceptron(object):
  8     def __init__(self, input_num):
  9         '''
 10         初始化感知器,设置输入参数的个数,以及激活函数。
 11         激活函数的类型为double -> double
 12         '''
 13         #self.activator = activator
 14         # 权重向量初始化为0
 15         self.weights = [0.0 for _ in range(input_num)]
 16         # 偏置项初始化为0
 17         self.bias = 0.0
 18 
 19     def __str__(self):
 20         '''
 21         打印学习到的权重、偏置项
 22         '''
 23         return 'weights\t:%s\nbias\t:%f\n' % (self.weights, self.bias)
 24 
 25     
 26     def predict(self, input_vec):
 27         '''
 28         输入向量,输出感知器的计算结果
 29         '''
 30         # 把input_vec[x1,x2,x3...]和weights[w1,w2,w3,...]打包在一起
 31         #         # 变成[(x1,w1),(x2,w2),(x3,w3),...]
 32         # 然后利用map函数计算[x1*w1, x2*w2, x3*w3]
 33         # 最后利用reduce求和
 34         value = fc.reduce(lambda a, b: a + b, map(lambda x, w: x * w, input_vec, self.weights), 0) + self.bias
 35         return self.f(value)#f是用于计算的激活函数
 36  
 37     def train(self, input_vecs, labels, iteration, rate):
 38         '''
 39         输入训练数据:一组向量、与每个向量对应的label;以及训练轮数、学习率
 40         '''
 41         for i in range(iteration):
 42             self._one_iteration(input_vecs, labels, rate)
 43 
 44     def f(self, x):
 45         '''
 46         定义激活函数f
 47         '''
 48         return 1 if x > 0 else 0
 49 
 50     def _one_iteration(self, input_vecs, labels, rate):
 51         '''
 52         一次迭代,把所有的训练数据过一遍
 53         '''
 54         # 把输入和输出打包在一起,成为样本的列表[(input_vec, label), ...]
 55         # 而每个训练样本是(input_vec, label)
 56         samples = zip(input_vecs, labels)
 57         # 对每个样本,按照感知器规则更新权重
 58         for (input_vec, label) in samples:
 59             # 计算感知器在当前权重下的输出
 60             output = self.predict(input_vec)
 61             # 更新权重
 62             self._update_weights(input_vec, output, label, rate)
 63 
 64     def _update_weights(self, input_vec, output, label, rate):
 65         '''
 66         按照感知器规则更新权重
 67         '''
 68         # 把input_vec[x1,x2,x3,...]和weights[w1,w2,w3,...]打包在一起
 69         # 变成[(x1,w1),(x2,w2),(x3,w3),...]
 70         # 然后利用感知器规则更新权重
 71         delta = label - output
 72         weight_iter = map(
 73             lambda x, w: w + rate * delta * x,
 74             input_vec, self.weights)
 75         # 更新bias
 76         self.weights = [i for i in weight_iter]
 77         self.bias += rate * delta
 78 
 79 
 80 
 81 
 82 
 83 def get_training_dataset():
 84     '''
 85     基于and真值表构建训练数据
 86     '''
 87     # 构建训练数据
 88     # 输入向量列表
 89     input_vecs = [[1,1], [0,0], [1,0], [0,1]]
 90     # 期望的输出列表,注意要与输入一一对应
 91     # [1,1] -> 1, [0,0] -> 0, [1,0] -> 0, [0,1] -> 0
 92     labels = [1, 0, 0, 0]
 93     return input_vecs, labels    
 94 
 95 
 96 def train_and_perceptron():
 97     '''
 98     使用and真值表训练感知器
 99     '''
100     # 创建感知器,输入参数个数为2(因为and是二元函数),激活函数为f
101     p = Perceptron(2)
102     # 训练,迭代10轮, 学习速率为0.1
103     input_vecs, labels = get_training_dataset()
104     p.train(input_vecs, labels, 10, 0.1)
105     #返回训练好的感知器+
106 
107     return p
108 
109 
110 if __name__ == '__main__': 
111     # 训练and感知器
112     and_perception = train_and_perceptron()
113     # 打印训练获得的权重
114     print(and_perception)
115     # 测试
116     print('1 and 1 = %d' % and_perception.predict([1, 1]))
117     print('0 and 0 = %d' % and_perception.predict([0, 0]))
118     print('1 and 0 = %d' % and_perception.predict([1, 0]))
119     print('0 and 1 = %d' % and_perception.predict([0, 1]))

后续新增知识可以返回补充。

原文地址:https://www.cnblogs.com/ttdeveloping/p/9779483.html