PHP中AND门的基本感知器,我做对了吗?奇怪的结果

时间:2018-06-29 06:04:28

标签: php neural-network perceptron

我想从最基本的感知器算法开始学习神经网络。因此,我已经在PHP中实现了一个,并且在对其进行培训后得到了奇怪的结果。所有4种可能的输入组合都将返回错误或正确的结果(通常是错误的结果)。

1)我的实现是否有问题,或者我得到的结果是否正常?

2)这种实现可以使用2个以上的输入吗?

3)在此之后学习神经网络的下一步(最简单)是什么?也许增加更多的神经元,改变激活功能,或者...?

P.S。我对数学很不满意,不一定了解100%感知器背后的数学,至少不是培训部分。

感知器类

<?php

namespace Perceptron;

class Perceptron
{
    // Number of inputs
    protected $n;

    protected $weights = [];

    protected $bias;

    public function __construct(int $n)
    {
        $this->n = $n;

        // Generate random weights for each input
        for ($i = 0; $i < $n; $i++) {
            $w = mt_rand(-100, 100) / 100;

            array_push($this->weights, $w);
        }

        // Generate a random bias
        $this->bias = mt_rand(-100, 100) / 100;
    }

    public function sum(array $inputs)
    {
        $sum = 0;

        for ($i = 0; $i < $this->n; $i++) {
            $sum += ($inputs[$i] * $this->weights[$i]);
        }

        return $sum + $this->bias;
    }

    public function activationFunction(float $sum)
    {
        return $sum < 0.0 ? 0 : 1;
    }

    public function predict(array $inputs)
    {
        $sum = $this->sum($inputs);

        return $this->activationFunction($sum);
    }

    public function train(array $trainingSet, float $learningRate)
    {
        foreach ($trainingSet as $row) {
            $inputs = array_slice($row, 0, $this->n);
            $correctOutput = $row[$this->n];

            $output = $this->predict($inputs);
            $error = $correctOutput - $output;

            // Adjusting the weights
            $this->weights[0] = $this->weights[0] + ($learningRate * $error);
            for ($i = 0; $i < $this->n - 1; $i++) {
                $this->weights[$i + 1] =
                    $this->weights[$i] + ($learningRate * $inputs[$i] * $error);
            }
        }

        // Adjusting the bias
        $this->bias += ($learningRate * $error);
    }
}

主文件

<?php

require_once 'vendor/autoload.php';

use Perceptron\Perceptron;

// Create a new perceptron with 2 inputs
$perceptron = new Perceptron(2);

// Test the perceptron
echo "Before training:\n";

$output = $perceptron->predict([0, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";

$output = $perceptron->predict([0, 1]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";

$output = $perceptron->predict([1, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";

$output = $perceptron->predict([1, 1]);
echo "{$output} - " . ($output == 1 ? 'correct' : 'nope') . "\n";

// Train the perceptron
$trainingSet = [
    // The 3rd column is the correct output
    [0, 0, 0],
    [0, 1, 0],
    [1, 0, 0],
    [1, 1, 1],
];

for ($i = 0; $i < 1000; $i++) {
    $perceptron->train($trainingSet, 0.1);
}

// Test the perceptron again - now the results should be correct
echo "\nAfter training:\n";

$output = $perceptron->predict([0, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";

$output = $perceptron->predict([0, 1]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";

$output = $perceptron->predict([1, 0]);
echo "{$output} - " . ($output == 0 ? 'correct' : 'nope') . "\n";

$output = $perceptron->predict([1, 1]);
echo "{$output} - " . ($output == 1 ? 'correct' : 'nope') . "\n";

2 个答案:

答案 0 :(得分:0)

我必须感谢您发布了这个问题,我希望有机会更深入地研究神经网络。无论如何,正事。修改并详细记录了所有情况之后,最终只需要更改一个字符即可按预期工作:

public function sum(array $inputs)
{
    ...
    //instead of multiplying the input by the weight, we should be adding the weight
    $sum += ($inputs[$i] + $this->weights[$i]);
    ...
}

通过这种更改,经过1000次迭代的训练最终会被过度杀伤。 代码的一小部分令人困惑,权重的设置不同:

public function train(array $trainingSet, float $learningRate)
{
    foreach ($trainingSet as $row) {
        ...
        $this->weights[0] = $this->weights[0] + ($learningRate * $error);
        for ($i = 0; $i < $this->n - 1; $i++) {
            $this->weights[$i + 1] =
                $this->weights[$i] + ($learningRate * $inputs[$i] * $error);
        }
}

我不一定理解您为什么选择这种方式。我没有经验的眼睛会认为以下内容同样适用。

for ($i = 0; $i < $this->n; $i++) { 
    $this->weight[$i] += $learningRate * $error;
}

答案 1 :(得分:0)

发现了一个愚蠢的错误,因为我不小心将其置于foreach循环之外,所以我没有调整训练集每一行的偏差。 train()方法应如下所示:

public function train(array $trainingSet, float $learningRate)
{
    foreach ($trainingSet as $row) {
        $inputs = array_slice($row, 0, $this->n);
        $correctOutput = $row[$this->n];

        $output = $this->predict($inputs);
        $error = $correctOutput - $output;

        // Adjusting the weights
        for ($i = 0; $i < $this->n; $i++) {
            $this->weights[$i] += ($learningRate * $inputs[$i] * $error);
        }

        // Adjusting the bias
        $this->bias += ($learningRate * $error);
    }
}

现在,每次运行脚本后,经过培训我都可以获得正确的结果。只需训练100个纪元即可。