Commit d29c5906 authored by Marcin Michalski's avatar Marcin Michalski Committed by Arkadiusz Kondas
Browse files

Return labels in MultilayerPerceptron output (#315)

parent e2553696
......@@ -41,7 +41,7 @@ class MLPClassifier extends MultilayerPerceptron implements Classifier
}
}
return $this->classes[$predictedClass];
return $predictedClass;
}
/**
......@@ -49,9 +49,8 @@ class MLPClassifier extends MultilayerPerceptron implements Classifier
*/
protected function trainSample(array $sample, $target): void
{
// Feed-forward.
$this->setInput($sample)->getOutput();
$this->setInput($sample);
// Back-propagate.
$this->backpropagation->backpropagate($this->getLayers(), $this->getTargetClass($target));
......
......@@ -41,12 +41,9 @@ class Layer
return $this->nodes;
}
/**
* @return Neuron
*/
private function createNode(string $nodeClass, ?ActivationFunction $activationFunction = null): Node
{
if ($nodeClass == Neuron::class) {
if ($nodeClass === Neuron::class) {
return new Neuron($activationFunction);
}
......
......@@ -51,8 +51,6 @@ abstract class LayeredNetwork implements Network
/**
* @param mixed $input
*
* @return $this
*/
public function setInput($input): Network
{
......
......@@ -69,6 +69,10 @@ abstract class MultilayerPerceptron extends LayeredNetwork implements Estimator,
throw new InvalidArgumentException('Provide at least 2 different classes');
}
if (count($classes) !== count(array_unique($classes))) {
throw new InvalidArgumentException('Classes must be unique');
}
$this->classes = array_values($classes);
$this->iterations = $iterations;
$this->inputLayerFeatures = $inputLayerFeatures;
......@@ -109,6 +113,16 @@ abstract class MultilayerPerceptron extends LayeredNetwork implements Estimator,
$this->backpropagation->setLearningRate($this->learningRate);
}
public function getOutput(): array
{
$result = [];
foreach ($this->getOutputLayer()->getNodes() as $i => $neuron) {
$result[$this->classes[$i]] = $neuron->getOutput();
}
return $result;
}
/**
* @param mixed $target
*/
......
......@@ -44,7 +44,7 @@ class Neuron implements Node
/**
* @return Synapse[]
*/
public function getSynapses()
public function getSynapses(): array
{
return $this->synapses;
}
......
......@@ -183,7 +183,7 @@ class MLPClassifierTest extends TestCase
$testSamples = [[0, 0], [1, 0], [0, 1], [1, 1]];
$predicted = $classifier->predict($testSamples);
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid();
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($classifier, $filepath);
......@@ -204,7 +204,7 @@ class MLPClassifierTest extends TestCase
$this->assertEquals('a', $network->predict([1, 0]));
$this->assertEquals('b', $network->predict([0, 1]));
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid();
$filename = 'perceptron-test-'.random_int(100, 999).'-'.uniqid('', false);
$filepath = tempnam(sys_get_temp_dir(), $filename);
$modelManager = new ModelManager();
$modelManager->saveToFile($network, $filepath);
......@@ -245,6 +245,13 @@ class MLPClassifierTest extends TestCase
new MLPClassifier(2, [2], [0]);
}
public function testOutputWithLabels(): void
{
$output = (new MLPClassifier(2, [2, 2], ['T', 'F']))->getOutput();
$this->assertEquals(['T', 'F'], array_keys($output));
}
private function getSynapsesNodes(array $synapses): array
{
$nodes = [];
......
......@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Phpml\Tests\NeuralNetwork\Network;
use Phpml\Exception\InvalidArgumentException;
use Phpml\NeuralNetwork\ActivationFunction;
use Phpml\NeuralNetwork\Layer;
use Phpml\NeuralNetwork\Network\MultilayerPerceptron;
......@@ -13,6 +14,39 @@ use PHPUnit_Framework_MockObject_MockObject;
class MultilayerPerceptronTest extends TestCase
{
public function testThrowExceptionWhenHiddenLayersAreEmpty(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Provide at least 1 hidden layer');
$this->getMockForAbstractClass(
MultilayerPerceptron::class,
[5, [], [0, 1], 1000, null, 0.42]
);
}
public function testThrowExceptionWhenThereIsOnlyOneClass(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Provide at least 2 different classes');
$this->getMockForAbstractClass(
MultilayerPerceptron::class,
[5, [3], [0], 1000, null, 0.42]
);
}
public function testThrowExceptionWhenClassesAreNotUnique(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Classes must be unique');
$this->getMockForAbstractClass(
MultilayerPerceptron::class,
[5, [3], [0, 1, 2, 3, 1], 1000, null, 0.42]
);
}
public function testLearningRateSetter(): void
{
/** @var MultilayerPerceptron $mlp */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment