pub struct Pool { /* private fields */ }
Expand description
Implementations§
Source§impl Pool
impl Pool
Sourcepub fn new(
inputs: usize,
outputs: usize,
population_size: usize,
connection_mut_rate: f32,
node_mut_rate: f32,
weight_mut_rate: f32,
perturb_rate: f32,
weight_mut_step_size: f32,
disable_mut_rate: f32,
enable_mut_rate: f32,
excess_coef: f32,
disjoint_coef: f32,
weight_diff_coef: f32,
species_threshold: f32,
mut_only_rate: f32,
mate_only_rate: f32,
crossover_rate: f32,
species_dropoff_age: usize,
age_significance: f32,
survival_threshold: f32,
) -> Self
pub fn new( inputs: usize, outputs: usize, population_size: usize, connection_mut_rate: f32, node_mut_rate: f32, weight_mut_rate: f32, perturb_rate: f32, weight_mut_step_size: f32, disable_mut_rate: f32, enable_mut_rate: f32, excess_coef: f32, disjoint_coef: f32, weight_diff_coef: f32, species_threshold: f32, mut_only_rate: f32, mate_only_rate: f32, crossover_rate: f32, species_dropoff_age: usize, age_significance: f32, survival_threshold: f32, ) -> Self
Initialize a new Pool with the given number of inputs
, outputs
, and
overriding all of the default constants. (If you wish to use some of
the defaults they are accessible in the defaults module.)
Sourcepub fn with_defaults(inputs: usize, outputs: usize) -> Self
pub fn with_defaults(inputs: usize, outputs: usize) -> Self
Initialize a new Pool with the given number of inputs
, outputs
,
and use all of the default constants.
Examples found in repository?
13fn main() {
14 let args: Vec<String> = env::args().collect();
15
16 if args.len() < 2 {
17 println!("Usage: '{} train' to train a new comparer.", args[0]);
18 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
19 return;
20 }
21
22 if args[1] == "train" {
23 // One input node for each input in the training data structure
24 let input_nodes = 4;
25 // One output node with the "prediction"
26 let output_nodes = 1;
27 // Create a new gene pool with an initial population of genomes
28 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
29
30 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
31
32 let mut trainer = Trainer::new(training_data);
33 // This function will be called once per Genome per piece of
34 // TrainingData in each generation, passing the values of the
35 // output nodes of the Genome as well as the expected result
36 // from the TrainingData.
37 trainer.evaluate_fn = adding_fitness_func;
38 trainer.hidden_activation = linear_activation;
39 trainer.output_activation = linear_activation;
40
41 // Train over the course of 100 generations
42 trainer.train(&mut gene_pool, 100);
43
44 let best_genome = gene_pool.get_best_genome();
45
46 println!("Serializing best genome to winner.json");
47 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome).unwrap();
48 } else {
49 if args.len() < 7 {
50 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
51 return;
52 }
53 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
54 let input1 = args[3]
55 .parse::<f32>()
56 .expect("Couldn't parse input1 as f32");
57 let input2 = args[4]
58 .parse::<f32>()
59 .expect("Couldn't parse input2 as f32");
60 let input3 = args[5]
61 .parse::<f32>()
62 .expect("Couldn't parse input1 as f32");
63 let input4 = args[6]
64 .parse::<f32>()
65 .expect("Couldn't parse input2 as f32");
66 // Note that this is the exact same function we used in training
67 // further up!
68 genome.evaluate(
69 &vec![input1, input2, input3, input4],
70 Some(linear_activation),
71 Some(linear_activation),
72 );
73 println!(
74 "Sum of inputs is..........{}",
75 genome.get_outputs()[0] as u32
76 );
77 }
78}
More examples
36fn main() {
37 let args: Vec<String> = env::args().collect();
38
39 if args.len() < 2 {
40 println!("Usage: '{} train' to train a new comparer.", args[0]);
41 println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
42 return;
43 }
44
45 if args[1] == "train" {
46 // One input node for each input in the TrainingData structure
47 let input_nodes = 2;
48 // One output node with the "prediction"
49 let output_nodes = 1;
50 // Create a new gene pool with an initial population of genomes
51 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
52
53 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
54
55 // These variables are used to keep track of the top performer, so we
56 // can write it out later.
57 let mut best_genome: Option<Genome> = None;
58 let mut best_fitness = 0.0;
59
60 // We use a label here to allow us to break out if we find a genome
61 // with a perfect score before we run through all of the generations.
62 'outer: for generation in 0..1000 {
63 println!("Evaluating generation {}", generation + 1);
64 let total_species = gene_pool.len();
65 for s in 0..total_species {
66 let species = &mut gene_pool[s];
67 let genomes_in_species = species.len();
68 for g in 0..genomes_in_species {
69 let genome = &mut species[g];
70 let mut fitness = 0.0;
71
72 for td in &training_data {
73 // Evaluate the genome using the training data as the
74 // initial inputs.
75 genome.evaluate(&td.inputs[0..2].to_vec(), None, None);
76
77 // We add this to the existing fitness for the genome
78 // to ensure that the genomes with the best score across
79 // all tests will have the highest overall fitness.
80 fitness += fitness_func(genome.get_outputs()[0], td.expected[0]);
81 }
82
83 // Update the genome with the calculate fitness score.
84 // (This is important, as this fitness score is needed to
85 // spawn the next generation correctly.)
86 genome.update_fitness(fitness);
87
88 if fitness > best_fitness {
89 println!(
90 "Species {} Genome {} increased best fitness to {}",
91 s, g, best_fitness
92 );
93 best_fitness = fitness;
94 best_genome = Some(genome.clone());
95 }
96
97 if fitness == PERFECT_SCORE {
98 println!("Found a perfect genome!");
99 break 'outer;
100 }
101 }
102 }
103 // Spawn the next generation.
104 gene_pool.new_generation();
105 }
106 println!("Serializing best genome to winner.json");
107 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
108 .unwrap();
109 } else {
110 if args.len() < 5 {
111 println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
112 return;
113 }
114 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
115 let input1 = args[3]
116 .parse::<f32>()
117 .expect("Couldn't parse input1 as f32");
118 let input2 = args[4]
119 .parse::<f32>()
120 .expect("Couldn't parse input2 as f32");
121 genome.evaluate(&vec![input1, input2], None, None);
122 if genome.get_outputs()[0] > 0.5 {
123 println!("Predicted that {} is greater than {}!", input1, input2);
124 } else {
125 println!(
126 "Predicted that {} is equal or less than {}!",
127 input1, input2
128 );
129 }
130 }
131}
14fn main() {
15 let args: Vec<String> = env::args().collect();
16
17 if args.len() < 2 {
18 println!("Usage: '{} train' to train a new comparer.", args[0]);
19 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
20 return;
21 }
22
23 if args[1] == "train" {
24 // One input node for each input in the TrainingData structure
25 let input_nodes = 4;
26 // One output node with the "prediction"
27 let output_nodes = 1;
28 // Create a new gene pool with an initial population of genomes
29 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
30
31 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
32
33 // These variables are used to keep track of the top performer, so we
34 // can write it out later.
35 let mut best_genome: Option<Genome> = None;
36 let mut best_fitness = 0.0;
37
38 // We will test genomes from 100 generations
39 for generation in 0..100 {
40 println!("Evaluating generation {}", generation + 1);
41 let total_species = gene_pool.len();
42 // As genomes diverge in structure and configuration, they will
43 // be divided into separate species.
44 for s in 0..total_species {
45 let species = &mut gene_pool[s];
46 let genomes_in_species = species.len();
47 for g in 0..genomes_in_species {
48 let genome = &mut species[g];
49
50 let mut fitness = 0.0;
51 for td in &training_data {
52 // Evaluate the genome using the training data as the
53 // initial inputs.
54 genome.evaluate(
55 &td.inputs[0..4].to_vec(),
56 Some(linear_activation),
57 Some(linear_activation),
58 );
59
60 // We add this to the existing fitness for the genome
61 // to ensure that the genomes with the best score across
62 // all tests will have the highest overall fitness.
63 fitness += adding_fitness_func(&genome.get_outputs(), &td.expected);
64 }
65
66 // Update the genome with the calculate fitness score.
67 // (This is important, as this fitness score is needed to
68 // spawn the next generation correctly.)
69 genome.update_fitness(fitness);
70
71 if fitness > best_fitness {
72 println!(
73 "Species {} Genome {} increased best fitness to {}",
74 s, g, best_fitness
75 );
76 best_fitness = fitness;
77 best_genome = Some(genome.clone());
78 }
79 }
80 }
81 // Spawn the next generation.
82 gene_pool.new_generation();
83 }
84 println!("Serializing best genome to winner.json");
85 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
86 .unwrap();
87 } else {
88 if args.len() < 7 {
89 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
90 return;
91 }
92 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
93 let input1 = args[3]
94 .parse::<f32>()
95 .expect("Couldn't parse input1 as f32");
96 let input2 = args[4]
97 .parse::<f32>()
98 .expect("Couldn't parse input2 as f32");
99 let input3 = args[5]
100 .parse::<f32>()
101 .expect("Couldn't parse input1 as f32");
102 let input4 = args[6]
103 .parse::<f32>()
104 .expect("Couldn't parse input2 as f32");
105 // Note that this is the exact same function we used in training
106 // further up!
107 genome.evaluate(
108 &vec![input1, input2, input3, input4],
109 Some(linear_activation),
110 Some(linear_activation),
111 );
112 println!(
113 "Sum of inputs is..........{}",
114 genome.get_outputs()[0] as u32
115 );
116 }
117}
Sourcepub fn train_population(
&mut self,
generations: usize,
training_data: &Vec<TrainingData>,
evaluate_fn: EvaluationFn,
hidden_activation: Option<ActivationFn>,
output_activation: Option<ActivationFn>,
)
pub fn train_population( &mut self, generations: usize, training_data: &Vec<TrainingData>, evaluate_fn: EvaluationFn, hidden_activation: Option<ActivationFn>, output_activation: Option<ActivationFn>, )
Trains a population of Genomes over generations
generations.
training_data
must be a &Vec of TrainingData. Each Genome will be
gevn the inputs from each TrainingData as inputs
to its network. evaluate_fn
will be called after each item of TrainingData
is fed to the Genome. This function will be passed a Vec of the Genome’s
outputs and the expected value or values from the
TrainingData. This function is expected to assess the Genome’s performance
by comparing the two, and return an f32 representing its “score”. The scores
from each call to evaluate_fn
will be summed together to form the final
fitness value of the Genome.
Sourcepub fn stats(&self) -> PoolStats
pub fn stats(&self) -> PoolStats
Returns the PoolStats at a moment in time. (If you need updated statistics you must call this method each time you need them.)
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Returns the number of Species in the Pool.
Examples found in repository?
36fn main() {
37 let args: Vec<String> = env::args().collect();
38
39 if args.len() < 2 {
40 println!("Usage: '{} train' to train a new comparer.", args[0]);
41 println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
42 return;
43 }
44
45 if args[1] == "train" {
46 // One input node for each input in the TrainingData structure
47 let input_nodes = 2;
48 // One output node with the "prediction"
49 let output_nodes = 1;
50 // Create a new gene pool with an initial population of genomes
51 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
52
53 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
54
55 // These variables are used to keep track of the top performer, so we
56 // can write it out later.
57 let mut best_genome: Option<Genome> = None;
58 let mut best_fitness = 0.0;
59
60 // We use a label here to allow us to break out if we find a genome
61 // with a perfect score before we run through all of the generations.
62 'outer: for generation in 0..1000 {
63 println!("Evaluating generation {}", generation + 1);
64 let total_species = gene_pool.len();
65 for s in 0..total_species {
66 let species = &mut gene_pool[s];
67 let genomes_in_species = species.len();
68 for g in 0..genomes_in_species {
69 let genome = &mut species[g];
70 let mut fitness = 0.0;
71
72 for td in &training_data {
73 // Evaluate the genome using the training data as the
74 // initial inputs.
75 genome.evaluate(&td.inputs[0..2].to_vec(), None, None);
76
77 // We add this to the existing fitness for the genome
78 // to ensure that the genomes with the best score across
79 // all tests will have the highest overall fitness.
80 fitness += fitness_func(genome.get_outputs()[0], td.expected[0]);
81 }
82
83 // Update the genome with the calculate fitness score.
84 // (This is important, as this fitness score is needed to
85 // spawn the next generation correctly.)
86 genome.update_fitness(fitness);
87
88 if fitness > best_fitness {
89 println!(
90 "Species {} Genome {} increased best fitness to {}",
91 s, g, best_fitness
92 );
93 best_fitness = fitness;
94 best_genome = Some(genome.clone());
95 }
96
97 if fitness == PERFECT_SCORE {
98 println!("Found a perfect genome!");
99 break 'outer;
100 }
101 }
102 }
103 // Spawn the next generation.
104 gene_pool.new_generation();
105 }
106 println!("Serializing best genome to winner.json");
107 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
108 .unwrap();
109 } else {
110 if args.len() < 5 {
111 println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
112 return;
113 }
114 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
115 let input1 = args[3]
116 .parse::<f32>()
117 .expect("Couldn't parse input1 as f32");
118 let input2 = args[4]
119 .parse::<f32>()
120 .expect("Couldn't parse input2 as f32");
121 genome.evaluate(&vec![input1, input2], None, None);
122 if genome.get_outputs()[0] > 0.5 {
123 println!("Predicted that {} is greater than {}!", input1, input2);
124 } else {
125 println!(
126 "Predicted that {} is equal or less than {}!",
127 input1, input2
128 );
129 }
130 }
131}
More examples
14fn main() {
15 let args: Vec<String> = env::args().collect();
16
17 if args.len() < 2 {
18 println!("Usage: '{} train' to train a new comparer.", args[0]);
19 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
20 return;
21 }
22
23 if args[1] == "train" {
24 // One input node for each input in the TrainingData structure
25 let input_nodes = 4;
26 // One output node with the "prediction"
27 let output_nodes = 1;
28 // Create a new gene pool with an initial population of genomes
29 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
30
31 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
32
33 // These variables are used to keep track of the top performer, so we
34 // can write it out later.
35 let mut best_genome: Option<Genome> = None;
36 let mut best_fitness = 0.0;
37
38 // We will test genomes from 100 generations
39 for generation in 0..100 {
40 println!("Evaluating generation {}", generation + 1);
41 let total_species = gene_pool.len();
42 // As genomes diverge in structure and configuration, they will
43 // be divided into separate species.
44 for s in 0..total_species {
45 let species = &mut gene_pool[s];
46 let genomes_in_species = species.len();
47 for g in 0..genomes_in_species {
48 let genome = &mut species[g];
49
50 let mut fitness = 0.0;
51 for td in &training_data {
52 // Evaluate the genome using the training data as the
53 // initial inputs.
54 genome.evaluate(
55 &td.inputs[0..4].to_vec(),
56 Some(linear_activation),
57 Some(linear_activation),
58 );
59
60 // We add this to the existing fitness for the genome
61 // to ensure that the genomes with the best score across
62 // all tests will have the highest overall fitness.
63 fitness += adding_fitness_func(&genome.get_outputs(), &td.expected);
64 }
65
66 // Update the genome with the calculate fitness score.
67 // (This is important, as this fitness score is needed to
68 // spawn the next generation correctly.)
69 genome.update_fitness(fitness);
70
71 if fitness > best_fitness {
72 println!(
73 "Species {} Genome {} increased best fitness to {}",
74 s, g, best_fitness
75 );
76 best_fitness = fitness;
77 best_genome = Some(genome.clone());
78 }
79 }
80 }
81 // Spawn the next generation.
82 gene_pool.new_generation();
83 }
84 println!("Serializing best genome to winner.json");
85 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
86 .unwrap();
87 } else {
88 if args.len() < 7 {
89 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
90 return;
91 }
92 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
93 let input1 = args[3]
94 .parse::<f32>()
95 .expect("Couldn't parse input1 as f32");
96 let input2 = args[4]
97 .parse::<f32>()
98 .expect("Couldn't parse input2 as f32");
99 let input3 = args[5]
100 .parse::<f32>()
101 .expect("Couldn't parse input1 as f32");
102 let input4 = args[6]
103 .parse::<f32>()
104 .expect("Couldn't parse input2 as f32");
105 // Note that this is the exact same function we used in training
106 // further up!
107 genome.evaluate(
108 &vec![input1, input2, input3, input4],
109 Some(linear_activation),
110 Some(linear_activation),
111 );
112 println!(
113 "Sum of inputs is..........{}",
114 genome.get_outputs()[0] as u32
115 );
116 }
117}
Sourcepub fn population_size(&self) -> usize
pub fn population_size(&self) -> usize
Sourcepub fn get_best_genome(&self) -> Genome
pub fn get_best_genome(&self) -> Genome
Returns the best Genome in the current population. (Earlier generations could theoretically have had a better Genome. If it is important to have the best Genome ever, you should call this method once per generation to check each generation’s best Genome.)
Examples found in repository?
13fn main() {
14 let args: Vec<String> = env::args().collect();
15
16 if args.len() < 2 {
17 println!("Usage: '{} train' to train a new comparer.", args[0]);
18 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
19 return;
20 }
21
22 if args[1] == "train" {
23 // One input node for each input in the training data structure
24 let input_nodes = 4;
25 // One output node with the "prediction"
26 let output_nodes = 1;
27 // Create a new gene pool with an initial population of genomes
28 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
29
30 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
31
32 let mut trainer = Trainer::new(training_data);
33 // This function will be called once per Genome per piece of
34 // TrainingData in each generation, passing the values of the
35 // output nodes of the Genome as well as the expected result
36 // from the TrainingData.
37 trainer.evaluate_fn = adding_fitness_func;
38 trainer.hidden_activation = linear_activation;
39 trainer.output_activation = linear_activation;
40
41 // Train over the course of 100 generations
42 trainer.train(&mut gene_pool, 100);
43
44 let best_genome = gene_pool.get_best_genome();
45
46 println!("Serializing best genome to winner.json");
47 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome).unwrap();
48 } else {
49 if args.len() < 7 {
50 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
51 return;
52 }
53 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
54 let input1 = args[3]
55 .parse::<f32>()
56 .expect("Couldn't parse input1 as f32");
57 let input2 = args[4]
58 .parse::<f32>()
59 .expect("Couldn't parse input2 as f32");
60 let input3 = args[5]
61 .parse::<f32>()
62 .expect("Couldn't parse input1 as f32");
63 let input4 = args[6]
64 .parse::<f32>()
65 .expect("Couldn't parse input2 as f32");
66 // Note that this is the exact same function we used in training
67 // further up!
68 genome.evaluate(
69 &vec![input1, input2, input3, input4],
70 Some(linear_activation),
71 Some(linear_activation),
72 );
73 println!(
74 "Sum of inputs is..........{}",
75 genome.get_outputs()[0] as u32
76 );
77 }
78}
Sourcepub fn new_generation(&mut self)
pub fn new_generation(&mut self)
Spawn the next generation of Genomes. This should only be done after you’ve assessed all Genomes in the current generation and updated their fitness scores. Calling this function will use the top performing existing Genomes as the basis of the next generation.
Examples found in repository?
36fn main() {
37 let args: Vec<String> = env::args().collect();
38
39 if args.len() < 2 {
40 println!("Usage: '{} train' to train a new comparer.", args[0]);
41 println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
42 return;
43 }
44
45 if args[1] == "train" {
46 // One input node for each input in the TrainingData structure
47 let input_nodes = 2;
48 // One output node with the "prediction"
49 let output_nodes = 1;
50 // Create a new gene pool with an initial population of genomes
51 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
52
53 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
54
55 // These variables are used to keep track of the top performer, so we
56 // can write it out later.
57 let mut best_genome: Option<Genome> = None;
58 let mut best_fitness = 0.0;
59
60 // We use a label here to allow us to break out if we find a genome
61 // with a perfect score before we run through all of the generations.
62 'outer: for generation in 0..1000 {
63 println!("Evaluating generation {}", generation + 1);
64 let total_species = gene_pool.len();
65 for s in 0..total_species {
66 let species = &mut gene_pool[s];
67 let genomes_in_species = species.len();
68 for g in 0..genomes_in_species {
69 let genome = &mut species[g];
70 let mut fitness = 0.0;
71
72 for td in &training_data {
73 // Evaluate the genome using the training data as the
74 // initial inputs.
75 genome.evaluate(&td.inputs[0..2].to_vec(), None, None);
76
77 // We add this to the existing fitness for the genome
78 // to ensure that the genomes with the best score across
79 // all tests will have the highest overall fitness.
80 fitness += fitness_func(genome.get_outputs()[0], td.expected[0]);
81 }
82
83 // Update the genome with the calculate fitness score.
84 // (This is important, as this fitness score is needed to
85 // spawn the next generation correctly.)
86 genome.update_fitness(fitness);
87
88 if fitness > best_fitness {
89 println!(
90 "Species {} Genome {} increased best fitness to {}",
91 s, g, best_fitness
92 );
93 best_fitness = fitness;
94 best_genome = Some(genome.clone());
95 }
96
97 if fitness == PERFECT_SCORE {
98 println!("Found a perfect genome!");
99 break 'outer;
100 }
101 }
102 }
103 // Spawn the next generation.
104 gene_pool.new_generation();
105 }
106 println!("Serializing best genome to winner.json");
107 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
108 .unwrap();
109 } else {
110 if args.len() < 5 {
111 println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
112 return;
113 }
114 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
115 let input1 = args[3]
116 .parse::<f32>()
117 .expect("Couldn't parse input1 as f32");
118 let input2 = args[4]
119 .parse::<f32>()
120 .expect("Couldn't parse input2 as f32");
121 genome.evaluate(&vec![input1, input2], None, None);
122 if genome.get_outputs()[0] > 0.5 {
123 println!("Predicted that {} is greater than {}!", input1, input2);
124 } else {
125 println!(
126 "Predicted that {} is equal or less than {}!",
127 input1, input2
128 );
129 }
130 }
131}
More examples
14fn main() {
15 let args: Vec<String> = env::args().collect();
16
17 if args.len() < 2 {
18 println!("Usage: '{} train' to train a new comparer.", args[0]);
19 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
20 return;
21 }
22
23 if args[1] == "train" {
24 // One input node for each input in the TrainingData structure
25 let input_nodes = 4;
26 // One output node with the "prediction"
27 let output_nodes = 1;
28 // Create a new gene pool with an initial population of genomes
29 let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
30
31 let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
32
33 // These variables are used to keep track of the top performer, so we
34 // can write it out later.
35 let mut best_genome: Option<Genome> = None;
36 let mut best_fitness = 0.0;
37
38 // We will test genomes from 100 generations
39 for generation in 0..100 {
40 println!("Evaluating generation {}", generation + 1);
41 let total_species = gene_pool.len();
42 // As genomes diverge in structure and configuration, they will
43 // be divided into separate species.
44 for s in 0..total_species {
45 let species = &mut gene_pool[s];
46 let genomes_in_species = species.len();
47 for g in 0..genomes_in_species {
48 let genome = &mut species[g];
49
50 let mut fitness = 0.0;
51 for td in &training_data {
52 // Evaluate the genome using the training data as the
53 // initial inputs.
54 genome.evaluate(
55 &td.inputs[0..4].to_vec(),
56 Some(linear_activation),
57 Some(linear_activation),
58 );
59
60 // We add this to the existing fitness for the genome
61 // to ensure that the genomes with the best score across
62 // all tests will have the highest overall fitness.
63 fitness += adding_fitness_func(&genome.get_outputs(), &td.expected);
64 }
65
66 // Update the genome with the calculate fitness score.
67 // (This is important, as this fitness score is needed to
68 // spawn the next generation correctly.)
69 genome.update_fitness(fitness);
70
71 if fitness > best_fitness {
72 println!(
73 "Species {} Genome {} increased best fitness to {}",
74 s, g, best_fitness
75 );
76 best_fitness = fitness;
77 best_genome = Some(genome.clone());
78 }
79 }
80 }
81 // Spawn the next generation.
82 gene_pool.new_generation();
83 }
84 println!("Serializing best genome to winner.json");
85 serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
86 .unwrap();
87 } else {
88 if args.len() < 7 {
89 println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
90 return;
91 }
92 let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
93 let input1 = args[3]
94 .parse::<f32>()
95 .expect("Couldn't parse input1 as f32");
96 let input2 = args[4]
97 .parse::<f32>()
98 .expect("Couldn't parse input2 as f32");
99 let input3 = args[5]
100 .parse::<f32>()
101 .expect("Couldn't parse input1 as f32");
102 let input4 = args[6]
103 .parse::<f32>()
104 .expect("Couldn't parse input2 as f32");
105 // Note that this is the exact same function we used in training
106 // further up!
107 genome.evaluate(
108 &vec![input1, input2, input3, input4],
109 Some(linear_activation),
110 Some(linear_activation),
111 );
112 println!(
113 "Sum of inputs is..........{}",
114 genome.get_outputs()[0] as u32
115 );
116 }
117}