Passed
Push — master ( 7ab80b...4af844 )
by Arkadiusz
03:30
created

Backpropagation::backpropagate()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 5
nop 2
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 int
14
     */
15
    private $theta;
16
17
    /**
18
     * @var array
19
     */
20
    private $sigmas;
21
22
    /**
23
     * @var array
24
     */
25
    private $prevSigmas;
26
27
    /**
28
     * @param int $theta
29
     */
30
    public function __construct(int $theta)
31
    {
32
        $this->theta = $theta;
33
    }
34
35
    /**
36
     * @param array $layers
37
     * @param mixed $targetClass
38
     */
39
    public function backpropagate(array $layers, $targetClass)
40
    {
41
42
        $layersNumber = count($layers);
43
44
        // Backpropagation.
45
        for ($i = $layersNumber; $i > 1; --$i) {
46
            $this->sigmas = [];
47
            foreach ($layers[$i - 1]->getNodes() as $key => $neuron) {
48
49
                if ($neuron instanceof Neuron) {
50
                    $sigma = $this->getSigma($neuron, $targetClass, $key, $i == $layersNumber);
51
                    foreach ($neuron->getSynapses() as $synapse) {
52
                        $synapse->changeWeight($this->theta * $sigma * $synapse->getNode()->getOutput());
53
                    }
54
                }
55
            }
56
            $this->prevSigmas = $this->sigmas;
57
        }
58
    }
59
60
    /**
61
     * @param Neuron $neuron
62
     * @param int    $targetClass
63
     * @param int    $key
64
     * @param bool   $lastLayer
65
     *
66
     * @return float
67
     */
68
    private function getSigma(Neuron $neuron, int $targetClass, int $key, bool $lastLayer): float
69
    {
70
        $neuronOutput = $neuron->getOutput();
71
        $sigma = $neuronOutput * (1 - $neuronOutput);
72
73
        if ($lastLayer) {
74
            $value = 0;
75
            if ($targetClass === $key) {
76
                $value = 1;
77
            }
78
            $sigma *= ($value - $neuronOutput);
79
        } else {
80
            $sigma *= $this->getPrevSigma($neuron);
81
        }
82
83
        $this->sigmas[] = new Sigma($neuron, $sigma);
84
85
        return $sigma;
86
    }
87
88
    /**
89
     * @param Neuron $neuron
90
     *
91
     * @return float
92
     */
93
    private function getPrevSigma(Neuron $neuron): float
94
    {
95
        $sigma = 0.0;
96
97
        foreach ($this->prevSigmas as $neuronSigma) {
98
            $sigma += $neuronSigma->getSigmaForNeuron($neuron);
99
        }
100
101
        return $sigma;
102
    }
103
}
104