Backpropagation::getPrevSigma()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Phpml\NeuralNetwork\Training;
6
7
use Phpml\NeuralNetwork\Node\Neuron;
8
use Phpml\NeuralNetwork\Training\Backpropagation\Sigma;
9
10
class Backpropagation
11
{
12
    /**
13
     * @var float
14
     */
15
    private $learningRate;
16
17
    /**
18
     * @var array
19
     */
20
    private $sigmas = [];
21
22
    /**
23
     * @var array
24
     */
25
    private $prevSigmas = [];
26
27
    public function __construct(float $learningRate)
28
    {
29
        $this->setLearningRate($learningRate);
30
    }
31
32
    public function setLearningRate(float $learningRate): void
33
    {
34
        $this->learningRate = $learningRate;
35
    }
36
37
    public function getLearningRate(): float
38
    {
39
        return $this->learningRate;
40
    }
41
42
    /**
43
     * @param mixed $targetClass
44
     */
45
    public function backpropagate(array $layers, $targetClass): void
46
    {
47
        $layersNumber = count($layers);
48
49
        // Backpropagation.
50
        for ($i = $layersNumber; $i > 1; --$i) {
51
            $this->sigmas = [];
52
            foreach ($layers[$i - 1]->getNodes() as $key => $neuron) {
53
                if ($neuron instanceof Neuron) {
54
                    $sigma = $this->getSigma($neuron, $targetClass, $key, $i == $layersNumber);
55
                    foreach ($neuron->getSynapses() as $synapse) {
56
                        $synapse->changeWeight($this->learningRate * $sigma * $synapse->getNode()->getOutput());
57
                    }
58
                }
59
            }
60
61
            $this->prevSigmas = $this->sigmas;
62
        }
63
64
        // Clean some memory (also it helps make MLP persistency & children more maintainable).
65
        $this->sigmas = [];
66
        $this->prevSigmas = [];
67
    }
68
69
    private function getSigma(Neuron $neuron, int $targetClass, int $key, bool $lastLayer): float
70
    {
71
        $neuronOutput = $neuron->getOutput();
72
        $sigma = $neuron->getDerivative();
73
74
        if ($lastLayer) {
75
            $value = 0;
76
            if ($targetClass === $key) {
77
                $value = 1;
78
            }
79
80
            $sigma *= ($value - $neuronOutput);
81
        } else {
82
            $sigma *= $this->getPrevSigma($neuron);
83
        }
84
85
        $this->sigmas[] = new Sigma($neuron, $sigma);
86
87
        return $sigma;
88
    }
89
90
    private function getPrevSigma(Neuron $neuron): float
91
    {
92
        $sigma = 0.0;
93
94
        foreach ($this->prevSigmas as $neuronSigma) {
95
            $sigma += $neuronSigma->getSigmaForNeuron($neuron);
96
        }
97
98
        return $sigma;
99
    }
100
}
101