Skip to content

Commit

Permalink
Merge pull request #7 from yaricom/safe-method
Browse files Browse the repository at this point in the history
Implemented SAFE coevolution method for solving maze navigation problem
  • Loading branch information
yaricom authored Apr 9, 2024
2 parents a75e969 + 9355de5 commit 89c0de5
Show file tree
Hide file tree
Showing 7 changed files with 570 additions and 10 deletions.
98 changes: 98 additions & 0 deletions data/safe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#############################
# The SAFE population options
#############################
# Probability of mutating a single trait param
trait_param_mut_prob: 0.5
# Power of mutation on a single trait param
trait_mutation_power: 1.0
# The power of a link weight mutation
weight_mut_power: 2.5

# 3 global coefficients are used to determine the formula for computing the compatibility between 2 genomes.
# The formula is: disjoint_coeff * pdg + excess_coeff * peg + mutdiff_coeff * mdmg.
# See the Compatibility method in the Genome class for more info
# They can be thought of as the importance of disjoint Genes, excess Genes, and parametric difference between Genes of
# the same function, respectively.
disjoint_coeff: 1.0
excess_coeff: 1.0
mutdiff_coeff: 0.4

# This global tells compatibility threshold under which two Genomes are considered the same species
compat_threshold: 3.0
# How much does age matter? Gives a fitness boost up to some young age (niching). If it is 1, then young species get no fitness boost.
age_significance: 1.0
# Percent of average fitness for survival, how many get to reproduce based on survival_thresh * pop_size
survival_thresh: 0.2

# Probabilities of a non-mating reproduction
mutate_only_prob: 0.25
# Probability of genome trait mutation
mutate_random_trait_prob: 0.1
# Probability of link trait mutation
mutate_link_trait_prob: 0.1
# Probability of node trait mutation
mutate_node_trait_prob: 0.1
# Probability of link weight value mutation
mutate_link_weights_prob: 0.9
# Probability of enabling/disabling of specific link/gene
mutate_toggle_enable_prob: 0.0
# Probability of finding the first disabled gene and re-enabling it
mutate_gene_reenable_prob: 0.0
# Probability of adding new node
mutate_add_node_prob: 0.03
# Probability of adding new link between nodes
mutate_add_link_prob: 0.08
# Probability of making connections from disconnected sensors (input, bias type neurons)
mutate_connect_sensors: 0.5

# Probability of mating between different species
interspecies_mate_rate: 0.001
# Probability of mating this Genome with another Genome g. For every point in each Genome, where each Genome shares
# the innovation number, the Gene is chosen randomly from either parent. If one parent has an innovation absent in
# the other, the baby may inherit the innovation if it is from the more fit parent.
mate_multipoint_prob: 0.3
# Probability of mating like in multipoint, but instead of selecting one or the other when the innovation numbers match,
# it averages their weights.
mate_multipoint_avg_prob: 0.3
# Probability of mating similar to a standard single point CROSSOVER operator. Traits are averaged as in the previous two
# mating methods. A Gene is chosen in the smaller Genome for splitting. When the Gene is reached, it is averaged with
# the matching Gene from the larger Genome, if one exists. Then every other Gene is taken from the larger Genome.
mate_singlepoint_prob: 0.3

# Probability of mating without mutation
mate_only_prob: 0.2

# Probability of forcing selection of ONLY links that are naturally recurrent
recur_only_prob: 0.0

# The number of babies to stolen off to the champions
babies_stolen: 0
# The population size as a number of organisms
pop_size: 100
# Age when Species starts to be penalized
dropoff_age: 50
# Number of tries mutate_add_link will attempt to find an open link
newlink_tries: 50
# Tells to print population to file every n generations
print_every: 10

# The number of runs to average over in an experiment
num_runs: 100
# The number of epochs (generations) to execute training
num_generations: 100

# The epoch's executor type to apply [sequential, parallel]
epoch_executor: sequential

# The genome compatibility method to use [linear, fast]. The latter is best for bigger genomes
genome_compat_method: linear

# The log level
log_level: info

# The nodes activation functions list to choose from (activation function -> it's selection probability)
node_activators:
- SigmoidBipolarActivation 0.25
- GaussianBipolarActivation 0.35
- LinearAbsActivation 0.15
- SineActivation 0.25
27 changes: 27 additions & 0 deletions data/safeobjfuncstartgenes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# The objective function candidate start genome
genome:
id: 1
# The traits used in this genome
traits:
- {id: 1, params: [0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}

# The neuron nodes list for this genome
nodes:
- {id: 1, trait_id: 0, type: BIAS, activation: LinearActivation}
# The input sensors
- { id: 2, trait_id: 0, type: INPT, activation: LinearActivation }
# The non-linear hidden control node
- { id: 3, trait_id: 0, type: HIDN, activation: SigmoidSteepenedActivation }
# The output nodes
# The a coefficient
- { id: 4, trait_id: 0, type: OUTP, activation: LinearActivation }
# The b coefficient
- { id: 5, trait_id: 0, type: OUTP, activation: LinearActivation }

# The connection genes
genes:
- {src_id: 1, tgt_id: 3, weight: 0.0, trait_id: 1, innov_num: 1, mut_num: 0, recurrent: false, enabled: true}
- {src_id: 2, tgt_id: 3, weight: 0.0, trait_id: 1, innov_num: 2, mut_num: 0, recurrent: false, enabled: true}
# Hidden-to-output
- {src_id: 3, tgt_id: 4, weight: 0.0, trait_id: 1, innov_num: 12, mut_num: 0, recurrent: false, enabled: true}
- {src_id: 3, tgt_id: 5, weight: 0.0, trait_id: 1, innov_num: 13, mut_num: 0, recurrent: false, enabled: true}
8 changes: 7 additions & 1 deletion examples/maze/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func mazeSimulationStep(env *Environment, phenotype *network.Network, netDepth i

// use the net's outputs to change heading and velocity of maze agent
if err := env.ApplyOutputs(phenotype.Outputs[0].Activation, phenotype.Outputs[1].Activation); err != nil {
neat.ErrorLog("Failed to apply outputs")
neat.ErrorLog(fmt.Sprintf("Failed to apply outputs: %s", err))
return err
}

Expand Down Expand Up @@ -196,3 +196,9 @@ func adjustSpeciesNumber(speciesCount, epochId, adjustFrequency, numberSpeciesTa
}
}
}

// NoveltyMetric the novelty metric function for maze simulation
var NoveltyMetric neatns.NoveltyMetric = func(x, y *neatns.NoveltyItem) float64 {
diff := histDiff(x.Data, y.Data)
return diff
}
8 changes: 1 addition & 7 deletions examples/maze/maze_ns.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ import (
// The initial novelty threshold for Novelty Archive
const archiveThresh = 6.0

// the novelty metric function for maze simulation
var noveltyMetric neatns.NoveltyMetric = func(x, y *neatns.NoveltyItem) float64 {
diff := histDiff(x.Data, y.Data)
return diff
}

// NewNoveltySearchEvaluator allows creating maze solving agent based on Novelty Search optimization.
// It will use provided MazeEnv to run simulation of the maze environment. The numSpeciesTarget specifies the
// target number of species to maintain in the population. If the number of species differ from the numSpeciesTarget it
Expand Down Expand Up @@ -55,7 +49,7 @@ func (e *noveltySearchEvaluator) TrialRunStarted(trial *experiment.Trial) {
trialSim = mazeSimResults{
trialID: trial.Id,
records: new(RecordStore),
archive: neatns.NewNoveltyArchive(archiveThresh, noveltyMetric, opts),
archive: neatns.NewNoveltyArchive(archiveThresh, NoveltyMetric, opts),
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/maze/maze_obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (e *objectiveEvaluator) TrialRunStarted(trial *experiment.Trial) {
trialSim = mazeSimResults{
trialID: trial.Id,
records: new(RecordStore),
archive: neatns.NewNoveltyArchive(archiveThresh, noveltyMetric, neatns.DefaultNoveltyArchiveOptions()),
archive: neatns.NewNoveltyArchive(archiveThresh, NoveltyMetric, neatns.DefaultNoveltyArchiveOptions()),
}
}

Expand Down
Loading

0 comments on commit 89c0de5

Please sign in to comment.