Exemple #1
0
        /// <summary>
        /// Tell how different are 2 genomes. This is used in speciation.
        /// </summary>
        /// <returns>A normalized float.</returns>
        public static float GeneticDistance(NEATConfig config, Genome genome1, Genome genome2)
        {
            var distance            = 0f;
            var comparisonInfo      = new GenomeComparisonInfo(genome1, genome2);
            var genesCountInBiggest = Mathf.Max(genome1.Genes.Count, genome2.Genes.Count);

            var disjointDist = comparisonInfo.Disjoint.Count * config.speciesCompatibility.disjointImpact;
            var excessDist   = comparisonInfo.Excess.Count * config.speciesCompatibility.excessImpact;

            distance += disjointDist / genesCountInBiggest;
            distance += excessDist / genesCountInBiggest;

            float totalWeightDif = 0;

            foreach (var gene in comparisonInfo.Matching)
            {
                var weight1 = Mathf.Abs(genome1.GetGene(gene).Weight);
                var weight2 = Mathf.Abs(genome2.GetGene(gene).Weight);
                var diff    = Mathf.Abs(weight1 - weight2) / Mathf.Max(weight1, weight2);
                totalWeightDif += diff;
            }

            distance += totalWeightDif / comparisonInfo.Matching.Count * config.speciesCompatibility.weightMeanDifCoef;
            distance /= config.speciesCompatibility.TotalImpactSum;
            return(distance);
        }
Exemple #2
0
        /// <summary>
        ///	Feed inputs into the neural network.
        ///	Starting from the output Neurons, solve all necessary neurons,
        ///	including recurent sequences.
        ///	The input and bias neurons are considered solved.
        /// </summary>
        /// <param name="inputs"> The given inner values of the Input layer. </param>
        public float[] FeedNeuralNetwork(NEATConfig config, float[] inputs)
        {
            var inputCount = InputCount;

            if (inputs.Length != inputCount)
            {
                throw new System.Exception(string.Format("Invalid number of inputs, {0} given {1} expected",
                                                         inputs.Length, inputCount));
            }

            int i = 0;

            foreach (var inputNeuron in InputNeurons)
            {
                inputNeuron.InnerValue = inputs[i++];
            }

            solvedNeurons.Clear();

            foreach (var outNeuron in OutputNeurons)
            {
                FeedNeuralNetworkRecursively(config.activationFunction, outNeuron, solvedNeurons);
            }

            return(CollectNetworkOutputs());
        }
        /// <summary>
        /// Groups all the genomes in Species, so that they can
        /// develop their own structures, without being 'distracted'
        /// by other local maximums.
        /// </summary>
        public void Speciate(NEATConfig config, List <Genome> genomes)
        {
            foreach (var genome in genomes)
            {
                var compatibleSpecies = GetGenomeSpecies(config, SpeciesList, genome);

                if (compatibleSpecies == null)
                {
                    var newSpecies = new Species();
                    newSpecies.NewGenomes.Add(genome);
                    SpeciesList.Add(newSpecies);
                }
                else
                {
                    compatibleSpecies.NewGenomes.Add(genome);
                }
            }

            foreach (var speciesI in SpeciesList)
            {
                speciesI.Genomes    = speciesI.NewGenomes;
                speciesI.NewGenomes = new List <Genome>();
                speciesI.Generation++;
            }

            EliminateEmptySpecies();
            AssignSpeciesToGenomes(SpeciesList);
        }
 public static void MutateConnection(NEATConfig config, Genome genome)
 {
     foreach (var gene in genome.Genes)
     {
         gene.Mutate(config);
     }
 }
        /// <summary>
        /// Mutates the given genome.
        /// First, try to mutate the structure. Only one
        /// structural mutation can happen at a time.
        /// Then, mutate the genome's weights, each
        /// genome has a chance to be modified.
        /// </summary>
        /// <param name="gradient">The mutation chances are multiplied by this gradient.</param>
        /// <returns>The same genome, but mutated.</returns>
        public static Genome Mutate(NEATConfig config, Genome genome, float gradient = 1f)
        {
            float rand = Random.Range(0, 1f);

            // Mutate structure. It's a weighted random choice.
            if (rand <= config.structMutation.connectionAddProb * gradient)
            {
                MutateAddGene(config, genome);
            }
            else if ((rand -= config.structMutation.connectionAddProb) <= config.structMutation.connectionDelProb * gradient)
            {
                MutateDelGene(genome);
            }
            else if ((rand -= config.structMutation.connectionDelProb) <= config.structMutation.nodeAddProb * gradient)
            {
                MutateAddNode(genome);
            }
            else if ((rand -= config.structMutation.nodeAddProb) <= config.structMutation.nodeDelProb * gradient)
            {
                MutateDelNode(genome);
            }

            // Mutate weight values.
            foreach (var gene in genome.Genes)
            {
                if (Random.Range(0, 1.0f) <= config.weightMutation.prob * gradient)
                {
                    gene.Mutate(config);
                }
            }

            return(genome);
        }
        public static Gene MutateAddGene(NEATConfig config, Genome genome)
        {
            List <Neuron> possibleStartingNodes = new List <Neuron>(genome.Neurons);

            while (possibleStartingNodes.Count > 0)
            {
                Neuron startingNode          = possibleStartingNodes[Random.Range(0, possibleStartingNodes.Count)];
                var    alreadyConnectedNodes = startingNode.OutNeurons;

                Neuron[] possibleEndNodes = genome.Neurons.Where(x =>
                                                                 x.Type != ENeuronType.Input &&
                                                                 x.Type != ENeuronType.Bias &&
                                                                 !alreadyConnectedNodes.Contains(x)
                                                                 ).ToArray();

                if (possibleEndNodes.Length != 0)
                {
                    Neuron endNeuron     = possibleEndNodes[Random.Range(0, possibleEndNodes.Length)];
                    var    newConnection = new Gene(
                        startingNode,
                        endNeuron,
                        (config == null) ? 0 : config.NewRandomWeight());

                    startingNode.OutGenes.Add(newConnection);
                    endNeuron.InGenes.Add(newConnection);
                    genome.Genes.Add(newConnection);
                    return(newConnection);
                }
                else
                {
                    possibleStartingNodes.Remove(startingNode);
                }
            }
            return(null);
        }
        /// <summary>
        /// Get N genomes from this species.
        /// The best genome is simply copied.
        /// A part of the genomes are soft copied. Soft, means that the mutation
        /// is less than normal.
        /// The rest, are a result of a crossover between weighted random chosen
        /// genomes. The random is weighted, based on the fitness. The parents can't
        /// be the same.
        /// </summary>
        public Genome[] GetNGenomesForNextGeneration(NEATConfig config, int n)
        {
            var result = new Genome[n];

            Genomes = Genomes.OrderByDescending(x => x.Fitness).ToList();

            for (int i = 0; i < n; i++)
            {
                if (i == 0)
                {
                    result[i] = new Genome(Genomes[0]);
                }
                else if (i <= config.partOfGenomesToCopyForNextGenerations * n || Genomes.Count == 1)
                {
                    result[i] = new Genome(FitnessWeightedRandomChoice(Genomes)).Mutate(config, 0.8f);
                }
                else
                {
                    var parent1 = FitnessWeightedRandomChoice(Genomes, config.weightedRandomGradient);
                    var parent2 = FitnessWeightedRandomChoice(Genomes.Where(x => x != parent1), config.weightedRandomGradient);
                    result[i] = Genome.Crossover(config, parent1, parent2).Mutate(config);
                }
            }
            return(result);
        }
Exemple #8
0
 public Genome(NEATConfig config, PackedGenome packedGenome)
 {
     SpeciesId = null;
     Fitness   = 0;
     CreateNetwork(config.inputCount,
                   config.outputCount,
                   packedGenome.genes.Select(x => new Gene(x))
                   );
 }
Exemple #9
0
 /// <summary>
 /// There is a config.WeightMutateNewValProb chance to
 /// reinitialize the Weight.
 /// </summary>
 public void Mutate(NEATConfig config)
 {
     if (Random.Range(0, 1.0f) < config.weightMutation.NewValProb)
     {
         Weight = config.NewRandomWeight();
     }
     else
     {
         Weight += config.GetAWeightMutation();
     }
 }
Exemple #10
0
        public Population(int genomeCount, int inCount, int outCount, NEATConfig config)
        {
            SpeciesCtrl = new SpeciesControl();
            GenomeCount = genomeCount;
            InputCount  = inCount;
            OutputCount = outCount;
            Config      = config;

            Genomes = new List <Genome>(GenomeCount);
            Populate();
        }
Exemple #11
0
        public static Genome LoadGenome(NEATConfig config, string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new Exception(filePath + " doesn't exist.");
            }

            var        bf   = new BinaryFormatter();
            FileStream file = File.Open(filePath, FileMode.Open);

            var packedGenome = (PackedGenome)bf.Deserialize(file);

            file.Close();
            return(new Genome(config, packedGenome));
        }
Exemple #12
0
        /// <summary>
        /// Create a new offspring by combining the 2 parents' genes.
        /// The Matching genes are already randomly chosen from parent1 or p2.
        /// </summary>
        /// <returns>A fresh Genome (not mutated yet).</returns>
        public static Genome Crossover(NEATConfig config, Genome parent1, Genome parent2)
        {
            var fittestParent  = (parent1.Fitness > parent2.Fitness) ? parent1 : parent2;
            var genesToInherit = new List <Gene>(fittestParent.Genes.Count);
            var comparisonInfo = new GenomeComparisonInfo(parent1, parent2);

            // The matching genes are chosen randomly from target1 or target2
            genesToInherit.AddRange(comparisonInfo.Matching.Select(x => new Gene(x)));

            // Add the disjoint genes from the fittests.
            genesToInherit.AddRange(comparisonInfo.Disjoint.Where(x => x.Value == fittestParent)
                                    .Select(x => new Gene(x.Key)));

            // Add the excess genes from the fittests.
            genesToInherit.AddRange(comparisonInfo.Excess.Where(x => x.Value == fittestParent)
                                    .Select(x => new Gene(x.Key)));

            return(new Genome(fittestParent, genesToInherit));
        }
Exemple #13
0
        private string _mutationLogs = "";                                                          // Mutation Logs

        public Evaluator(NEATConfig config, Genome startingGenome, InnovationCounter nodeInnovation, InnovationCounter connectionInnovation)
        {
            _config               = config;
            GenerationNumber      = 0;
            _nodeInnovation       = nodeInnovation;
            _connectionInnovation = connectionInnovation;

            _genomes = new List <Genome>();
            for (int i = 0; i < _config.populationSize; ++i)
            {
                _genomes.Add(Genome.GenomeRandomWeights(startingGenome, _r));
            }

            _nextEvaluationGenomes = new List <Genome>();

            _species = new List <Species>();

            _genomesSpecies = new Dictionary <Genome, Species>();

            BestFitness = -1f;
            BestGenome  = null;
        }
        /// <summary>
        /// Determines the species in which the given genome is located.
        /// Two genomes are in the same species if their genetic distance
        /// is less than the given compatibility treshold.
        /// </summary>
        private Species GetGenomeSpecies(NEATConfig config, List <Species> species, Genome genome)
        {
            if (species == null)
            {
                return(null);
            }

            foreach (var speciesI in species)
            {
                if (speciesI.Genomes.Count == 0)
                {
                    continue;
                }
                var threshold   = config.speciesCompatibility.threshold;
                var geneticDist = Genome.GeneticDistance(config, genome, speciesI.Representative);

                if (geneticDist <= threshold)
                {
                    return(speciesI);
                }
            }

            return(null);
        }
Exemple #15
0
 public Genome Mutate(NEATConfig config, float gradient = 1f)
 {
     return(Mutator.Mutate(config, this, gradient));
 }
 public bool DidntImproveInLastGenerations(NEATConfig config)
 {
     return(GenerationsSinceFitnesImprovement >= config.maxStagnation);
 }