public void TestOffspringSelector() { var crossover = new NEAT.MultipointCrossover(); var offspringSelector = new OffspringSelector(crossover); var offspringCount = 100; var offspring = offspringSelector.Select(species, offspringCount); Assert.AreEqual(offspringCount, offspring.Length); }
IEnumerator Start() { var logPath = string.Format("logs_{0}", DateTime.Now.Ticks); Debug.LogFormat("Logging to {0}", logPath); if (!Directory.Exists(logPath)) { Directory.CreateDirectory(logPath); } elitesLog = File.CreateText(Path.Combine(logPath, "elites.csv")); populationLog = File.CreateText(Path.Combine(logPath, "populations.csv")); generationLog = File.CreateText(Path.Combine(logPath, "generations.csv")); speciesLog = File.CreateText(Path.Combine(logPath, "species.csv")); var populationSize = 100; var innovations = new InnovationCollection(); var mutations = new MutationCollection(); mutations.Add(0.01f, new AddNeuronMutator(innovations)); // 0.1% mutations.Add(0.05f, new AddSynapseMutator(innovations)); // 1% mutations.Add(0.05f, new ToggleSynapseMutator(0.125f)); mutations.Add(0.20f, new PerturbNeuronMutator(0.5f, 0.25f)); // 98% vvv mutations.Add(0.20f, new PerturbSynapseMutator(0.5f, 0.25f)); mutations.Add(0.20f, new ReplaceNeuronMutator(0.5f)); mutations.Add(0.20f, new ReplaceSynapseMutator(0.5f)); var eliteSelector = new EliteSelector(); var crossover = new MultipointCrossover(); var offspringSelector = new OffspringSelector(crossover); var distanceMetric = new DistanceMetric(2.0f, 2.0f, 1.0f); var speciation = new Speciation(10, 6.0f, 0.3f, distanceMetric); var neuronGenes = new []{ new NeuronGene(innovations.GetInitialNeuronInnovationId(0), NeuronType.UpperNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(1), NeuronType.LowerNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(2), NeuronType.PositionNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(3), NeuronType.SpeedNeuron), }.ToGeneList(); var synapseGenes = new GeneList<SynapseGene>(); var protoGenotype = new Genotype(neuronGenes, synapseGenes); var genotypes = new GenotypeStream(protoGenotype) .Take(populationSize).ToArray(); var species = new Specie[0]; var generation = 0; var elitePhenotypes = new List<Phenotype>(); var offspringPhenotypes = genotypes.Select(gt => new Phenotype(gt)).ToList(); while (true) { yield return StartCoroutine(EvaluatePopulation(offspringPhenotypes)); var phenotypes = new List<Phenotype>(elitePhenotypes.Count + offspringPhenotypes.Count); phenotypes.AddRange(elitePhenotypes); phenotypes.AddRange(offspringPhenotypes); Assert.AreEqual(phenotypes.Count, populationSize, "Population size must remain constant"); var longest = phenotypes.OrderByDescending(pt => pt.BestDuration).First(); Debug.LogFormat("[{0}] Fitness: {1}, Duration: {2}s ({3}, {4}) (Longest)", generation, longest.MeanFitness, longest.MeanDuration, longest.Genotype.NeuronCount, longest.Genotype.SynapseCount); var best = phenotypes.OrderByDescending(pt => pt.Fitness).First(); Debug.LogFormat("[{0}] Fitness: {1}, Duration: {2}s ({3}, {4}) (Best)", generation, best.MeanFitness, best.MeanDuration, best.Genotype.NeuronCount, best.Genotype.SynapseCount); elitesLog.WriteLine(string.Join(",", new string[]{ generation.ToString(), best.Fitness.ToString(), best.BestDuration.ToString(), JSON.Serialize(best.Genotype.ToJSON()), })); var meanComplexity = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.Complexity, (sum) => sum / (float)phenotypes.Count); var meanNeuronCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.NeuronCount, (sum) => sum / (float)phenotypes.Count); var meanSynapseCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.SynapseCount, (sum) => sum / (float)phenotypes.Count); var meanFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Fitness, (sum) => sum / (float)phenotypes.Count); var stdevFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow(pt.Fitness - meanFitness, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevComplexity = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.Complexity - meanComplexity, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevNeuronCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.NeuronCount - meanNeuronCount, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevSynapseCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.SynapseCount - meanSynapseCount, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); species = speciation.Speciate(species, phenotypes.ToArray()); Debug.LogFormat("[{0}] Species Count: {1} (Threshold: {2})", generation, species.Length, speciation.DistanceThreshold); var meanAdjustedFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.AdjustedFitness, (sum) => sum / (float)phenotypes.Count); // standard deviation: // take the square root of the average of the squared deviations of the values from their average value var stdevAdjustedFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow(pt.AdjustedFitness - meanAdjustedFitness, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); generationLog.WriteLine(new []{ generation, best.Fitness, best.MeanDuration, meanAdjustedFitness, stdevAdjustedFitness, meanFitness, stdevFitness, meanComplexity, stdevComplexity, meanNeuronCount, stdevNeuronCount, meanSynapseCount, stdevSynapseCount }.Stringify()); foreach (var sp in species) { speciesLog.WriteLine(new []{ generation, sp.SpeciesId, sp.Count, sp.BestFitness, sp.MeanFitness, sp.MeanAdjustedFitness, sp.MeanComplexity, }.Stringify()); foreach (var pt in sp) { populationLog.WriteLine(new []{ generation, sp.SpeciesId, pt.Fitness, pt.AdjustedFitness, pt.BestDuration, pt.Genotype.Complexity, pt.Genotype.NeuronCount, pt.Genotype.SynapseCount, }.Stringify()); } } var eliteCount = species.Length; elitePhenotypes = eliteSelector.Select(species, eliteCount); var offspringCount = populationSize - elitePhenotypes.Count; var offspringGenotypes = offspringSelector.Select(species, offspringCount); var mutationResults = mutations.Mutate(offspringGenotypes); Debug.LogFormat("[{0}] Mutations: Added Neurons: {1}, Added Synapses: {2}, Perturbed Neurons: {3}, Perturbed Synapses: {4}, Replaced Neurons: {5}, Replaced Synapses: {6}, Toggled Synapses: {7}, Pruned Synapses: {8}, Orphaned Neurons: {9}", generation, mutationResults.addedNeurons, mutationResults.addedSynapses, mutationResults.perturbedNeurons, mutationResults.perturbedSynapses, mutationResults.replacedNeurons, mutationResults.replacedSynapses, mutationResults.toggledSynapses, mutationResults.prunedSynapses, mutationResults.orphanedNeurons); offspringPhenotypes = offspringGenotypes.Select(gt => new Phenotype(gt)).ToList(); generation++; // Flush these so we can preview results while it runs generationLog.Flush(); populationLog.Flush(); speciesLog.Flush(); } }