`Genome::process` first implementation with a single `output` + must add 2 layers to have the last one as the `output`

This commit is contained in:
xdrm-brackets 2016-10-27 00:19:28 +02:00
parent 20382821ca
commit db41a36af4
9 changed files with 139 additions and 48 deletions

View File

@ -16,7 +16,7 @@
**** LOCAL ATTRIBUTES **** **** LOCAL ATTRIBUTES ****
************************************************/ ************************************************/
public $layers; // Number of layers public $layers; // Number of layers
public $neurons; // Neurons of the genome public $neurons; // Number of neurons per layer
public $synapses; // Synapses between neurons public $synapses; // Synapses between neurons
@ -78,14 +78,12 @@
// set layers // set layers
$this->layers = $layers; $this->layers = $layers;
/* (2) Creating random neurons */ /* (2) Store number of neurons */
$this->neurons = []; $this->neurons = $neurons;
for( $i = 0, $l = $neurons*$layers ; $i < $l ; $i++ )
$this->neurons[$i] = rand(self::MIN, self::MAX) / self::MAX;
/* (3) Creating random synapses */ /* (3) Creating random synapses */
$this->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; $this->synapses[$i] = rand(self::MIN, self::MAX) / self::MAX;
// Success status // Success status
@ -106,7 +104,7 @@
/* (2) Clones into this Genome */ /* (2) Clones into this Genome */
$this->layers = $parent->layers; $this->layers = $parent->layers;
$this->neurons = array_slice($parent->neurons, 0); $this->neurons = $parent->neurons;
$this->synapses = array_slice($parent->synapses, 0); $this->synapses = array_slice($parent->synapses, 0);
// Success state // Success state
@ -127,21 +125,18 @@
return false; return false;
/* (2) Checks number of layers+neurons (same species) */ /* (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; return false;
/* (3) Set layer count */ /* (3) Set layer count */
$this->layers = $father->layers; $this->layers = $father->layers;
/* (4) Do random crossover for neurons */ /* (4) Set neurons number */
$this->neurons = []; $this->neurons = $father->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];
/* (5) Do random crossover for synapses */ /* (5) Do random crossover for synapses */
$this->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]; if( !!rand(0,1) ) $this->synapses[$i] = $father->synapses[$i];
else $this->synapses[$i] = $mother->synapses[$i]; else $this->synapses[$i] = $mother->synapses[$i];
@ -195,6 +190,64 @@
$this->synapses[$iSynapses[$i]] = rand(self::MIN, self::MAX) / self::MAX; $this->synapses[$iSynapses[$i]] = rand(self::MIN, self::MAX) / self::MAX;
} }
/* CALCULATES THE OUTPUT OF THE GENOME
*
* @input<Array> Input for which we want fitness
*
* @return output<double> 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 **** **** Serialization ****
@ -210,12 +263,9 @@
$csv = ''; $csv = '';
/* (2) Adds global attributes */ /* (2) Adds global attributes */
$csv .= $this->layers .';'; $csv .= $this->layers .','. $this->neurons .';';
/* (3) Adds neurons data */ /* (3) Adds synapses data */
$csv .= implode(',', $this->neurons) .';';
/* (4) Adds synapses data */
$csv .= implode(',', $this->synapses); $csv .= implode(',', $this->synapses);
return $csv; return $csv;
@ -236,16 +286,16 @@
throw new \Error('Format error during Genome unserialization.'); throw new \Error('Format error during Genome unserialization.');
/* (2) Get global attributes */ /* (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.'); 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 */ /* (3) Get synapses values */
$this->neurons = explode(',', $segments[1]); $this->synapses = explode(',', $segments[1]);
/* (4) Get synapses values */
$this->synapses = explode(',', $segments[2]);
} }
} }

View File

@ -343,9 +343,42 @@
/* [2] Creates the neural network /* [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 **** **** Serialization Methods ****
************************************************/ ************************************************/

View File

@ -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

View File

@ -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}]}

View File

@ -1,8 +1,8 @@
0,0,0;0 0,0,0;0,0
0,0,1;1 0,0,1;0,1
0,1,0;0 0,1,0;0,1
0,1,1;1 0,1,1;0,1
1,0,0;0 1,0,0;0,0
1,0,1;1 1,0,1;0,1
1,1,0;1 1,1,0;1,1
1,1,1;0 1,1,1;1,1

View File

@ -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

View File

@ -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}]}

View File

@ -10,7 +10,7 @@
if( false && 'test_creating_dataset' ){ if( false && 'test_creating_dataset' ){
function behaviour($abc){ 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"; echo "Welcome to neural-network.php\n";
@ -18,7 +18,7 @@
$nn = NeuralNetwork::create(50, 100); $nn = NeuralNetwork::create(50, 100);
$nn->setMaxValues([1, 1, 1], [1]); $nn->setMaxValues([1, 1, 1], [1, 1]);
$nn->setHiddenLayersCount(2); $nn->setHiddenLayersCount(2);
$nn->setHiddenLayerNeuronsCount(3); $nn->setHiddenLayerNeuronsCount(3);
@ -31,17 +31,17 @@
$d = [1, 1, 0]; $nn->addSample($d, behaviour($d)); $d = [1, 1, 0]; $nn->addSample($d, behaviour($d));
$d = [1, 1, 1]; $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' ){ 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 */ /* (1) Basic Creation */
$a = new Genome(2, 3); // 2 layers of 3 neurons each -> randomly filled $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 $c = new Genome($a, $b); // @c is a randomly-done mix of @a and @b
echo "crossover : A+B -> C\n"; echo "crossover : A+B -> C\n";
echo "C : ".$c->serialize()."\n"; echo "C : ".$c->serialize()."\n";
} }
if( true ){
$g = new Genome(2, 3);
echo $g->process([1, 1, 0]);
}
// REWRITE TEST // REWRITE TEST
// for( $a = 0, $al = 50 ; $a < $al ; $a++ ) // for( $a = 0, $al = 50 ; $a < $al ; $a++ )
// for( $b = 0, $bl = 20 ; $b < $bl ; $b++ ){ // for( $b = 0, $bl = 20 ; $b < $bl ; $b++ ){