Gestion de quasi-tout -> FONCTIONNELLLLLLL

This commit is contained in:
xdrm-brackets 2016-10-27 18:34:28 +02:00
parent e16048b569
commit da50b03202
13 changed files with 1919 additions and 112 deletions

View File

@ -23,7 +23,7 @@
try{ try{
fclose( fopen($file, 'w') ); fclose( fopen($file, 'w') );
return true; return true;
}catch(Exception $e){ return false; } }catch(\Exception $e){ return false; }
} }
@ -35,7 +35,7 @@
public static function read($file){ public static function read($file){
/* (0) Checks arguments */ /* (0) Checks arguments */
if( !is_string($file) ) if( !is_string($file) )
throw new \Error('Wrong argument for read(<String>).'); throw new \Exception('Wrong argument for read(<String>).');
/* (1) Initializing driver on file (read-flag) */ /* (1) Initializing driver on file (read-flag) */
$driver = new \SplFileObject($file, 'r'); $driver = new \SplFileObject($file, 'r');
@ -53,6 +53,54 @@
return $read; return $read;
} }
/* READS A FILE'S SPECIFIC LINE
*
* @file<String> File to read
* @line<int> Line to read
*
*/
public static function readline($file, $line){
/* (0) Checks arguments */
if( !is_string($file) || intval($line) !== $line )
throw new \Exception('Wrong argument for readline(<String>, <int>).');
/* (1) Initializing driver on file (read-flag) */
$driver = new \SplFileObject($file, 'r');
/* (2) Goto specific line */
$driver->seek($line);
/* (3) Return line's content */
if( $driver->key() == $line )
return $driver->current();
else
return null;
}
/* WRITES A FILE'S SPECIFIC LINE
*
* @file<String> File to read
* @line<int> Line to read
*
*/
public static function writeline($file, $line){
/* (0) Checks arguments */
if( !is_string($file) || intval($line) !== $line )
throw new \Exception('Wrong argument for writeline(<String>, <int>).');
/* (1) Initializing driver on file (read-flag) */
$driver = new \SplFileObject($file, 'r');
/* (2) Goto specific line */
$driver->seek($line);
/* (3) Return line's content */
if( $driver->key() == $line )
return $driver->current();
else
return null;
}
/* WRITES CONTENT TO A FILE /* WRITES CONTENT TO A FILE
* *
@ -72,7 +120,7 @@
/* (1) Erase file */ /* (1) Erase file */
try{ try{
fclose( fopen($file, 'w') ); fclose( fopen($file, 'w') );
}catch(Exception $e){ return false; } }catch(\Exception $e){ return false; }
/* (2) Get driver (write-flag) */ /* (2) Get driver (write-flag) */
$driver = new \SplFileObject($file, 'r+'); $driver = new \SplFileObject($file, 'r+');

View File

@ -54,23 +54,24 @@
$argv = func_get_args(); $argv = func_get_args();
$argc = count($argv); $argc = count($argv);
/* (2) If RandomCreation */
/* (2) If CrossoverCreation */ if( $argc > 3 && is_numeric($argv[0]) && is_numeric($argv[1]) && is_numeric($argv[2]) && is_numeric($argv[3]) )
if( $argc > 1 && $argv[0] instanceof Genome && $argv[1] instanceof Genome )
$this->construct_crossover($argv[0], $argv[1]);
/* (3) If RandomCreation */
else if( $argc > 3 && is_numeric($argv[0]) && is_numeric($argv[1]) && is_numeric($argv[2]) && is_numeric($argv[3]) )
$this->construct_new($argv[0], $argv[1], $argv[2], $argv[3]); $this->construct_new($argv[0], $argv[1], $argv[2], $argv[3]);
/* (3) If CrossoverCreation */
else if( $argc > 1 && $argv[0] instanceof Genome && $argv[1] instanceof Genome )
$this->construct_crossover($argv[0], $argv[1]);
/* (4) If InheritanceCreation (clone) */ /* (4) If InheritanceCreation (clone) */
else if( $argc > 0 && $argv[0] instanceof Genome ) else if( $argc > 0 && $argv[0] instanceof Genome )
$this->construct_inheritance($argv[0]); $this->construct_inheritance($argv[0]);
/* (5) If no match */ /* (5) If no match */
else else
throw new \Error('Invalid Genome constructor\'s arguments.'); throw new \Exception('Invalid Genome constructor\'s arguments.');
/* (6) Default values */
$this->fitness = null;
$this->callback = function(){}; $this->callback = function(){};
} }
@ -159,7 +160,7 @@
/* (5) Do random crossover for synapses */ /* (5) Do random crossover for synapses */
$this->synapses = []; $this->synapses = [];
for( $i = 0, $l = $this->neurons*($this->inputN+$this->outputN+$this->neurons*$this->layers) ; $i < $l ; $i++ ) for( $i = 0, $l = count($mother->synapses) ; $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];
@ -180,7 +181,7 @@
public function setCallback($callback=null){ public function setCallback($callback=null){
/* (1) Checks @callback argument */ /* (1) Checks @callback argument */
if( !is_callable($callback) ) if( !is_callable($callback) )
throw new \Error('Wrong argument for Genome\'s callback function.'); throw new \Exception('Wrong argument for Genome\'s callback function.');
/* (2) Set callback function */ /* (2) Set callback function */
$this->callback = $callback; $this->callback = $callback;
@ -194,13 +195,27 @@
public function setFitness($fitness=null){ public function setFitness($fitness=null){
/* (1) Checks @fitness argument */ /* (1) Checks @fitness argument */
if( !is_numeric($fitness) ) if( !is_numeric($fitness) )
throw new \Error('Wrong argument for specifying Genome\'s fitness.'); throw new \Exception('Wrong argument for specifying Genome\'s fitness.');
/* (2) Set fitness */ /* (2) Set fitness */
$this->fitness = floatval($fitness); $this->fitness = floatval($fitness);
} }
/************************************************
**** Getter ****
************************************************/
/* RETURNS THE FITNESS OF THE GENOME
*
* @return fitness<double> Current fitness (or NULL if not defined)
*
*/
public function getFitness(){
return $this->fitness;
}
/************************************************ /************************************************
**** Genome Actions **** **** Genome Actions ****
************************************************/ ************************************************/
@ -213,10 +228,10 @@
public function mutation($threshold=0.5){ public function mutation($threshold=0.5){
/* (1) Checks @threshold argument */ /* (1) Checks @threshold argument */
if( floatval($threshold) !== $threshold || $threshold < 0 || $threshold > 1 ) if( floatval($threshold) !== $threshold || $threshold < 0 || $threshold > 1 )
throw new \Error('Invalid threshold for Genome mutation.'); throw new \Exception('Invalid threshold for Genome mutation.');
/* (2) Calculates how many neurons/synapses to mutate */ /* (2) Calculates how many neurons/synapses to mutate */
$synapsesMutations = round( (count($this->synapses) - 1) * $threshold ); $synapsesMutations = round( (count($this->synapses) - 1) * rand(0, $threshold*self::MAX)/self::MAX );
/* (3) Choose random synapses' indexes */ /* (3) Choose random synapses' indexes */
$iSynapses = []; $iSynapses = [];
@ -243,7 +258,7 @@
public function train($input=null, $callback=null){ public function train($input=null, $callback=null){
/* (1) Checks @input argument */ /* (1) Checks @input argument */
if( !is_array($input) || count($input) !== $this->inputN ) if( !is_array($input) || count($input) !== $this->inputN )
throw new \Error('Invalid @input for Genome\'s training.'); throw new \Exception('Invalid @input for Genome\'s training.');
/* (2) Checks optional @callback argument */ /* (2) Checks optional @callback argument */
if( is_callable($callback) ) if( is_callable($callback) )
@ -366,7 +381,7 @@
/* (3) If between hidden/output */ /* (3) If between hidden/output */
}else if( $layer == $this->layers+1 ){ }else if( $layer == $this->layers+1 ){
$offset = $this->neurons * ($this->inputN+$this->neurons*$this->layers); $offset = $this->neurons * ($this->inputN+$this->neurons*($this->layers-1));
for( $s = $offset+$neuron, $sl = $offset+$this->neurons*$this->outputN ; $s < $sl ; $s += $this->outputN ) for( $s = $offset+$neuron, $sl = $offset+$this->neurons*$this->outputN ; $s < $sl ; $s += $this->outputN )
yield $this->inputN+$this->neurons*($this->layers-1) + ($s-$offset-$neuron)/$this->outputN => $s; yield $this->inputN+$this->neurons*($this->layers-1) + ($s-$offset-$neuron)/$this->outputN => $s;
@ -408,21 +423,21 @@
*/ */
public function unserialize($serialized){ public function unserialize($serialized){
/* (1) Segmenting data */ /* (1) Segmenting data */
$segments = explode(';', $serialized); $segments = explode(';', trim($serialized) );
// Manage segmentation error // Manage segmentation error
if( count($segments) < 3 ) if( count($segments) < 2 )
throw new \Error('Format error during Genome unserialization.'); throw new \Exception('Format error during Genome unserialization.');
/* (2) Get global attributes */ /* (2) Get global attributes */
$globals = explode(',', $segments[0]); $globals = explode(',', $segments[0]);
if( count($globals) < 4 ) if( count($globals) < 4 )
throw new \Error('Format error during Genome unserialization.'); throw new \Exception('Format error during Genome unserialization.');
$this->layers = intval($globals[0]); $this->layers = intval($globals[0]);
$this->inputN = intval($globals[1]); $this->inputN = intval($globals[1]);
$this->layers = intval($globals[2]); $this->neurons = intval($globals[2]);
$this->outputN = intval($globals[3]); $this->outputN = intval($globals[3]);
/* (3) Get synapses values */ /* (3) Get synapses values */

View File

@ -34,14 +34,14 @@
/* (1) Checks argument */ /* (1) Checks argument */
if( is_null($storage=NeuralNetworkCore::getStorage($storage)) ) if( is_null($storage=NeuralNetworkCore::getStorage($storage)) )
throw new Error('Wrong NeuralNetwork loader\'s argument.'); throw new \Exception('Wrong NeuralNetwork loader\'s argument.');
/* (2) If files doesn't exist, raise error */ /* (2) If files doesn't exist, raise error */
if( !$storage[0]['exists'] || !$storage[1]['exists'] || !$storage[2]['exists'] ) if( !$storage['nn']['exists'] )
throw new Error('Loaded storage have file(s) missing.'); throw new \Exception('Loaded storage have file(s) missing.');
/* (3) Unserialize last NeuralNetwork */ /* (3) Unserialize last NeuralNetwork */
$last_network = FileManager::read($storage[0]['filename']); $last_network = FileManager::read($storage['nn']['filename']);
/* (4) Creates and fill instance */ /* (4) Creates and fill instance */
$instance = new NeuralNetworkCore(0, 0); $instance = new NeuralNetworkCore(0, 0);

View File

@ -11,21 +11,22 @@
************************************************/ ************************************************/
private $maxGnr; // Maximum generation iterations private $maxGnr; // Maximum generation iterations
private $maxGnm; // Maximum genomes per generation private $maxGnm; // Maximum genomes per generation
private $kptGnm; // Number of genomes kept for each generation
private $mutThr; // Mutation threshold private $mutThr; // Mutation threshold
private $fitEnd; // Fitness range to end process private $fitEnd; // Fitness range to end process
private $numHid; // Number of hidden layer(s) private $numHid; // Number of hidden layer(s)
private $numNeu; // Number of neurons for each hidden layer private $numNeu; // Number of neurons for each hidden layer
private $inpNeu; // Number of input neurons
private $outNeu; // Number of output neurons
private $storage; // path to storage private $storage; // path to storage
private $callback; // callback training function
/************************************************ /************************************************
**** LOCAL ATTRIBUTES **** **** LOCAL ATTRIBUTES ****
************************************************/ ************************************************/
private $gnr; // Current generation index public $gnr; // Current generation index
private $gmns; // Current generation's genomes public $gnm; // Current genome index
private $gnm; // Current genome index private $genome; // Current genome instance
private $fit; // Current fitness
@ -70,15 +71,18 @@
/* (2) Checks file's existence and returns it */ /* (2) Checks file's existence and returns it */
return [ return [
[ 'nn' => [
'filename' => $absolute_path.'.nn', // will contain neural network data 'filename' => $absolute_path.'.nn', // will contain neural network data
'exists' => is_file($absolute_path.'.nn') 'exists' => is_file($absolute_path.'.nn')
],[ ], 'ex' => [
'filename' => $absolute_path.'.ex', // will contain samples 'filename' => $absolute_path.'.ex', // will contain samples
'exists' => is_file($absolute_path.'.ex') 'exists' => is_file($absolute_path.'.ex')
],[ ], 'gn' => [
'filename' => $absolute_path.'.ln', // will contain values & weights 'filename' => $absolute_path.'.gn', // will contain genomes of the generation
'exists' => is_file($absolute_path.'.ln') 'exists' => is_file($absolute_path.'.gn')
], 'ft' => [
'filename' => $absolute_path.'.ft', // will contain genomes' fitness
'exists' => is_file($absolute_path.'.ft')
] ]
]; ];
@ -107,17 +111,16 @@
/* (2) Default attributes */ /* (2) Default attributes */
$default = self::conf()['default']; $default = self::conf()['default'];
$this->setKeptGenomes($default['genomes_kept']); // default value
$this->setMutationThreshold($default['mutation_threshold']); // default value $this->setMutationThreshold($default['mutation_threshold']); // default value
$this->setFitnessEnd($default['fitness_end']); // default value $this->setFitnessEnd($default['fitness_end']); // default value
$this->setHiddenLayersCount($default['hidden_layers']); // default value $this->setHiddenLayersCount($default['hidden_layers']); // default value
$this->setHiddenLayerNeuronsCount($default['layer_neurons']); // default value $this->setHiddenLayerNeuronsCount($default['layer_neurons']); // default value
$this->max = null; // default value $this->max = null; // default value
$this->setStorage($default['storage']); // default value $this->setStorage($default['storage']); // default value
$this->callback = function(){}; // default value
} }
/************************************************ /************************************************
**** Attributes Setters **** **** Attributes Setters ****
************************************************/ ************************************************/
@ -146,12 +149,12 @@
/* [2] Initializes files /* [2] Initializes files
=========================================================*/ =========================================================*/
/* (1) Creates directory/ies */ /* (1) Creates directory/ies */
if( !is_dir(dirname(($this->storage[0]['filename']))) ) if( !is_dir(dirname(($this->storage['nn']['filename']))) )
mkdir( dirname($this->storage[0]['filename']), 0775, true ); mkdir( dirname($this->storage['nn']['filename']), 0775, true );
// Checks // Checks
if( !is_dir(dirname(($this->storage[0]['filename']))) ) if( !is_dir(dirname(($this->storage['nn']['filename']))) )
throw new \Error('Error creating directory: '.dirname(($this->storage[0]['filename']))); throw new \Exception('Error creating directory: '.dirname(($this->storage['nn']['filename'])));
/* (2) Creates files */ /* (2) Creates files */
foreach($this->storage as $file) foreach($this->storage as $file)
@ -215,14 +218,49 @@
$this->numHid = $numHid; $this->numHid = $numHid;
} }
/* SET NUMBER OF NEURONS OF THE INPUT LAYER
*
* @inpNeu<int> Number of neurons for the input layer
*
*/
public function setInputLayerCount($inpNeu){
if( abs(intval($inpNeu)) !== $inpNeu ) return;
$this->inpNeu = $inpNeu;
}
/* SET NUMBER OF NEURONS OF THE OUTPUT LAYER
*
* @outNeu<int> Number of neurons for the output layer
*
*/
public function setOutputLayerCount($outNeu){
if( abs(intval($outNeu)) !== $outNeu ) return;
$this->outNeu = $outNeu;
}
/************************************************ /************************************************
**** Sample Setters **** **** Sample Setters ****
************************************************/ ************************************************/
/* ADD SAMPLE TO THE NEURAL NETWORK /* ADD SAMPLE TO THE NEURAL NETWORK
*
* @input<Array> Set of input of the sample
* @output<Array> Set of output of the sample
*
*/
public function addSample($input, $output){ public function addSample($input, $output){
FileManager::append( $this->storage[1]['filename'], implode(',',$input) .';'. implode(',',$output) ); /* (1) Checks number of input neurons */
if( !is_array($input) || is_null($this->inpNeu) || count($input) != $this->inpNeu )
throw new \Exception('Wrong @input argument for addSample() method.');
/* (2) Checks number of output neurons */
if( !is_array($output) || is_null($this->outNeu) || count($output) != $this->outNeu )
throw new \Exception('Wrong @output argument for addSample() method.');
FileManager::append( $this->storage['ex']['filename'], implode(',',$input) .';'. implode(',',$output) );
} }
@ -245,9 +283,9 @@
$storage = self::getStorage($path); $storage = self::getStorage($path);
/* (2) Checks if files doesn't exist */ /* (2) Checks if files doesn't exist */
if( $storage[0]['exists'] || $storage[1]['exists'] || $storage[2]['exists'] ) if( $storage['nn']['exists'] )
if( !$override ) if( !$override )
throw new \Error('This storage already exists, you can only load() it.'); throw new \Exception('This storage already exists, you can only load() it.');
/* [2] Creates storage & its files /* [2] Creates storage & its files
@ -264,65 +302,185 @@
/* [3] Stores data /* [3] Stores data
=========================================================*/ =========================================================*/
/* (1) Stores NeuralNetwork state (attributes) */ /* (1) Stores NeuralNetwork state (attributes) */
FileManager::write($storage[0]['filename'], $this->serialize()); FileManager::write($storage['nn']['filename'], $this->serialize());
/* (2) Stores samples */ /* (2) Stores samples */
FileManager::write($storage[1]['filename'], FileManager::read($last_storage[1]['filename'])); FileManager::write($storage['ex']['filename'], FileManager::read($last_storage['ex']['filename']));
/* (3) Stores NeuralNetwork values & weights */ /* (3) Stores NeuralNetwork values & weights */
FileManager::write($storage[2]['filename'], FileManager::read($last_storage[2]['filename'])); FileManager::write($storage['gn']['filename'], FileManager::read($last_storage['gn']['filename']));
} }
/* INITIALIZES THE LEARNING ROUTINE
/* STARTS THE LEARNING ROUTINE
* *
* @callback<Function> Callback function to display current state * @callback<Function> Callback function to display current state
* *
*/ */
public function learn($callback=null){ public function initLearningRoutine($callback=null){
/* [1] Manages @callback argument /* [1] Manages @callback argument
=========================================================*/ =========================================================*/
if( !is_callable($callback) ) if( !is_callable($callback) )
$callback = function(){}; $this->callback = function(){};
else
$this->callback = $callback;
/* [2] Creates the neural network /* [2] Creates the First generation and serialize it
=========================================================*/ =========================================================*/
// best of last generation /* (1) Initializes data & storage */
$best = null; $this->gnr = 0;
$this->gnm = 0;
FileManager::write($this->storage['gn']['filename'], '');
FileManager::write($this->storage['ft']['filename'], '');
/* (2) Stores random genomes to storage */
for( $g = 0 ; $g < $this->maxGnm ; $g++ ){
$gnm = new Genome($this->numHid, $this->numNeu, $this->inpNeu, $this->outNeu);
FileManager::append($this->storage['gn']['filename'], $gnm->serialize());
}
}
/* RETURNS THE CURRENT GENOME
*
* @return genome<Genome> Returns the current genome
*
*/
public function getGenome(){
/* (1) Checks if learning routine has beem started */
if( !is_numeric($this->gnm) )
throw new \Exception('Learning routine closed.');
/* (2) Reads the current genome from storage */
$serialized = FileManager::readline($this->storage['gn']['filename'], $this->gnm);
/* (3) Unserializes genome */
$this->genome = new Genome(2, 2, 2, 2);
try{
$this->genome->unserialize($serialized);
$this->genome->setCallback($this->callback);
return $this->genome;
/* (4) If error */
}catch(Exception $e){ return null; }
}
/* ITERATES TO THE NEXT GENOME (IF SAME GENERATION)
*
*/
public function nextGenome(){
/* (0) Checks if Genome's fitness has been set
---------------------------------------------------------*/
if( !($this->genome instanceof Genome) || is_null($this->genome->getFitness()) )
throw new \Exception('The learning routine is closed.');
/* (1) Stores fitness */
FileManager::append($this->storage['ft']['filename'], strval($this->genome->getFitness()) );
/* (1) For each generation /* (1) Iterates if possible
---------------------------------------------------------*/ ---------------------------------------------------------*/
for( $this->gnr = 0 ; $this->gnr < $this->maxGnr ; $this->gnr++ ){ if( $this->gnm < $this->maxGnm-1 ){
/* (1) Initializes genome list for current generation */ $this->gnm++;
$this->gnms = [];
/* (2) For each genome of the generation */ /* (2) If must change generation
for( $this->gnm = 0 ; $this->gnm < $this->maxGnm ; $this->gnm++ ){ ---------------------------------------------------------*/
}else if( $this->gnr < $this->maxGnr-1 ){
// {2.1} First Generation -> random genomes // /* (1) Update generation & genome indexes */
if( $this->gnr === 0 ) $this->gnr++;
$this->gnms[$this->gnm] = new Genome($this->numHid, $this->numNeu); $this->gnm = 0;
// {2.2} Others generations -> crossover + mutation // /* (2) Fetch the whole generation fitness values */
else{ $ftRead = FileManager::read($this->storage['ft']['filename']);
$this->gnms[$this->gnm] = new Genome($best['father'], $best['mother']); $fitnesses = explode("\n", trim($ftRead) );
$this->gnms[$this->gnm]->mutation($this->mutThr);
}
/* (3) Calculate fitness */ /* (3) Extract @mother & @father indexes */
// ... blablabla $iBest = $this->bestFitnesses($fitnesses);
/* (4) Extract best 2 genomes */
$sFather = FileManager::readline($this->storage['gn']['filename'], $iBest[0]);
$sMother = FileManager::readline($this->storage['gn']['filename'], $iBest[1]);
/* (5) Unserializes them */
$father = new Genome(2, 2, 2, 2);
$father->unserialize($sFather);
$mother = new Genome(2, 2, 2, 2);
$mother->unserialize($sMother);
/* (6) Create new generation */
FileManager::write($this->storage['gn']['filename'], '');
FileManager::write($this->storage['ft']['filename'], '');
for( $g = 0 ; $g < $this->maxGnm ; $g++ ){
// {6.1} Re-use father //
if( $g == 0 )
FileManager::append($this->storage['gn']['filename'], $father->serialize());
// {6.2} Re-use mother //
else if( $g == 1 )
FileManager::append($this->storage['gn']['filename'], $mother->serialize());
// {6.3} Do cross-over + mutation for the rest //
else{
$gnm = new Genome($father, $mother);
$gnm->mutation($this->mutThr);
FileManager::append($this->storage['gn']['filename'], $gnm->serialize());
} }
} }
// TODO: Select best genomes based on fitness
$best = null;
/* (3) If end of process
---------------------------------------------------------*/
}else{
$this->gnr = null;
$this->gnm = null;
}
} }
/************************************************
**** Utility ****
************************************************/
/* RETURNS THE 2 BEST FITNESSES FROM A LIST
*
* @fitnesses<Array> List of indexes fitnesses
*
* @return best<Array> List of the 2 indexes of the best fitnesses
*
*/
private static function bestFitnesses($fitnesses=null){
/* (1) Checks @fitnesses argument */
if( !is_array($fitnesses) )
throw new \Exception('Fitness list format error.');
/* (1) Find father (best)
---------------------------------------------------------*/
/* (1) Select greatest fitness value */
arsort($fitnesses);
/* (2) Attributes @father & @mother indexes */
$iFather = null;
$iMother = null;
$c = 0;
foreach($fitnesses as $k=>$v){
if( $c == 0 ) $iFather = $k;
else if( $c == 1 ) $iMother = $k;
else break;
$c++;
}
return [ $iFather, $iMother ];
}
/************************************************ /************************************************
**** Serialization Methods **** **** Serialization Methods ****
@ -340,11 +498,12 @@
/* (2) Adding attributes */ /* (2) Adding attributes */
$json['maxGnr'] = $this->maxGnr; $json['maxGnr'] = $this->maxGnr;
$json['maxGnm'] = $this->maxGnm; $json['maxGnm'] = $this->maxGnm;
$json['kptGnm'] = $this->kptGnm;
$json['mutThr'] = $this->mutThr; $json['mutThr'] = $this->mutThr;
$json['fitEnd'] = $this->fitEnd; $json['fitEnd'] = $this->fitEnd;
$json['numHid'] = $this->numHid; $json['numHid'] = $this->numHid;
$json['numNeu'] = $this->numNeu; $json['numNeu'] = $this->numNeu;
$json['inpNeu'] = $this->inpNeu;
$json['outNeu'] = $this->outNeu;
$json['storage'] = $this->storage; $json['storage'] = $this->storage;
@ -368,11 +527,12 @@
/* (3) Attributing json attributes */ /* (3) Attributing json attributes */
$this->maxGnr = $json['maxGnr']; $this->maxGnr = $json['maxGnr'];
$this->maxGnm = $json['maxGnm']; $this->maxGnm = $json['maxGnm'];
$this->kptGnm = $json['kptGnm'];
$this->mutThr = $json['mutThr']; $this->mutThr = $json['mutThr'];
$this->fitEnd = $json['fitEnd']; $this->fitEnd = $json['fitEnd'];
$this->numHid = $json['numHid']; $this->numHid = $json['numHid'];
$this->numNeu = $json['numNeu']; $this->numNeu = $json['numNeu'];
$this->inpNeu = $json['inpNeu'];
$this->outNeu = $json['outNeu'];
$this->storage = $json['storage']; $this->storage = $json['storage'];
} }

View File

@ -1,8 +0,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

View File

@ -6,3 +6,11 @@
1,0,1;0,1 1,0,1;0,1
1,1,0;1,1 1,1,0;1,1
1,1,1;1,1 1,1,1;1,1
0,0,0;0,0
0,0,2;0,2
0,2,0;0,2
0,2,2;0,2
2,0,0;0,0
2,0,2;0,2
2,2,0;2,2
2,2,2;2,2

View File

@ -0,0 +1,520 @@
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
2
0
0
0
2
0
0
0
0
0
2
2
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
2
0
2
0
0
2
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
2
2
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
2
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
2
0
0
2
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
2
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
2
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2

File diff suppressed because it is too large Load Diff

View File

@ -1 +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}]} {"maxGnr":50,"maxGnm":1000,"kptGnm":2,"mutThr":0.3,"fitEnd":1,"numHid":2,"numNeu":3,"inpNeu":3,"outNeu":2,"storage":{"nn":{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/test\/test1.nn","exists":false},"ex":{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/test\/test1.ex","exists":false},"gn":{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/test\/test1.gn","exists":false},"ft":{"filename":"\/home\/xdrm-brackets\/Desktop\/git.xdrm.io\/neural-network.php\/build\/neuralnetwork\/storage\/test\/test1.ft","exists":false}}}

View File

@ -2,7 +2,6 @@
"storage_parent": "/build/neuralnetwork/storage", "storage_parent": "/build/neuralnetwork/storage",
"default": { "default": {
"genomes_kept": 2,
"mutation_threshold": 0.3, "mutation_threshold": 0.3,
"fitness_end": 1, "fitness_end": 1,
"storage": "_buffer", "storage": "_buffer",

View File

@ -10,38 +10,103 @@
return [($abc[0] & $abc[1]), $abc[1] | $abc[2]]; return [($abc[0] & $abc[1]), $abc[1] | $abc[2]];
} }
if( false && 'test_creating_dataset' ){ if( true && 'test_creating_dataset' ){
$part = 1;
echo "Welcome to neural-network.php\n"; echo "Welcome to neural-network.php\n";
echo "-----------------------------\n"; echo "-----------------------------\n\n";
$nn = NeuralNetwork::create(50, 100); /* [1] Trying to load neural network
=========================================================*/
try{
$nn->setHiddenLayersCount(2); $nn = NeuralNetwork::load('test/test1');
$nn->setHiddenLayerNeuronsCount(3); echo "$part. NeuralNetwork loaded from 'test/test1'\n"; $part++;
$d = [0, 0, 0]; $nn->addSample($d, behaviour($d)); /* [2] Else, creates it
$d = [0, 0, 1]; $nn->addSample($d, behaviour($d)); =========================================================*/
$d = [0, 1, 0]; $nn->addSample($d, behaviour($d)); }catch(\Exception $e){
$d = [0, 1, 1]; $nn->addSample($d, behaviour($d));
$d = [1, 0, 0]; $nn->addSample($d, behaviour($d)); $nn = NeuralNetwork::create(50, 1000);
$d = [1, 0, 1]; $nn->addSample($d, behaviour($d));
$d = [1, 1, 0]; $nn->addSample($d, behaviour($d)); $nn->setHiddenLayersCount(4);
$d = [1, 1, 1]; $nn->addSample($d, behaviour($d)); $nn->setHiddenLayerNeuronsCount(3);
$d = [0, 0, 0]; $nn->addSample($d, behaviour($d)); $nn->setInputLayerCount(3);
$d = [0, 0, 2]; $nn->addSample($d, behaviour($d)); $nn->setOutputLayerCount(2);
$d = [0, 2, 0]; $nn->addSample($d, behaviour($d));
$d = [0, 2, 2]; $nn->addSample($d, behaviour($d)); echo "$part. NeuralNetwork configured\n"; $part++;
$d = [2, 0, 0]; $nn->addSample($d, behaviour($d));
$d = [2, 0, 2]; $nn->addSample($d, behaviour($d)); $d = [0, 0, 0]; $nn->addSample($d, behaviour($d));
$d = [2, 2, 0]; $nn->addSample($d, behaviour($d)); $d = [0, 0, 1]; $nn->addSample($d, behaviour($d));
$d = [2, 2, 2]; $nn->addSample($d, behaviour($d)); $d = [0, 1, 0]; $nn->addSample($d, behaviour($d));
$d = [0, 1, 1]; $nn->addSample($d, behaviour($d));
$d = [1, 0, 0]; $nn->addSample($d, behaviour($d));
$d = [1, 0, 1]; $nn->addSample($d, behaviour($d));
$d = [1, 1, 0]; $nn->addSample($d, behaviour($d));
$d = [1, 1, 1]; $nn->addSample($d, behaviour($d));
$d = [0, 0, 0]; $nn->addSample($d, behaviour($d));
$d = [0, 0, 2]; $nn->addSample($d, behaviour($d));
$d = [0, 2, 0]; $nn->addSample($d, behaviour($d));
$d = [0, 2, 2]; $nn->addSample($d, behaviour($d));
$d = [2, 0, 0]; $nn->addSample($d, behaviour($d));
$d = [2, 0, 2]; $nn->addSample($d, behaviour($d));
$d = [2, 2, 0]; $nn->addSample($d, behaviour($d));
$d = [2, 2, 2]; $nn->addSample($d, behaviour($d));
echo "$part. Samples added to NeuralNetwork\n"; $part++;
$nn->store('test/test1', true);
echo "$part. NeuralNetwork stored to 'test/test1'\n"; $part++;
}
/* [2] Initializing learning routine
=========================================================*/
$fitness = 0;
$max_fit = 0;
$nn->initLearningRoutine(function($input, $output){
global $fitness;
if( $output[0] == behaviour($input)[0] ) $fitness++;
if( $output[1] == behaviour($input)[1] ) $fitness++;
});
echo "$part. Learning routine initialized.\n"; $part++;
/* [3] Learning through generations and genomes
=========================================================*/
/* (1) For each generation */
for( $gnr = 0 ; $gnr < 50 ; $gnr++ ){
/* (2) For each genome */
for( $gnm = 0 ; $gnm < 1000 ; $gnm++ ){
$fitness = 0;
/* (2.1) Get current genome */
$g = $nn->getGenome();
echo "\r[x] genome ".($nn->gnm+1)."/1000 on generation ".($nn->gnr+1)."/50 - max fitness: $max_fit ";
/* (2.2) Train genome with random samples */
for( $r = 0 ; $r < 100 ; $r++ )
$g->train([rand(0,10), rand(0,10), rand(0,10)]);
/* (2.3) Set fitness & go to next genome */
if( $fitness > $max_fit ) $max_fit = $fitness;
$g->setFitness($fitness);
$nn->nextGenome();
}
}
$nn->store('test/test1', true);
} }
if( false && 'load_neural_network' ){ if( false && 'load_neural_network' ){
$nn = NeuralNetwork::load('test/test1'); $nn = NeuralNetwork::load('test/test1');
@ -50,7 +115,7 @@
if( false && '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, 3, 2); // 2 layers of 3 neurons each -> randomly filled
echo "A : ".$a->serialize()."\n"; echo "A : ".$a->serialize()."\n";
@ -72,7 +137,7 @@
} }
if( true ){ if( false ){
$g = new Genome(2, 3, 3, 2); $g = new Genome(2, 3, 3, 2);
$fitness = 0; $fitness = 0;