使用感知器的Python机器学习简介

58次阅读

共计 4072 个字符,预计需要花费 11 分钟才能阅读完成。

发布于 2016 年 11 月 29 日,2017 年 1 月 19 日更新, 作者: Matthew Corrigan
使用感知器的 Python 机器学习简介

每个熟悉技术的人都听说过机器学习。但都认为必得高智商的数学大师才能搞, 咋也得懂微积分才整机器学习吧。其实没那么难,本文将指导您在没有任何高级数学理论的情况下, 在 Python 中创建感知器,总计也不到 60 行代码。
什么是感知器?
感知器是机器学习和神经网络的基础。你为程序喂一堆输入数据,想个法儿把这些输入数据变成输出数据。通过为每个输入数据分配权重来实现。每个输入乘以该权重,并加在一起。最后,我们需要将该总和转换为二个值之一:1 或 -1。在训练感知器时,我们会评估程序生成的输出,并根据输入和应该输出的内容调整权重。实际上,感知器可以帮助我们对数据进行分类。如果这个解释让你感到困惑,请不要担心,当我们开始编码时你就会明白了。
编码感知器类
我们应该从创建一个感知器类开始。在初始化函数中,我们想要初始化我们的权重,每个权重是从 - 1 到 1 之间的随机数。为了生成随机数,我们将使用 random.random(),它返回 0 到 1 之间的数字。
  import random
  
  class Perceptron:
  
    def __init __(self, learn_speed, num_weights):
    
      self.speed = learn_speed
    
      self.weights = []
      for x in range(0, num_weights):
        self.weights.append(random.random()* 2-1)
        第一个参数 learn_speed 用于控制感知器学习的速度。值越低,学习的时间越长,但每个数据对总体权重的值改变就越小。如果此参数太高,我们的程序将很快改变其权重,使其不准确。另一方面,如果 learn_speed 太低,则因为精度问题永远也无法完成感知器的训练。该参数的值约为 0.01-0.05 时比较合适。
第二个参数 num_weights 控制感知器将具有多少个权重值。我们的感知器也将具有与权重相同的输入数量,因为每个输入都有自己对应的权重值。
接下来,我们需要在类中创建一个函数来接收输入,并将它们转换为输出。我们通过将每个输入乘以其相应的权重,将所有这些加在一起,然后检查总和是否大于 0 来完成此操作。在您的 perceptron 类中,在__init__函数之后添加此代码:
  def feed_forward(self, inputs):
      sum = 0
      #权重乘以输入并求和
      for x in range(0, len(self.weights)):
        sum + = self.weights[x] * inputs[x]
      #返回 ’ 激活 ’ 总和
      return self.activate(sum)
      
    def activate(self, num):
      #将大于 0 之和转为 1,低于 0 转为 -1
      if num> 0:
        return 1
      return -1
上面的代码是我们感知器的基础。如果您能够很好地理解这些代码,那么您对机器学习的基础知识已有了一个飞跃。让我们一块一块地剖析这段代码。
第一个函数 feed_forward 用于将输入转换为输出。术语前馈通常用于神经网络,以描述将输入转换为输出的过程。该方法基于每个对应的权重对每个输入进行加权并求和,然后使用 activate 函数返回 1 或 -1。
activate 函数用于将数字转换为 1 或 -1。这是因为当我们使用感知器时,我们想要对数据进行分类。我们将它分为两​​组,其中一组用 1 表示,另一组用 - 1 表示。
你可能想知道,“如果权重是随机的,那有什么用?”这就是我们在使用之前必须训练感知器的原因。在我们的训练函数中,我们希望根据提供的输入进行猜测,然后看看我们的猜测与我们想要的输出相比如何。感知器类的训练函数如下所示。
  def train(self,inputs,desired_output):
      guess = self.feed_forward(inputs)
      error = desired_output – guess
      
      for x in range(0, len(self.weights)):
        self.weights[x] + = error * inputs[x] * self.speed
        前几行中的大多数都应该有意义。我们的函数接受输入,以及当我们通过程序运行输入时应该发生的输出。我们使用 feed_forward 函数猜测输入,然后根据我们应该输出的内容计算出错误。请注意,如果我们正确预测,则错误将等于 0,并且函数的最后一行根本不会改变我们的权重。
这个功能的最后两行是多汁的部分 – 他们把学习放在机器学习中。我们遍历每个重量并根据我们有多少错误来调整它。请注意,我们在这里使用 self.speed 变量,它决定了感知器学习的速度。通过在一堆输入及其输出上运行此训练函数,我们最终可以教我们的感知器获得正确的输出。
训练感知器
如果我们不实际训练它们,我们的感知器就没用了。我们将通过编写快速 Trainer 类来完成此操作。在这个例子中,我们将训练我们的感知器, 使其能分辨一个点是在一条线之上还是在一条线之下。我们的线由方程 y = 0.5x + 10 表示。一旦您知道如何训练感知器来识别线,您可以将 x 和 y 表示为不同的属性,在线的上方或下方作为这些属性的运算结果。
例如,如果您有关于哈佛大学申请人的 GPA 和 ACT 分数的数据集,以及他们是否被接受,您可以训练感知器在图表上找到 x = GPA 分数和 y = ACT 分数的线。在线以上将是被接受的学生,并且在线以下将是被拒绝的学生。然后,您可以使用此感知器来预测学生是否会根据他们的 GPA 和 ACT 分数被哈佛大学录取。
在这个例子中,我们将继续去识别一条线。为此,我们将创建一个 Trainer 类,用于训练感知器的点数,以及它们是否在线上。以下是我们的 Trainer 类的代码:
class Trainer:

def __init__(self):
self.perceptron = Perceptron(0.01, 3)

def f(self, x):
return 0.5*x + 10 # line: f(x) = 0.5x + 10

def train(self):
for x in range(0, 1000000):
x_coord = random.random()*500-250
y_coord = random.random()*500-250
line_y = self.f(x_coord)

if y_coord > line_y: # 在线上方
answer = 1
self.perceptron.train([x_coord, y_coord, 1], answer)
else: # 在线下​​面
answer = -1
self.perceptron.train([x_coord, y_coord, 1], answer)
return self.perceptron # 返回我们训练有素的感知器    
      正如您所看到的,Trainer 类的初始化程序创建了一个具有三个输入且学习速度为 0.01 的感知器。前两个输入是 x 和 y,但最后一个输入是什么?这是神经网络和机器学习的另一个核心概念。最后一个输入将始终设置为 1. 与其对应的权重将决定它对我们的线的影响。例如,如果你回顾我们的等式:y = 0.5x + 10,我们需要某种方式来表示 y 轴截距 10. 我们通过创建第三个输入来实现这一点,该输入需要根据感知器的权重增加或减少。将其视为一个阈值,帮助感知器理解线需要向上调整 10 个单位。
在我们的 f 函数中,我们接受一个 x 坐标并返回一个 y 坐标。根据 x 坐标在线上找到点,这将在下一个函数中派上用场。
Trainer 类的这个训练函数是所有魔法发生的地方,我们实际上是训练我们的感知器。我们开始循环 100 万次。还记得我们的感知器学习速度吗?我们训练感知器的次数越多(在这种情况下,100 万次),即使学习速度很低,它也会越准确。
在循环的每次迭代中,我们创建一个点,确定它是否在线的上方或下方,然后将这些输入馈送到感知器的训练函数中。首先,在 -250 和 250 之间随机生成 x 和 y 坐标。接下来,我们找到 y 坐标在该 x 行的线上的位置,以查看我们的点是否在线上方。例如,如果我们在(1,3)处选择一个点,那么我们应该获得 x 值为 3 的线上的点的 y 坐标。我们使用 f 函数执行此操作。如果我们的随机 y 坐标值高于线上对应的 y 坐标值,我们知道随机坐标在线上方。
这就是我们在 if … else 语句中所做的。如果点在线上方,我们设置预期输出,存储在 answer 中为 1. 如果点低于该线,则我们的预期输出为 -1。然后根据 x,y 坐标和我们的预期输出训练我们的感知器。整个循环完成后,返回新训练的感知器对象。
运行程序
为了运行程序,我们创建一个 training 对象,并调用它的.train()方法。
trainer = Trainer()
p = trainer.train()
现在是荣耀的时刻; 我们运行该程序。让我们选择两点,(– 7,9)和(3,1)。第一个点在线上方,所以它应该返回 1,第二个点在线下面,所以它应该返回 -1。让我们看看我们如何运行我们的感知器:
print “(-7, 9): ” + p.feed_forward([-7,9,1])
print “(3, 1): ” + p.feed_forward([3,1,1])
如果我们运行它会输出:
(-7, 9): 1 (3, 1): -1
成功!我们的程序检测到每个点是在线之上还是之下。您可以尝试更多的点来自己测试程序是否正常运行。
小结
本文旨在帮助您了解机器学习的一些基础知识; 具体而言,神经网络。如果您想深入研究这个主题,请查看以下链接:
神经网络简介斯坦福大学的免费机器学习课程纳米级机器学习

正文完
 0