diff --git a/build/neuralnetwork/core/Genome.php b/build/neuralnetwork/core/Genome.php index 87d3f85..882a6af 100644 --- a/build/neuralnetwork/core/Genome.php +++ b/build/neuralnetwork/core/Genome.php @@ -16,7 +16,7 @@ **** LOCAL ATTRIBUTES **** ************************************************/ public $layers; // Number of layers - public $neurons; // Neurons of the genome + public $neurons; // Number of neurons per layer public $synapses; // Synapses between neurons @@ -78,14 +78,12 @@ // set layers $this->layers = $layers; - /* (2) Creating random neurons */ - $this->neurons = []; - for( $i = 0, $l = $neurons*$layers ; $i < $l ; $i++ ) - $this->neurons[$i] = rand(self::MIN, self::MAX) / self::MAX; + /* (2) Store number of neurons */ + $this->neurons = $neurons; /* (3) Creating random synapses */ $this->synapses = []; - for( $i = 0, $l = pow($neurons, $layers) ; $i < $l ; $i++ ) + for( $i = 0, $l = $layers*pow($neurons,2) ; $i < $l ; $i++ ) $this->synapses[$i] = rand(self::MIN, self::MAX) / self::MAX; // Success status @@ -106,7 +104,7 @@ /* (2) Clones into this Genome */ $this->layers = $parent->layers; - $this->neurons = array_slice($parent->neurons, 0); + $this->neurons = $parent->neurons; $this->synapses = array_slice($parent->synapses, 0); // Success state @@ -127,21 +125,18 @@ return false; /* (2) Checks number of layers+neurons (same species) */ - if( $father->layers !== $mother->layers || count($father->neurons) !== count($mother->neurons) ) + if( $father->layers !== $mother->layers || $father->neurons !== $mother->neurons ) return false; /* (3) Set layer count */ $this->layers = $father->layers; - /* (4) Do random crossover for neurons */ - $this->neurons = []; - for( $i = 0, $l = count($father->neurons) ; $i < $l ; $i++ ) - if( !!rand(0,1) ) $this->neurons[$i] = $father->neurons[$i]; - else $this->neurons[$i] = $mother->neurons[$i]; + /* (4) Set neurons number */ + $this->neurons = $father->neurons; /* (5) Do random crossover for synapses */ $this->synapses = []; - for( $i = 0, $l = pow(count($this->neurons)/$this->layers, $this->layers) ; $i < $l ; $i++ ) + for( $i = 0, $l = $this->layers*pow($this->neurons, 2) ; $i < $l ; $i++ ) if( !!rand(0,1) ) $this->synapses[$i] = $father->synapses[$i]; else $this->synapses[$i] = $mother->synapses[$i]; @@ -195,6 +190,64 @@ $this->synapses[$iSynapses[$i]] = rand(self::MIN, self::MAX) / self::MAX; } + /* CALCULATES THE OUTPUT OF THE GENOME + * + * @input Input for which we want fitness + * + * @return output Output calculated with this input + * + */ + public function process($input=null){ + /* (1) Checks @input argument */ + if( !is_array($input) || count($input) !== $this->neurons ) + throw new \Error('Invalid @input for Genome\'s output calculation.'); + + + /* [1] Set temporary calculation data + =========================================================*/ + /* (1) Set temporary neurons data */ + $neurons = array_merge( $input, array_fill(0, $this->neurons*$this->layers, 0) ); + + /* (2) Set temporary synapses data */ + $synapses = $this->synapses; + + + /* [2] Calculates output + =========================================================*/ + /* (1) For each hidden layer + ---------------------------------------------------------*/ + for( $l = 1 ; $l < $this->layers+1 ; $l++ ){ + + /* (2) For each neuron of this layer + ---------------------------------------------------------*/ + for( $n = $l*$this->neurons, $nl = ($l+1)*$this->neurons ; $n < $nl ; $n++ ){ + + $neurons[$n] = 0; + + /* (3) For each synapse between current neuron and last layer + ---------------------------------------------------------*/ + for( $s = ($l-1)*pow($this->neurons,2), $sl = $l*pow($this->neurons,2) ; $s < $sl ; $s++ ) + $neurons[$n] += $synapses[$s] * $neurons[ floor($s/$this->neurons) ]; + // newNeuron += synapse*lastLayerNeuron + + /* Divide the sum to make a mean */ + $neurons[$n] /= $this->neurons; + } + + } + + /* (4) Calculates single output + ---------------------------------------------------------*/ + $output = 0; + + for( $n = ($this->layers-1)*$this->neurons, $nl = $this->layers*$this->neurons ; $n < $nl ; $n++ ) + $output += $neurons[$n]; + + + /* [3] Returns output + =========================================================*/ + return $output / $this->neurons; + } /************************************************ **** Serialization **** @@ -210,12 +263,9 @@ $csv = ''; /* (2) Adds global attributes */ - $csv .= $this->layers .';'; + $csv .= $this->layers .','. $this->neurons .';'; - /* (3) Adds neurons data */ - $csv .= implode(',', $this->neurons) .';'; - - /* (4) Adds synapses data */ + /* (3) Adds synapses data */ $csv .= implode(',', $this->synapses); return $csv; @@ -236,16 +286,16 @@ throw new \Error('Format error during Genome unserialization.'); /* (2) Get global attributes */ - if( !is_numeric($segments[0]) ) + $global = explode(',', $segments[0]); + + if( count($global) < 2 ) throw new \Error('Format error during Genome unserialization.'); - $this->layers = intval($segments[0]); + $this->layers = intval($global[0]); + $this->layers = intval($global[1]); - /* (3) Get neurons values */ - $this->neurons = explode(',', $segments[1]); - - /* (4) Get synapses values */ - $this->synapses = explode(',', $segments[2]); + /* (3) Get synapses values */ + $this->synapses = explode(',', $segments[1]); } } diff --git a/build/neuralnetwork/core/NeuralNetworkCore.php b/build/neuralnetwork/core/NeuralNetworkCore.php index a4c33f8..4d777c4 100644 --- a/build/neuralnetwork/core/NeuralNetworkCore.php +++ b/build/neuralnetwork/core/NeuralNetworkCore.php @@ -343,9 +343,42 @@ /* [2] Creates the neural network =========================================================*/ + // best of last generation + $best = new Genome($this->numHid, $this->numNeu); + + + /* (1) For each generation + ---------------------------------------------------------*/ + for( $this->gnr = 0 ; $this->gnr < $this->maxGnr ; $this->gnr++ ){ + + /* (1) Initializes genome list for current generation */ + $this->gnms = []; + + /* (2) For each genome of the generation */ + for( $this->gnm = 0 ; $this->gnm < $this->maxGnm ; $this->gnm++ ){ + + // {2.1} First Generation -> random genomes // + if( $this->gnr === 0 ) + $this->gnms[$this->gnm] = new Genome($this->numHid, $this->numNeu); + + // {2.2} Others generations -> crossover + mutation // + else{ + $this->gnms[$this->gnm] = new Genome($best['father'], $best['mother']); + $this->gnms[$this->gnm]->mutation($this->mutThr); + } + + /* (3) Calculate fitness */ + // ... blablabla + } + + } + + // TODO: Select best genomes based on fitness + $best = null; } + /************************************************ **** Serialization Methods **** ************************************************/ diff --git a/build/neuralnetwork/storage/A/B/C/test.ex b/build/neuralnetwork/storage/A/B/C/test.ex deleted file mode 100644 index 8496455..0000000 --- a/build/neuralnetwork/storage/A/B/C/test.ex +++ /dev/null @@ -1,8 +0,0 @@ -0,0,0;0 -0,0,1;1 -0,1,0;0 -0,1,1;1 -1,0,0;0 -1,0,1;1 -1,1,0;1 -1,1,1;0 diff --git a/build/neuralnetwork/storage/A/B/C/test.nn b/build/neuralnetwork/storage/A/B/C/test.nn deleted file mode 100644 index 9dd4e10..0000000 --- a/build/neuralnetwork/storage/A/B/C/test.nn +++ /dev/null @@ -1 +0,0 @@ -{"maxGnr":50,"maxGnm":100,"kptGnm":2,"mutThr":0.3,"fitEnd":1,"numHid":2,"numNeu":3,"max":{"input":[1,1,1],"output":[1]},"storage":[{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/A\/B\/C\/test.nn","exists":true},{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/A\/B\/C\/test.ex","exists":true},{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/A\/B\/C\/test.ln","exists":true}]} \ No newline at end of file diff --git a/build/neuralnetwork/storage/_buffer.ex b/build/neuralnetwork/storage/_buffer.ex index 8496455..6eee4ae 100644 --- a/build/neuralnetwork/storage/_buffer.ex +++ b/build/neuralnetwork/storage/_buffer.ex @@ -1,8 +1,8 @@ -0,0,0;0 -0,0,1;1 -0,1,0;0 -0,1,1;1 -1,0,0;0 -1,0,1;1 -1,1,0;1 -1,1,1;0 +0,0,0;0,0 +0,0,1;0,1 +0,1,0;0,1 +0,1,1;0,1 +1,0,0;0,0 +1,0,1;0,1 +1,1,0;1,1 +1,1,1;1,1 diff --git a/build/neuralnetwork/storage/test/test1.ex b/build/neuralnetwork/storage/test/test1.ex new file mode 100644 index 0000000..6eee4ae --- /dev/null +++ b/build/neuralnetwork/storage/test/test1.ex @@ -0,0 +1,8 @@ +0,0,0;0,0 +0,0,1;0,1 +0,1,0;0,1 +0,1,1;0,1 +1,0,0;0,0 +1,0,1;0,1 +1,1,0;1,1 +1,1,1;1,1 diff --git a/build/neuralnetwork/storage/A/B/C/test.ln b/build/neuralnetwork/storage/test/test1.ln similarity index 100% rename from build/neuralnetwork/storage/A/B/C/test.ln rename to build/neuralnetwork/storage/test/test1.ln diff --git a/build/neuralnetwork/storage/test/test1.nn b/build/neuralnetwork/storage/test/test1.nn new file mode 100644 index 0000000..850bff2 --- /dev/null +++ b/build/neuralnetwork/storage/test/test1.nn @@ -0,0 +1 @@ +{"maxGnr":50,"maxGnm":100,"kptGnm":2,"mutThr":0.3,"fitEnd":1,"numHid":2,"numNeu":3,"max":{"input":[1,1,1],"output":[1,1]},"storage":[{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/test\/test1.nn","exists":false},{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/test\/test1.ex","exists":false},{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/test\/test1.ln","exists":false}]} \ No newline at end of file diff --git a/public/main.php b/public/main.php index 085a217..d9b8bdc 100644 --- a/public/main.php +++ b/public/main.php @@ -10,7 +10,7 @@ if( false && 'test_creating_dataset' ){ function behaviour($abc){ - return [($abc[0] & $abc[1]) ^ $abc[2]]; + return [($abc[0] & $abc[1]), $abc[1] | $abc[2]]; } echo "Welcome to neural-network.php\n"; @@ -18,7 +18,7 @@ $nn = NeuralNetwork::create(50, 100); - $nn->setMaxValues([1, 1, 1], [1]); + $nn->setMaxValues([1, 1, 1], [1, 1]); $nn->setHiddenLayersCount(2); $nn->setHiddenLayerNeuronsCount(3); @@ -31,17 +31,17 @@ $d = [1, 1, 0]; $nn->addSample($d, behaviour($d)); $d = [1, 1, 1]; $nn->addSample($d, behaviour($d)); - $nn->store('A/B/C/test', true); + $nn->store('test/test1', true); } if( false && 'load_neural_network' ){ - $nn = NeuralNetwork::load('A/B/C/test'); + $nn = NeuralNetwork::load('test/test1'); } - if( true && 'test_genomes' ){ + if( false && 'test_genomes' ){ /* (1) Basic Creation */ $a = new Genome(2, 3); // 2 layers of 3 neurons each -> randomly filled @@ -61,9 +61,17 @@ $c = new Genome($a, $b); // @c is a randomly-done mix of @a and @b echo "crossover : A+B -> C\n"; echo "C : ".$c->serialize()."\n"; + } + if( true ){ + + $g = new Genome(2, 3); + + echo $g->process([1, 1, 0]); + } + // REWRITE TEST // for( $a = 0, $al = 50 ; $a < $al ; $a++ ) // for( $b = 0, $bl = 20 ; $b < $bl ; $b++ ){