diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index e516491..3f8275e 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -564,28 +564,6 @@ namespace NanoBrain { return allInstances; } - // public void Backpropagation(Func Observer, float target, float learningRate) { - // foreach (Nucleus nucleus in this.instances[0].nuclei) { - // if (nucleus is not Neuron neuron) - // continue; - - // foreach (Synapse synapse in neuron.synapses) { - // List allSynapseNeurons = GetAllInstances(synapse.neuron); - - // Vector3 dSSRdW = Vector3.zero; - // for (int clusterIx = 0; clusterIx < this.instances.Length; clusterIx++) { - // Cluster clusterInstance = this.instances[clusterIx]; - // Neuron neuronInstance = allSynapseNeurons[clusterIx]; - - // // Simple case, without receivers... - // dSSRdW += (Vector3)(-2 * (Observer(clusterInstance) - target) * neuronInstance.activation); - // } - // synapse.weight += learningRate * dSSRdW.magnitude; - // } - // } - - // } - #endregion ClusterArray /// diff --git a/Runtime/Scripts/Core/Neuron.cs b/Runtime/Scripts/Core/Neuron.cs index a528f4d..efb0594 100644 --- a/Runtime/Scripts/Core/Neuron.cs +++ b/Runtime/Scripts/Core/Neuron.cs @@ -807,6 +807,7 @@ namespace NanoBrain { this.lastUpdate = Time.time; this.bias = inputValue; this.parent?.UpdateFromNucleus(this); + this.resetStimulus ??= ResetStimulus; if (autoResetDelay > 0) { long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); diff --git a/Runtime/Scripts/Core/Population.cs b/Runtime/Scripts/Core/Population.cs new file mode 100644 index 0000000..29c3ced --- /dev/null +++ b/Runtime/Scripts/Core/Population.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace NanoBrain { + public class Population { + public class Member { + public Member(Cluster cluster) { + this.brain = cluster; + this.performance = 0; + this.initialized = true; + } + public Cluster brain; + public float performance; + public bool initialized; + } + public List members = new(); + + public Member AddMember(Cluster brain) { + Member newMember = new(brain); + this.members.Add(newMember); + return newMember; + } + + /// + /// Generational update + /// + public virtual void Update() { + + } + + public void NewGeneration() { + foreach (Member member in this.members) { + member.initialized = false; + } + } + + protected List SelectElite(float percentage) { + return SelectElite((int)(members.Count * percentage)); + } + protected List SelectElite(int count) { + List selectedMembers = new(); + + SortMembers(); + for (int i = 0; i < count; i++) { + Member member = this.members[i]; + if (!member.initialized) { + Debug.Log($"Selected {i}: {member.performance}"); + member.initialized = true; + selectedMembers.Add(member); + } + } + + return selectedMembers; + } + + private void SortMembers() { + members.Sort((a, b) => a.performance.CompareTo(b.performance)); + } + + protected List GenerateMutants(List elite, float percentage) { + return GenerateMutants(elite, (int)(members.Count * percentage)); + } + protected List GenerateMutants(List elite, int count) { + List selectedMembers = new(); + int i = 0; + int n = 0; + while (n < count && i < this.members.Count) { + Member member = this.members[i]; + if (member.initialized == false) { + GenerateMutant(member, elite); + member.initialized = true; + n++; + selectedMembers.Add(member); + } + i++; + } + return selectedMembers; + } + + protected void GenerateMutant(Member member, List ants) { + System.Random randomGenerator = new(); + int n = ants.Count; + int parent1 = randomGenerator.Next(0, n); + int parent2 = randomGenerator.Next(0, n); + Debug.Log($"Mutate from {members[parent1].performance} and {members[parent2].performance}"); + + member.brain.CopyWeightsFrom(ants[parent1].brain); + member.brain.ProcessWeightsFrom(ants[parent2].brain, Average); + member.brain.GaussianAdditiveMutation(1e-1f); + } + + private static float Average(float a, float b) { + return (a + b) / 2; + } + + protected List GenerateRandom() { + return GenerateRandom(int.MaxValue); + } + + protected List GenerateRandom(int count) { + List selectedMembers = new(); + int i = 0; + int n = 0; + while (n < count && i < this.members.Count) { + Member member = this.members[i]; + if (member.initialized == false) { + Debug.Log($"Randomized {i}: {member.performance}"); + member.brain.InitializeRandom(); + member.initialized = true; + selectedMembers.Add(member); + n++; + } + i++; + } + return selectedMembers; + } + } +} \ No newline at end of file diff --git a/Runtime/Scripts/Core/Population.cs.meta b/Runtime/Scripts/Core/Population.cs.meta new file mode 100644 index 0000000..2d9d7fa --- /dev/null +++ b/Runtime/Scripts/Core/Population.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a820ab88a63bed6e881dbb82eae0a824 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: