Completed
Push — master ( cf222b...4daa0a )
by Arkadiusz
03:24
created

Adaline::updateWeights()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.2
c 0
b 0
f 0
cc 4
eloc 10
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Phpml\Classification\Linear;
6
7
use Phpml\Helper\Predictable;
8
use Phpml\Helper\Trainable;
9
use Phpml\Classification\Classifier;
10
use Phpml\Classification\Linear\Perceptron;
11
12
class Adaline extends Perceptron
13
{
14
15
    /**
16
     * Batch training is the default Adaline training algorithm
17
     */
18
    const BATCH_TRAINING    = 1;
19
20
    /**
21
     * Online training: Stochastic gradient descent learning
22
     */
23
    const ONLINE_TRAINING    = 2;
24
25
    /**
26
     * The function whose result will be used to calculate the network error
27
     * for each instance
28
     *
29
     * @var string
30
     */
31
    protected static $errorFunction = 'output';
32
33
    /**
34
     * Training type may be either 'Batch' or 'Online' learning
35
     *
36
     * @var string
37
     */
38
    protected $trainingType;
39
40
    /**
41
     * Initalize an Adaline (ADAptive LInear NEuron) classifier with given learning rate and maximum
42
     * number of iterations used while training the classifier <br>
43
     *
44
     * Learning rate should be a float value between 0.0(exclusive) and 1.0 (inclusive) <br>
45
     * Maximum number of iterations can be an integer value greater than 0 <br>
46
     * If normalizeInputs is set to true, then every input given to the algorithm will be standardized
47
     * by use of standard deviation and mean calculation
48
     *
49
     * @param int $learningRate
50
     * @param int $maxIterations
51
     */
52
    public function __construct(float $learningRate = 0.001, int $maxIterations = 1000,
53
        bool $normalizeInputs = true, int $trainingType = self::BATCH_TRAINING)
54
    {
55
        if (! in_array($trainingType, [self::BATCH_TRAINING, self::ONLINE_TRAINING])) {
56
            throw new \Exception("Adaline can only be trained with batch and online/stochastic gradient descent algorithm");
57
        }
58
59
        $this->trainingType = $trainingType;
0 ignored issues
show
Documentation Bug introduced by
The property $trainingType was declared of type string, but $trainingType is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
60
61
        parent::__construct($learningRate, $maxIterations, $normalizeInputs);
62
    }
63
64
    /**
65
     * Adapts the weights with respect to given samples and targets
66
     * by use of gradient descent learning rule
67
     */
68
    protected function runTraining()
69
    {
70
        // If online training is chosen, then the parent runTraining method
71
        // will be executed with the 'output' method as the error function
72
        if ($this->trainingType == self::ONLINE_TRAINING) {
73
            return parent::runTraining();
74
        }
75
76
        // Batch learning is executed:
77
        $currIter = 0;
78
        while ($this->maxIterations > $currIter++) {
79
            $outputs = array_map([$this, 'output'], $this->samples);
80
            $updates = array_map([$this, 'gradient'], $this->targets, $outputs);
81
82
            $this->updateWeights($updates);
83
        }
84
    }
85
86
    /**
87
     * Returns the direction of gradient given the desired and actual outputs
88
     *
89
     * @param int $desired
90
     * @param int $output
91
     * @return int
92
     */
93
    protected function gradient($desired, $output)
94
    {
95
        return $desired - $output;
96
    }
97
98
    /**
99
     * Updates the weights of the network given the direction of the
100
     * gradient for each sample
101
     *
102
     * @param array $updates
103
     */
104
    protected function updateWeights(array $updates)
105
    {
106
        // Updates all weights at once
107
        for ($i=0; $i <= $this->featureCount; $i++) {
108
            if ($i == 0) {
109
                $this->weights[0] += $this->learningRate * array_sum($updates);
110
            } else {
111
                $col = array_column($this->samples, $i - 1);
112
113
                $error = 0;
114
                foreach ($col as $index => $val) {
115
                    $error += $val * $updates[$index];
116
                }
117
118
                $this->weights[$i] += $this->learningRate * $error;
119
            }
120
        }
121
    }
122
}
123