нейронная сеть — базовый персептрон для шлюза AND в PHP, я правильно делаю? Странные результаты

Я хотел бы узнать о нейронных сетях, начиная с самого основного алгоритма персептрона. Итак, я реализовал один на PHP и получаю странные результаты после обучения. Все 4 возможных комбинации ввода возвращают либо неправильные, либо правильные результаты (чаще всего неправильные).

1) Что-то не так с моей реализацией, или результаты, которые я получаю, нормальные?

2) Может ли этот тип реализации работать с более чем 2 входами?

3) Каким будет следующий (самый легкий) шаг в изучении нейронных сетей после этого? Может быть, добавление нейронов, изменение функции активации или …?

Постскриптум Я довольно плохо разбираюсь в математике и не обязательно понимаю математику за перцептроном на 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";

0

Решение

Я должен поблагодарить вас за размещение этого вопроса, я хотел получить шанс немного глубже погрузиться в нейронные сети. Во всяком случае, до бизнеса. После возни с подробным описанием всего происходящего, в итоге потребовалось всего лишь 1 изменение символа для работы, как и предполагалось:

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;
}
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 эпох обучения.

0

По вопросам рекламы [email protected]