如何用 Python 从零开始实现感知机算法

感知器算法是最简单的人工神经网络类型。

它是一个单神经元模型,可用于两类分类问题,并为以后开发更大的网络奠定基础。

在本教程中,您将学习如何从头开始使用 Python 实现感知器算法。

完成本教程后,您将了解:

  • 如何训练感知器的网络权重。
  • 如何使用感知器进行预测。
  • 如何将感知器算法应用于现实世界的分类问题。

通过我的新书 《从零开始的机器学习算法》来启动您的项目,书中包含分步教程和所有示例的Python 源代码文件。

让我们开始吧。

  • 更新于 2017 年 1 月:更改了 `cross_validation_split()` 中 `fold_size` 的计算,使其始终为整数。修复了 Python 3 的问题。
  • 2018 年 8 月更新:测试并更新以与 Python 3.6 配合使用。
How To Implement The Perceptron Algorithm From Scratch In Python

如何用 Python 从零开始实现感知机算法
照片由 Les Haines 提供,部分权利保留。

描述

本节将简要介绍感知器算法以及我们之后将应用它的声纳数据集。

感知器算法

感知器受到称为神经元的单个神经细胞信息处理的启发。

神经元通过其树突接收输入信号,这些信号将电信号传递到细胞体。

以类似的方式,感知器从我们加权并在线性方程(称为激活)中组合的训练数据样本接收输入信号。

然后使用传递函数(例如阶跃传递函数)将激活转换为输出值或预测。

这样,感知器就是一种分类算法,适用于二分类问题(0 和 1),其中可以使用线性方程(如超平面)来分隔这两个类。

它与线性回归和逻辑回归密切相关,它们以类似的方式进行预测(例如,输入的加权和)。

感知器算法的权重必须使用随机梯度下降从训练数据中估计。

随机梯度下降

梯度下降是通过沿着成本函数的梯度来最小化函数的过程。

这涉及知道成本的形式以及其导数,以便从给定点知道梯度并可以朝该方向移动,例如朝向最小值向下移动。

在机器学习中,我们可以使用一种称为随机梯度下降的技术,该技术在每次迭代时评估和更新权重,以最小化模型在我们训练数据上的误差。

这种优化算法的工作方式是,每个训练实例都被逐一展示给模型。模型对训练实例进行预测,计算误差,然后更新模型以减小下一次预测的误差。

此过程可用于查找模型中导致模型在训练数据上误差最小的权重集。

对于感知器算法,每次迭代时,权重(w)都会使用以下方程进行更新

其中 w 是正在优化的权重,learning_rate 是您必须配置的学习率(例如 0.01),(expected – predicted) 是模型在训练数据上由权重归因的预测误差,x 是输入值。

声纳数据集

本教程中将使用的数据集是声纳数据集。

这是一个描述声纳啁啾回波反弹到不同服务的数据集。 60 个输入变量是不同角度的回波强度。这是一个二分类问题,需要模型区分岩石和金属圆柱体。

这是一个经过充分研究的数据集。所有变量都是连续的,通常在 0 到 1 的范围内。因此,我们不必对输入数据进行归一化,这通常是感知器算法的一个好做法。输出变量是字符串“M”(矿)和“R”(岩石),需要将其转换为整数 1 和 0。

通过预测数据集中观测值最多的类别(M 或地雷),零规则算法可以达到 53% 的准确率。

您可以在 UCI 机器学习库 上了解有关此数据集的更多信息。您可以免费下载数据集,并将其放入工作目录中,文件名设置为 sonar.all-data.csv

教程

本教程分为 3 部分

  1. 进行预测。
  2. 训练网络权重。
  3. 建模声纳数据集。

这些步骤将为您提供基础,以便您能够实现感知器算法并将其应用于您自己的分类预测建模问题。

1. 进行预测

第一步是开发一个能够进行预测的函数。

这在随机梯度下降中评估候选权重值时以及在模型最终确定后我们希望开始对测试数据或新数据进行预测时都需要。

下面是一个名为 predict() 的函数,它在给定一组权重的情况下预测某一行输出值。

第一个权重始终是偏置,因为它独立存在,不负责特定的输入值。

我们可以设计一个小型数据集来测试我们的预测函数。

我们也可以使用之前准备好的权重来为这个数据集进行预测。

将所有内容放在一起,我们可以在下面测试我们的 predict() 函数。

有两个输入值(X1X2)和三个权重值(biasw1w2)。我们为这个问题建模的激活方程是

或者,使用我们手动选择的特定权重值,为

运行此函数,我们得到的预测与预期输出(y)值匹配。

现在我们准备实现随机梯度下降来优化我们的权重值。

2. 训练网络权重

我们可以使用随机梯度下降来估计我们训练数据的权重值。

随机梯度下降需要两个参数

  • 学习率:用于限制每次更新权重时权重的大小。
  • 周期:在更新权重时遍历训练数据的次数。

这些参数以及训练数据将是函数的参数。

函数中需要进行 3 次循环

  1. 遍历每个周期。
  2. 遍历训练数据中的每一行以进行一个周期。
  3. 遍历每个权重并为一个周期中的一行更新它。

可以看出,我们在每个周期中为训练数据中的每一行更新每个权重。

权重是根据模型犯的错误来更新的。错误计算为预期输出值与使用候选权重进行的预测之间的差值。

每个输入属性都有一个权重,并且这些权重以一致的方式更新,例如

偏置的更新方式类似,只是没有输入,因为它不与特定输入值相关

现在我们可以将所有内容放在一起。下面是一个名为 train_weights() 的函数,它使用随机梯度下降来计算训练数据集的权重值。

您可以看到,我们还跟踪了每个周期的均方误差(一个正值),以便在每个外部循环中打印出有用的消息。

我们可以对上面相同的、经过设计的示例数据集进行测试。

我们使用 0.1 的学习率,并将模型训练 5 个周期,即权重暴露给整个训练数据集 5 次。

运行示例将打印每个周期的消息,其中包含该周期的均方误差和最终权重集。

您可以看到该算法是如何非常快速地学习该问题的。

现在,让我们将此算法应用于真实数据集。

3. 建模声纳数据集

在本节中,我们将使用随机梯度下降在声纳数据集上训练感知器模型。

该示例假设数据集的 CSV 副本位于当前工作目录中,文件名为 sonar.all-data.csv

首先加载数据集,将字符串值转换为数字,并将输出列从字符串转换为 0 到 1 的整数值。这是通过辅助函数 load_csv()str_column_to_float()str_column_to_int() 来加载和准备数据集来实现的。

我们将使用 k 折交叉验证来估计学习模型在未见过数据上的性能。这意味着我们将构造和评估 k 个模型,并将性能估计为平均模型误差。分类准确率将用于评估每个模型。这些行为由 cross_validation_split()accuracy_metric()evaluate_algorithm() 辅助函数提供。

我们将使用上面创建的 predict()train_weights() 函数来训练模型,并使用新的 perceptron() 函数将它们联系起来。

下面是完整的示例。

A k value of 3 was used for cross-validation, giving each fold 208/3 = 69.3 or just under 70 records to be evaluated upon each iteration. A learning rate of 0.1 and 500 training epochs were chosen with a little experimentation.

You can try your own configurations and see if you can beat my score.

Running this example prints the scores for each of the 3 cross-validation folds then prints the mean classification accuracy.

We can see that the accuracy is about 72%, higher than the baseline value of just over 50% if we only predicted the majority class using the Zero Rule Algorithm.

扩展

This section lists extensions to this tutorial that you may wish to consider exploring.

  • Tune The Example. Tune the learning rate, number of epochs and even data preparation method to get an improved score on the dataset.
  • Batch Stochastic Gradient Descent. Change the stochastic gradient descent algorithm to accumulate updates across each epoch and only update the weights in a batch at the end of the epoch.
  • Additional Regression Problems. Apply the technique to other classification problems on the UCI machine learning repository.

您是否探索过这些扩展?
Let me know about it in the comments below.

回顾

In this tutorial, you discovered how to implement the Perceptron algorithm using stochastic gradient descent from scratch with Python.

You learned.

  • How to make predictions for a binary classification problem.
  • How to optimize a set of weights using stochastic gradient descent.
  • How to apply the technique to a real classification predictive modeling problem.

你有什么问题吗?
在下面的评论中提出您的问题,我将尽力回答。

了解如何从零开始编写算法!

Machine Learning Algorithms From Scratch

没有库,只有 Python 代码。

...附带真实世界数据集的逐步教程

在我的新电子书中探索如何实现
从零开始实现机器学习算法

它涵盖了 18 个教程,包含 12 种顶级算法的所有代码,例如
线性回归、k-近邻、随机梯度下降等等……

最后,揭开
机器学习算法的神秘面纱

跳过学术理论。只看结果。

查看内容

170 Responses to How To Implement The Perceptron Algorithm From Scratch In Python

  1. Philip Brierley November 2, 2016 at 7:07 am #

    There is a derivation of the backprop learning rule at http://www.philbrierley.com/code.html and also similar code in a bunch of other languages from Fortran to c to php.

    With help we did get it working in Python, with some nice plots that show the learning proceeding.

    https://github.com/gavrol/NeuralNets

    • Jason Brownlee November 2, 2016 at 9:10 am #

      Thanks for sharing Philip.

      • Misge November 4, 2016 at 3:44 pm #

        Sorry to bother you but I want to understand whats wrong in using your code? I think you also used someone else’s code right? At least you read and reimplemented it. I hope my question will not offend you.

        • Jason Brownlee November 5, 2016 at 7:28 am #

          I wrote the code from scratch myself.

          The code works, what problem are you having exactly?

        • Mohsin July 10, 2019 at 1:40 am #

          Thanks it worked for me with python3.7

        • anjali September 12, 2019 at 8:17 pm #

          很好

    • hinna September 15, 2018 at 10:30 pm #

      sir I used ,
      dataset=[[1,1,6,1],
      [1,7,2,1],
      [1,8,9,1],
      [1,9,9,1],
      [1,4,8,1],
      [1,8,5,1],
      [1,2,1,0],
      [1,3,3,0],
      [1,2,4,0],
      [1,7,1,0],
      [1,1,3,0],
      [1,5,2,1]
      ]
      this dataset and code was
      # Make a prediction with weights
      def predict(row, weights)
      activation = weights[0]
      for i in range(len(row)-2)
      activation += weights[i + 1] * row[i+1]
      return 1.0 if activation >= 0.0 else 0.0

      # Estimate Perceptron weights using stochastic gradient descent

      def train_weights(train, l_rate, n_epoch)
      weights = [0.0 for i in range(len(train[0]))]
      for epoch in range(n_epoch)
      print(“Epoch no “,epoch)
      for row in train
      print(“\n\nrow is “,row)
      print(weights)
      prediction = predict(row, weights)
      error = row[-1] – prediction
      weights[0] = weights[0] + l_rate * error
      for i in range(len(row)-2)
      weights[i + 1] = weights[i + 1] + l_rate * error * row[i+1]
      return weights

      # Perceptron Algorithm With Stochastic Gradient Descent
      def perceptron(train,l_rate, n_epoch)
      predictions = list()
      weights = train_weights(train, l_rate, n_epoch)
      for row in train
      prediction = predict(row, weights)
      predictions.append(prediction)
      return(predictions)

      p=perceptron(dataset,l_rate,n_epoch)
      print(p)
      but output m getting is biased for the last entry of my dataset…so code not working well on this dataset 🙁

      • Jason Brownlee September 16, 2018 at 6:01 am #

        Perhaps use Keras instead, this code is for learning how perceptron works rather than for solving problems.

  2. Andre Logunov November 3, 2016 at 12:06 pm #

    你好,Jason!

    A very informative web-site you’ve got! I’m thinking of making a compilation of ML materials including yours. I wonder if I could use your wonderful tutorials in a book on ML in Russian provided of course your name will be mentioned? It’s just a thought so far.

    • Jason Brownlee November 4, 2016 at 9:03 am #

      No Andre, please do not use my materials in your book.

  3. Stefan November 4, 2016 at 3:12 am #

    Thanks for the interesting lesson. I’m reviewing the code now but I’m confused, where are the train and test values in the perceptron function coming from? I can’t find their origin.

    • Stefan Lop November 4, 2016 at 6:38 am #

      I’m also receiving a ValueError(“empty range for randrange()”) error, the script seems to loop through a couple of randranges in the cross_validation_split function before erroring, not sure why. Was the script you posted supposed to work out of the box? Because I cannot get it to work and have been using the exact same data set you are working with.

      • Jason Brownlee November 4, 2016 at 11:15 am #

        Hi Stefan, sorry to hear that you are having problems.

        Yes, the script works out of the box on Python 2.7.

        Perhaps there was a copy-paste error?
        Perhaps you are on a different platform like Python 3 and the script needs to be modified slightly?

        Are you able to share more details?

        • Stefan November 5, 2016 at 12:15 am #

          Was running Python 3, works fine in 2 haha thanks!

          • Jason Brownlee November 5, 2016 at 7:28 am #

            很高兴听到这个消息。

      • Jason Brownlee January 3, 2017 at 9:52 am #

        我已经更新了上面示例中的 cross_validation_split() 函数,以解决 Python 3 的问题。

    • Jason Brownlee November 4, 2016 at 9:13 am #

      In the full example, the code is not using train/test nut instead k-fold cross validation, which like multiple train/test evaluations.

      Learn more about the test harness here
      https://machinelearning.org.cn/create-algorithm-test-harness-scratch-python/

      • Stefan November 5, 2016 at 12:22 am #

        But the train and test arguments in the perceptron function must be populated by something, where is it? I can’t find anything that would pass a value to those train and test arguments.

        • Jason Brownlee November 5, 2016 at 7:31 am #

          Hi Stefan,

          The train and test arguments come from the call in evaluate_algorithm to algorithm() on line 67.

          Algorithm is a parameter which is passed in on line 114 as the perceptron() function.

          So, this means that each loop on line 58 that the train and test lists of observations come from the prepared cross-validation folds.

          To deeply understand this test harness code see the blog post dedicated to it here
          https://machinelearning.org.cn/create-algorithm-test-harness-scratch-python/

          • Stefan November 8, 2016 at 1:42 am #

            Oh boy, big time brain fart on my end I see it now. Thanks so much for your help, I’m really enjoying all of the tutorials you have provided so far.

          • Jason Brownlee November 8, 2016 at 9:54 am #

            I’m glad to hear you made some progress Stefan.

  4. Amita misra November 12, 2016 at 6:34 pm #

    Thanks for such a simple and basic introductory tutorial for deep learning. I had been trying to find something for months but it was all theano and tensor flow and left me intimidating. This is really a good place for a beginner like me.

  5. vedhavyas November 20, 2016 at 10:42 pm #

    嗨,Jason,

    Implemented in Golang. Here are my results

    Id 2, predicted 53, total 70, accuracy 75.71428571428571
    Id 1, predicted 53, total 69, accuracy 76.81159420289855
    Id 0, predicted 52, total 69, accuracy 75.36231884057972
    mean accuracy 75.96273291925466

    no. of folds: 3
    learningRate: 0.01
    epochs: 500

    • Jason Brownlee November 22, 2016 at 6:48 am #

      Very nice work vedhavyas!

      Do you have a link to your golang version you can post?

  6. Tim November 22, 2016 at 8:32 pm #

    嗨,Jason!

    Thanks for the great tutorial! A ‘from-scratch’ implementation always helps to increase the understanding of a mechanism.

    I have a question though: I thought to have read somewhere that in ‘stochastic’ gradient descent, the weights have to be initialised to a small random value (hence the “stochastic”) instead of zero, to prevent some nodes in the net from becoming or remaining inactive due to zero multiplication. I see in your gradient descent algorithm, you initialise the weights to zero. Could you elaborate some on the choice of the zero init value? My understanding may be incomplete, but this question popped up as I was reading.

    谢谢!

    • Jason Brownlee November 23, 2016 at 8:57 am #

      This can help with convergence Tim, but is not strictly required as the example above demonstrates.

      • Tim November 23, 2016 at 7:40 pm #

        Thanks Jason! That clears it up!

  7. kero hakem December 22, 2016 at 1:55 am #

    Thanks for the great tutorial! but how i can use this perceptron in predicting multiple classes

  8. PN February 22, 2017 at 5:52 am #

    Thanks for your great website. I use part of your tutorials in my machine learning class if it’s allowed.

  9. Aniket Saxena March 20, 2017 at 3:01 am #

    Hello Sir, please tell me to visualize the progress and final result of my program, how I can use matplotlib to output an image for each iteration of algorithm.

    • Jason Brownlee March 20, 2017 at 8:17 am #

      You could create and save the image within the epoch loop.

  10. Aniket Saxena March 22, 2017 at 1:20 am #

    Hello Sir, as i have gone through the above code and found out the epoch loop in two functions like in def train_weights and def perceptron and since I’m a beginner in machine learning so please guide me how can i create and save the image within epoch loop to visualize output of perceptron algorithm at each iteration

    • Jason Brownlee March 22, 2017 at 8:08 am #

      Sorry, I do not have an example of graphing performance. Consider using matplotlib.

  11. Sahiba March 24, 2017 at 4:43 am #

    嗨,Jason,

    Thank you for this explanation. I have a question – why isn’t the bias updating along with the weights?

  12. Aniket Saxena March 29, 2017 at 4:33 am #

    你好 Jason,
    Here in the above code i didn’t understand few lines in evaluate_algorithm function. Please guide me why we use these lines in train_set and row_copy.

    train_set.remove(fold)
    train_set = sum(train_set, [])

    and,

    row_copy[-1] = None

    • Jason Brownlee March 29, 2017 at 9:11 am #

      We clear the known outcome so the algorithm cannot cheat when being evaluated.

  13. Aniket Saxena March 29, 2017 at 1:13 pm #

    先生,
    One more question that after assigning row_copy in test_set, why do we set the last element of row_copy to None, i.e.,
    row_copy[-1] = None

    • Jason Brownlee March 30, 2017 at 8:46 am #

      So that the outcome variable is not made available to the algorithm used to make a prediction.

  14. Aniket Saxena March 31, 2017 at 2:11 am #

    And there is a question that the lookup dictionary’s value is updated at every iteration of for loop in function str_column_to_int() and that we returns the lookup dictionary then why we use second for loop to update the rows of the dataset in the following lines
    for i, value in enumerate(unique)
    lookup[value] = i
    for row in dataset
    row[column] = lookup[row[column]]
    return lookup

    Does it affect the dataset values after having passed the lookup dictionary and if yes, does the dataset which have been passed to the function evaluate_algorithm() may also alter in the following function call statement

    scores = evaluate_algorithm(dataset, perceptron, n_folds, l_rate, n_epoch)

  15. Michel May 17, 2017 at 7:17 am #

    Hello, I would like to understand 2 points of the code?
    1 ° because on line 10, you use train [0]?
    2 ° According to the formula of weights, w (t + 1) = w (t) + learning_rate * (expected (t) – predicted (t)) * x (t), then because it used in the code “weights [i + 1 ] = Weights [i + 1] + l_rate * error * row [i] “,
    Where does this plus 1 come from in the weigthts after equality?

    • Jason Brownlee May 17, 2017 at 8:44 am #

      Because the weight at index zero contains the bias term.

      • Michel May 25, 2017 at 2:36 am #

        Sorry, I still do not get it. Can you explain it a little better?

  16. Sri June 4, 2017 at 3:36 pm #

    Hi, I just finished coding the perceptron algorithm using stochastic gradient descent, i have some questions

    1) 当我用学习率为 0.1、训练周期数为 500 的感知器在整个声纳数据集上进行训练,目标是达到最小的“预测平方误差之和”时,误差卡在了 40。

    我该如何最小化这个误差?

    2) 这个问题是关于 k 折交叉验证测试的。在一个 k 折上训练的模型,其泛化能力一定不如在整个数据集上训练的模型。如果这是真的,那么 k 折交叉验证测试的有效性如何?

    3) 找到“学习率”和“训练周期数”的最佳组合,似乎是学习过程的真正诀窍。如何找到这个最佳组合?

  17. Vaibhav Rai 2017 年 7 月 18 日下午 5:44 #

    老师您好!
    您能帮我解决 randrange 函数中的一个错误吗?
    ValueError: randrange() 的范围为空

    • Jason Brownlee 2017 年 7 月 19 日上午 8:21 #

      这可能是 Python 2 与 Python 3 的问题。我在开发示例时使用的是 Python 2。

      • Vaibhav Rai 2017 年 7 月 19 日下午 4:07 #

        实际上,我将 cross_validation_split 中的 mydata_copy 改成了 mydata 来修正那个错误,但现在出现了 KeyError: 137。

        • Jason Brownlee 2017 年 7 月 19 日下午 4:11 #

          您能否提供更多关于您的环境(Python 版本)和错误(完整的追溯信息)的信息?

          • Vaibhav Rai 2017 年 7 月 19 日下午 5:13 #

            老师,我的 Python 版本是 3.6,错误是:
            KeyError: 137

          • Jason Brownlee 2017 年 7 月 20 日上午 6:17 #

            抱歉,该示例是为 Python 2.7 开发的。

            我相信代码需要修改才能在 Python 3 中运行。

  18. Vaibhav Rai 2017 年 7 月 21 日下午 4:38 #

    您能告诉我,除了 randrange 之外,还有什么其他函数可以用于生成索引吗?

  19. Alex Godfrey 2017 年 8 月 29 日上午 12:31 #

    仅略高于 50% 的基线值是如何得出的?

  20. Carla Meyer Castro 2017 年 9 月 28 日上午 4:24 #

    您好,我有一个关于这个函数的问题:

    # 将字符串列转换为浮点数
    def str_column_to_float(dataset, column)
    for row in dataset
    row[column] = float(row[column].strip())

    它返回什么?

    • Jason Brownlee 2017 年 9 月 28 日上午 5:28 #

      不返回任何内容,它直接修改提供的列。

  21. Dhruv 2017 年 10 月 31 日下午 2:53 #

    我想通过将一行与文件中的所有其他行进行比较来查找相似的记录。应该如何使用 sklearn 和 Python 来实现?请帮帮我。

    • Jason Brownlee 2017 年 10 月 31 日下午 2:59 #

      也许你可以计算行之间的欧几里得距离。

      你可能需要自己用 Python 实现。

  22. Deva 2017 年 11 月 3 日上午 12:11 #

    row[column]=float(row[column].strip()) 产生了错误:
    ValueError : could not string to float : R

    • Jason Brownlee 2017 年 11 月 3 日上午 5:19 #

      很抱歉听到这个消息,您是否完全按照帖子中的代码和数据进行了操作?

  23. Olu 2018 年 3 月 20 日晚上 10:07 #

    如何在不使用 Keras 库的情况下将此代码扩展到循环神经网络?

  24. Bala 2018 年 4 月 6 日下午 3:32 #

    嗨,Jason,
    这是一篇非常棒且详细的文章。
    我只是想问一下,当我运行您的代码时,我的准确率和数值略有不同,也就是说,我得到了大约 74.396% 的准确率,而且每次我重新运行时数值也会稍微改变。有时我也会达到 75%。
    为什么会这样?
    我的逻辑是,因为 k 折交叉验证随机创建了 3 个数据集划分,所以它的学习依赖于此,因为测试数据是随机变化的。我的逻辑正确吗?
    谢谢 Jason。

  25. Martin 2018 年 4 月 30 日晚上 11:51 #

    你好 Jason,
    非常好的教程,它真的帮助我理解了感知器背后的思想!但我的问题是,这与普通的梯度下降有什么不同?我看不到随机部分在哪里?您难道不应该对数据集进行采样并对子集执行计算吗?

    提前感谢,
    马丁

    • Jason Brownlee 2018 年 5 月 1 日上午 5:34 #

      梯度下降只是优化算法。

      在这里,我们将其应用于求解感知器权重。

  26. Ravi 2018 年 6 月 25 日上午 9:49 #

    在“训练网络权重”中
    公式定义为
    w(t+1) = w(t) + learning_rate * learning_rate *(expected(t)- predicted(t)) * x(t)
    bias(t+1) = bias(t) + learning_rate *(expected(t)- predicted(t)) * x(t)

    所以 t=0, w(1) = w(0) + learning_rate * learning_rate *(expected(0)- predicted(0)) * x(0)
    这与“train_weights”函数中的代码相冲突。

    在“train_weights”函数中
    以下截图:
    # Estimate Perceptron weights using stochastic gradient descent
    def train_weights(train, l_rate, n_epoch)
    weights = [0.0 for i in range(len(train[0]))]
    for epoch in range(n_epoch)
    for row in train
    prediction = predict(row, weights)
    error = row[-1] – prediction
    weights[0] = weights[0] + l_rate * error
    for i in range(len(row)-1)
    weights[i + 1] = weights[i + 1] + l_rate * error * row[i]
    return weights

    问题
    迭代 1: (i=0)
    for i in range(len(row)-1)
    weights[i + 1] = weights[i + 1] + l_rate * error * row[i]
    那么,weights[0 + 1] = weights[0 + 1] + l_rate * error * row[0] (即 weights[1] = weights[1] + l_rate * error * row[0]),我们需要考虑 weights[1] 和 row[0] 来计算 weights[1] 吗?(而不是 weights[1] 和 row[1] 来计算 weights[1])
    困惑的是 row[0] 用于计算 weights[1]。

    根据“训练网络权重”中提到的公式,我的理解是:

    weights[0] = 偏置项
    但必须遵循公式模式。

    weights[1] = weights[0] + l_rate * error * row[0]
    weights[2] = weights[1] + l_rate * error * row[1]

    而不是 ('train_weights')
    weights[1] = weights[1] + l_rate * error * row[0]
    weights[2] = weights[2] + l_rate * error * row[1]

    我请求您解释为什么在“train_weights”函数中会有所不同?

  27. Ben Hine 2018 年 7 月 20 日上午 10:14 #

    喜欢您的教程。我有一个小小的疑问。为什么您要在权重更新公式中包含 x?也就是说,如果您包含 x,那么“权重更新”就不准确了。它应该被称为输入更新公式?我在这里说错了什么吗?谢谢。

    • Jason Brownlee 2018 年 7 月 21 日上午 6:28 #

      我们正在改变/更新模型的权重,而不是输入。输入是不可变的。因此,这是一个权重更新公式。

  28. Ben Hine 2018 年 7 月 21 日晚上 10:41 #

    谢谢您的回复。我猜我很难理解 X 在公式中扮演的角色。另外,关于您“人为构造”的数据集……您是如何得到的?您是否随机生成 x1 和 x2 值,然后任意分配零和一作为输出,然后使用神经网络来确定适当的权重以满足“期望”输出,并以给定的偏置和权重作为起点?

    • Jason Brownlee 2018 年 7 月 22 日上午 6:24 #

      网络学习一组能够正确地将输入映射到输出的权重。

      这是所有神经网络的基础。

  29. Ben Hine 2018 年 7 月 22 日中午 12:10 #

    我可能没有正确地表述我的问题,但谢谢。我想我现在明白了变量 x 在权重更新公式中所起的作用。在我深入讨论之前,让我分享一下我认为神经网络即使没有它也能学习。来了:1. 零和一之间的差值总是 1、0 或 -1。权重将以差值、学习率和输入变量的乘积因子递增。如果我们省略输入变量,增量值将仅以差值和学习率的乘积因子变化,所以它不会破坏神经元更新权值的能力。所以我并不真正需要输入变量。也许有一个充分的理由?我看到的可能的一个原因是,如果输入值总是大于神经网络数据集中的权重,那么它的作用就是使更新值变大,因为输入值总是大于 1。如果这很明显,请原谅我,但我一开始没看到,但我喜欢了解公式中所有组件的用途。谢谢。您的代码很有趣。到目前为止一切顺利!

  30. Ben Hine 2018 年 7 月 24 日下午 3:34 #

    抱歉,如果我的上一个问题太拗口难以理解,但我不知道您是否同意,您的代码中的权重公式不需要输入 x。总之,代码在 Python 3.6(Jupyter Notebook)中可以正常运行,并且没有进行任何更改,我的数字是:

    分数:[81.15942028985508, 69.56521739130434, 62.31884057971014]
    平均准确率:71.014%

    我会尝试调整参数并反馈,看看是否能有所改进。我个人不认为 71.014% 会让扫雷经理非常有信心。

    • Jason Brownlee 2018 年 7 月 25 日上午 6:11 #

      如果您从方程中移除 x,您将不再拥有感知器更新算法。如果您对此有效,那就没关系。

  31. Ben Hine 2018 年 7 月 25 日下午 2:00 #

    这对像我这样刚开始了解感知器的人来说真是太棒的代码。我想指出的是,对于绝对初学者来说,代码中的
    lookup[value] = i 有点令人费解,而且可能令人困惑。如您所知,“lookup”被定义为一个字典,字典以键值对的形式存储数据。但这段代码实际上是将变量“value”(“R”和“M”)指定为键,将“i”(0、1)指定为值。我只是觉得值得注意。请不要恨我:)。我永远无法自己写出这个。

    • Jason Brownlee 2018 年 7 月 25 日下午 2:41 #

      谢谢您的提醒,Ben,抱歉我没有解释清楚。

      • Ben Hine 2018 年 7 月 26 日中午 12:26 #

        没关系。

  32. Ben Hine 2018 年 7 月 26 日中午 12:26 #

    Jason,您的代码有很多值得称赞的地方,但有一点很奇怪。cross_validation_split 生成随机索引,但索引在同一折叠内或所有三个折叠中都会重复。我们剩下的就是重复的观察,而遗漏了其他的。这样可以接受吗?我以前从未见过这样的折叠方法。

  33. Ben Hine 2018 年 7 月 27 日下午 1:50 #

    谢谢 Jason,我确实浏览了第一个链接中的代码。它有助于巩固我对交叉验证划分的理解。那么,您的结果表明,在运行交叉验证划分后,这 10 个数据点中的每一个折叠都有来自这 10 个数据点的唯一数字。对于一个大型数据集来说,在选择数据点以进行下一个折叠之前,将整个数据点集随机打乱不应该更随机吗?是的,数据会重复,但还有另一个随机因素。

    回到我关于神经网络代码中交叉验证划分函数输出重复索引的问题,我打印了每个折叠的索引号。在第零折中,我得到了三次索引号“7”。这就是我运行的:

    # 将数据集分成 k 折
    def cross_validation_split(dataset, n_folds)
    dataset_split = list()
    dataset_copy = list(dataset)
    fold_size = int(len(dataset) / n_folds)
    print(“fold_size =%s” % int(len(dataset)/n_folds))
    for i in range(n_folds)
    fold = list()
    print(“fold = %s” % i)
    while len(fold) < fold_size
    index = randrange(len(dataset_copy))
    print("index = %s" % index)
    fold.append(dataset_copy.pop(index))
    dataset_split.append(fold)
    return dataset_split

    此折叠中还有其他重复项。折叠一和折叠二中也有重复项。是我没有理解什么吗?抱歉充当魔鬼的代言人,但我很困惑。

    • Ben Hine 2018 年 7 月 27 日下午 2:16 #

      实际上,经过进一步研究,我确信 randrange 不适合这里,如果您想要唯一的数值,尤其是在数据集逐渐增大的情况下。例如,以下网站使用了 randrange(100),并且他们的代码产生了至少一个重复的值。我认为这可能会奏效:
      import random
      random.sample(range(interval), count)

      第一次传递时,interval = 69,count = 69
      第二次传递时,interval = 70-138,count = 69
      第三次传递时,interval = 139-208,count =69

      我会在回顾您的页面时实现这一点,并告诉您结果。

      我并不乐于指出这一点,我只是想理解一切。我真的很享受拆解您的算法并重新组合的过程。我钦佩它的复杂而简洁,并希望将来能像这样编码。我打算看看这个页面的其余部分,如果它们具有相同的品质,我还会继续关注您的其他示例。🙂

    • Jason Brownlee 2018 年 7 月 28 日上午 6:26 #

      请注意,我们通过移除选择项来减小 dataset_copy 的大小。

      这意味着索引会重复,但会指向不同的数据。

      您可以通过在帖子中链接的简单构造的小数据集(10 个整数示例)上测试该函数来确认这一点,并看到折叠中没有值重复。

      也许花点时间再研究一下这个函数?

      • Ben Hine 2018 年 7 月 28 日下午 1:56 #

        哇。是的。那很容易看出来。我刚刚被摆了一道。有很多事情在进行,但有序。我错过了。谢谢。抱歉。

        • Jason Brownlee 2018 年 7 月 29 日上午 6:04 #

          抱歉 Ben,我不想把任何人摆在那个位置,只是想提供帮助。

          也许代码太复杂了。

  34. Ben Hine 2018 年 7 月 30 日凌晨 1:39 #

    请不要道歉。代码很好。如果它太复杂,那是我的缺点,但我喜欢每天学习新东西。我真的很享受。我确实发现您使用列表而不是数据框很有趣。这是黄金。我只想很好地了解它并理解您使用的所有函数和方法。

    • Jason Brownlee 2018 年 7 月 30 日上午 5:53 #

      我选择列表而不是 numpy 数组或数据框是为了坚持使用 Python 标准库。

      这些示例是为了学习,而不是为了优化性能。

  35. Gop 2018 年 9 月 10 日上午 11:59 #

    我们如何显示测试数据点是线性可分的还是非线性可分的?

    • Jason Brownlee 2018 年 9 月 10 日下午 2:09 #

      如果你可以画一条线来分离它们,或者分别拟合它们进行分类和回归。

      • Gop 2018 年 9 月 11 日上午 4:40 #

        谢谢 Jason,您能详细说明一下吗?我刚开始接触。

        • Jason Brownlee 2018 年 9 月 11 日上午 6:32 #

          绘制您的数据,看看是否可以分离或用直线拟合。

          或者不画,假设它可以,并评估模型的性能。如果性能不佳,它可能不可分。

  36. Felipe 2018 年 9 月 21 日下午 12:18 #

    您好,我尝试了您的教程,玩得很开心,修改了学习率,我得到了
    lRate: 1.875000, n_epoch: 300 分数
    [82.6086956521739, 72.46376811594203, 73.91304347826086]
    平均准确率:76.329%

    我不知道这是否会对任何人有所帮助……但我认为我应该分享一下。

    继续发布更多教程!

  37. muluken 2018 年 10 月 1 日下午 6:04 #

    您好,我是来自埃塞俄比亚的 muluken。我想在我的硕士论文中使用 Python 编程和基于回归的方法来预测 GSM 用户的地理位置。但是,我找不到 Python 编程中的最佳训练方法以及如何将数据标准化以使其适合模型作为训练数据集。请对此发表看法。

  38. Jackson Scott 2018 年 10 月 2 日下午 12:19 #

    为什么学习率在改变时对平均准确率没有太大影响?
    目前,我的学习率设置为 9000,但准确率仍然和以前一样。

    • Jason Brownlee 2018 年 10 月 3 日上午 6:13 #

      也许问题非常简单,模型无论如何都会学会它。

  39. James 2018 年 10 月 28 日上午 12:33 #

    感谢您的时间,先生,您能告诉我哪里可以找到用MATLAB编写的此类代码吗?
    谢谢您。

  40. ahmed khalifa 2018年11月21日 上午3:12 #

    这非常简单而且出色,谢谢,伙计

  41. Rukshar 2019年2月4日 下午9:03 #

    您能推荐一些UCI ML存储库中的数据集来执行示例3吗?

  42. Aman Dhiman 2019年2月8日 下午6:58 #

    对我这样的初学者来说,这是一份非常好的指南!您能否帮助我了解上面示例中提到的权重?我正在参考您的示例编写自己的感知器,现在我不想使用相同的权重向量,而是想生成与您的示例相同的100%准确的预测。请指导我如何初始化最佳的随机权重以获得高效的感知器。谢谢。

    • Jason Brownlee 2019年2月9日 上午5:54 #

      您可以更改随机数种子以获得一组不同的随机权重。

  43. Toufik 2019年2月18日 下午10:29 #

    谢谢Jason,我可以用单层实现超过两类的鸢尾花分类,您能帮帮我吗?

  44. Toufik 2019年2月19日 下午9:21 #

    你好,但我只想使用感知器来对3个类别进行输出

    • Jason Brownlee 2019年2月20日 上午8:03 #

      它是为二元分类设计的,也许可以用多层感知器?

  45. Aya 2019年3月2日 下午8:31 #

    在您的代码的第四行,即
    for i in range(len(row)-1)

    我认为这里有一个错误,应该是 for i in range(len(weights)-1)
    另外,第18行也有同样的错误

    非常感谢您分享您的知识。组织得很好,解释得很清楚。

  46. Yavuzhan ERDEM 2019年4月10日 下午9:01 #

    杰森先生,您好

    我不明白您为什么向predict函数发送三个输入?
    我们有两个输入x1和x2,所以我们应该发送两个输入给predict。您能解释一下吗?

  47. Saurabh Kmar 2019年8月2日 下午7:40 #

    Jason Brownlee 兄弟,你为什么出生?

  48. Dereje 2019年8月26日 上午1:12 #

    亲爱的Jason,非常感谢您提供的关于声纳数据集上感知器算法的代码。在代码中,我们究竟在哪里使用str_column_to_int函数?我没找到。提前感谢。

    • Jason Brownlee 2019年8月26日 上午6:20 #

      好问题,最后的示例的第109行。

      • Dereje 2019年8月26日 上午8:56 #

        感谢您的回复。也许我没有理解代码。我期望有一个为str_column_to_int的输出分配的变量,但事实并非如此,比如dataset_int = str_column_to_int。这就是我问您的原因。

        我尝试了4折交叉验证,学习率=0.1,迭代次数=500:输出如下

        分数:[80.76923076923077, 82.6923076923077, 73.07692307692307, 71.15384615384616]
        平均准确率:76.923%

  49. Rukshar Alam 2019年9月9日 下午6:57 #

    请给我们更多的练习机会。您的教程简洁易懂。

  50. Mike 2019年9月12日 上午1:59 #

    嗨,Jason,

    我尝试了您的感知器示例,使用了声纳all data.csv数据集。但我没有得到与您相同的得分和平均准确率,正如您在此处看到的

    分数:[0.0, 1.4492753623188406, 0.0]
    平均准确率:0.483%

    我一步一步地按照您教程中展示的先前代码进行,它们运行正常。您能帮我一下吗?

    谢谢

  51. Sangeeth 2019年9月16日 上午3:31 #

    你好,
    数据集的最后一个元素是0或1。我看不到权重中的偏差。在更新权重时,我们不应该在X数据集的第一个元素中添加1吗?
    谢谢

    • Jason Brownlee 2019年9月16日 上午6:39 #

      第一个权重(索引0)是偏差。

      偏差权重是通过学习得到的,不是1。

  52. Efrain 2019年10月31日 上午7:54 #

    嗨 Jason
    我运行了您的代码,但结果与您不同。为什么?

    分数:[50.0, 66.66666666666666, 50.0]
    平均准确率:55.556%

    • Jason Brownlee 2019年10月31日 上午8:17 #

      也许确认一下您使用的是Python 2.7还是3.6?
      或许可以尝试多运行几次这个例子?

  53. Home 2020年1月26日 上午1:07 #

    嗨 Jason

    我对代码第2部分第19行要输入什么感到困惑?

    weights[i + 1] = weights[i + 1] + l_rate * error * row[i]

    我是神经网络的新手,并且正在尝试让这段代码工作,以便在进行用于格斗运动的遮挡 R-CNN 之前更好地理解感知器。

    代码在Python中可以工作,我已经确认了,但是,就像第1部分一样,我想完全理解您的数学。我通过使用Excel正确地确认了这一点,并且我发现很难知道到底是什么被代入了上面的公式(因为我无法从代码中辨别)。

    我有一个Excel文件,我很乐意发送给您,或者您可以在回复中使第19行更清楚吗?也许给我一个例子

    我非常感谢您在这里的工作,它确实对我有所帮助。期待您的回复

    谢谢

    Rory

    • Home 2020年1月26日 上午1:22 #

      您能为我定义函数中的元素吗

      谢谢

      • Jason Brownlee 2020年1月26日 上午5:23 #

        是的。

        – 权重是模型的参数。
        – weights[0] 是偏差,就像回归中的截距一样。一个偏移量。
        – weights[i+1] 是一个输入变量/列的权重。
        – l_rate 是学习率,我们设置的一个超参数,用于调整模型从数据中学习的速度。
        – error 是模型对样本造成的预测误差
        – row[i] 是一个输入变量/列的值

        希望这能有所帮助。

    • Jason Brownlee 2020年1月26日 上午5:20 #

      那一行到底有什么让您感到困惑?也许我可以回答您具体的问题?

  54. Home 2020年1月26日 上午2:52 #

    Jason,

    我可能已经解决了我的代码理解不足的问题……从公式来看,我在函数中打印了某些变量以更好地理解数学。我在Excel表中得到了以下结果

    Wt 0.722472523 0
    W[t+1] 0.116618823 0
    W[t+2] -0.234181177 1
    W[t+3] -0.234181177 1
    W[t+4] -0.234181177 1

    五个迭代周期后,这看起来正确吗?

  55. Home 2020年1月28日 上午5:18 #

    Jason

    我完成了代码,并使用PY3.8.1实现。

    分数:[81.15942028985508, 69.56521739130434, 62.31884057971014]
    平均准确率:71.014%

    增加学习率和迭代次数会提高准确率

    很棒的教程。谢谢

  56. nn 2020年4月3日 下午12:20 #

    LevelOfViolence CriticsRating Watched
    0 1 1.2 -1
    1 1 3.5 1
    2 1 4.2 1
    3 2 3.9 1
    4 2 2.8 -1
    5 3 3.0 -1
    6 5 4.5 -1
    7 4 1.8 -1
    8 1 2.1 -1
    9 3 4.8 1
    10 5 4.9 1
    11 3 1.5 -1
    12 3 2.6 -1

  57. nn 2020年4月3日 下午12:21 #

    三列,最后一列是标签,前两列是xn,yn……如何实现感知器?

  58. nn 2020年4月10日 上午8:34 #

    无法解决问题……我在这里分享我的代码
    def misclasscified(w_vector,x_vector,train_label)
    X1_train = [i[0] for i in x_vector]
    X2_train = [i[1] for i in x_vector]
    mis_classified_list = []
    for j in range(len(train_label))
    i = 0
    predicted_label= w_vector[i]+ w_vector[i+1] * X1_train[j]+ w_vector[i+2] * X2_train[j]
    if (predicted_label >= 0)
    predicted_label = 1
    else
    predicted_label = -1
    if (predicted_label != train_label[j])
    mis_classified_list.append([X1_train[j],X2_train[j]])

    return mis_classified_list

    w_vector =np.random.rand(3,1);
    x_vector = train_data
    train_label = [-1,1,1,1,-1,-1,-1,-1,-1,1,1,-1,-1]
    obj = misclasscified(w_vector,x_vector,train_label)
    obj

  59. Bertie 2020年4月11日 下午11:43 #

    非常感谢您的精彩教程!只是在这里有个小问题
    当您不随机选择一行来更新参数时,它真的叫做随机梯度下降吗?我以为为了正确起见,应该随机选择一行……
    非常感谢!=)

    • Jason Brownlee 2020年4月12日 上午6:21 #

      严格来说,“随机”梯度下降或“在线”梯度下降是指在每一行数据之后更新权重,并在每个 epoch 之后对数据进行洗牌。

  60. Sai Srinivas 2020年8月5日 下午3:46 #

    为什么我们需要乘以x在权重更新规则中??

  61. john 2020年9月26日 上午3:19 #

    你好,
    感谢您的辛勤工作!

    在第75-78行
    activation = weights[0]
    for i in range(len(row)-1)
    activation += weights[i + 1] * row[i]

    我认为您应该从 activation = weights[0]*row[0] 开始,然后是 activation += weights[i + 1] * row[i+1],否则,点积就会发生偏移。

    如果我错了,请纠正我。

    • Jason Brownlee 2020年9月26日 上午6:22 #

      不,0是为没有输入的偏差保留的。

      也许重新阅读教程中提到这一点的那部分。

  62. Vaishnavi 2020年10月21日 上午6:41 #

    我想用感知器实现XOR门在Python中。我可以使用多层感知器,其中NAND和OR门在隐藏层,‘AND Gate’给出输出吗?单层感知器没有给我输出。或者,有其他更快的方​​法吗?

    • Jason Brownlee 2020年10月21日 上午6:47 #

      为什么你想在感知器算法中使用逻辑门?

      我不明白,抱歉。

  63. Vaishnavi 2020年10月22日 下午4:36 #

    我是一名学生。我有一个作业,要编写感知器网络的代码来解决XOR问题并分析学习率的影响。我计算了权重,但我需要编写一个代码,以便程序本身更新权重。

  64. Armando 2021年2月6日 上午9:14 #

    感谢这篇精彩的文章,在了解它之后,我决定实现一个更简单的版本以求清晰。

    它也是2个参数和3个权重,目的是验证一个点(x,y)是在线之上还是之下。

    我添加了图形可视化来观察模型学习的过程。

    https://gist.github.com/amaynez/012f6adab976246e8f8a9e77e00d7989

  65. Mohamed Ahmed Mohamedzain 2021年3月19日 上午8:13 #


    我想要一个用于感知器学习的代码,逻辑操作是AND

    • Jason Brownlee 2021年3月20日 上午5:14 #

      很好,上面的教程是一个很好的起点。您需要准备一个数据集,例如,包含输入和输出的AND逻辑数据行。

  66. xiaoou wang 2021年4月15日 上午7:35 #

    很棒的教程,只是路过打个招呼。

    l_rate = 0.05 给出 75.36% 的准确率,是的

  67. joey 2021年5月22日 上午1:27 #

    运行 perceptron_sonar_001.py
    分数:[10.135135135135135, 12.837837837837837, 17.56756756756757]
    平均准确率:13.514%
    我的随机数据集

  68. Magda 2021年9月30日 上午3:31 #

    感谢这个很棒的教程。它帮助我理解并实现了自己的神经网络。

  69. Yasukawa 2023年5月30日 上午8:39 #

    我通过您的代码理解了感知器的概念。非常感谢您。同时,使用以下数据集(我自己创建的)
    datasets = [
    [1.23412321, 2.45612453, 0],
    [2.45678234, 4,23411223, 0],
    [3.12309812, 1.45615523, 0],
    [1.12453278, 3.16782391, 0],
    [1.34123190, -0.98713654, 0],
    [2.34590238, 3.140243321, 1],
    [6.89761151, 1.87644201, 1],
    [6.986309341, 2.91381529, 1],
    [4.08977865, 1.09812765, 1],
    [3.56743452, 1.87655543, 1]
    ]

    发生了以下错误:“IndexError: list index out of range”

    请您给我一些建议。非常感谢

  70. sudhir 2024年12月6日 下午7:37 #

    使用适当数量的输入和输出来创建感知器。使用固定增量学习算法进行训练,直到权重不再发生变化。

发表回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。