4

发布于2016年11月29日,2017年1月19日更新, 作者: Matthew Corrigan

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

eRhUjZVQSqKrZAjdy50J

每个熟悉技术的人都听说过机器学习。但都认为必得高智商的数学大师才能搞, 咋也得懂微积分才整机器学习吧。其实没那么难,本文将指导您在没有任何高级数学理论的情况下, 在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

成功! 我们的程序检测到每个点是在线之上还是之下。 您可以尝试更多的点来自己测试程序是否正常运行。

小结

本文旨在帮助您了解机器学习的一些基础知识; 具体而言,神经网络。 如果您想深入研究这个主题,请查看以下链接:

神经网络简介
斯坦福大学的免费机器学习课程
纳米级机器学习


Yujiaao
12.7k 声望4.7k 粉丝

[链接]