/// <summary> /// Helper mehtod: Selects a pair of nurons at random from diffrent /// levels of the network. The nurons are always listed in order. It /// returns false if it was ubale to generate a valid pair. /// </summary> /// <param name="n1">The lower level nuron</param> /// <param name="n2">The upper level nuron</param> private bool RandPair(out NuronOld n1, out NuronOld n2) { //generates two random nurons n1 = RandNuron(); n2 = RandNuron(); int count = 0; //keeps searching while the nurons are on the same level while (n1.Level == n2.Level && count < MAX_TRY) { NuronOld n3 = RandNuron(); n1 = n2; n2 = n3; count++; } //swaps the nurons if they are out of order if (n1.Level > n2.Level) { NuronOld n3 = n1; n1 = n2; n2 = n3; } //indicates if we found a valid pair return(count < MAX_TRY); }
/// <summary> /// Adds a nuron to the network at the given level and with the given /// activation function. It returns null if it was unable to add the nuron. /// </summary> /// <param name="func">Activation function of the nuron</param> /// <param name="level">Level of the nuron</param> /// <returns>The inserted nuron</returns> public NuronOld AddNuron(ActFunc func, int level) { //clamps the level to be within range if (level > MAX_LV) { level = MAX_LV; } if (level < 0) { level = 0; } //tries to generate a random index int index = RandIndex(); if (index < 0) { return(null); } //creates the node and adds it NuronOld n = new NuronOld(this, func, level, index); nurons.Add(index, n); return(n); }
/// <summary> /// Helper method: Finds an axon in the curent network that matches a /// target axon from another network. If no sucth match can be found, /// it returns null instead. /// </summary> /// <param name="other">Target axon</param> /// <returns>A matching axon</returns> private Axon FindMatch(Axon other) { //first atempts to find the target nuron NuronOld n1 = nurons.GetValue(other.Target); if (n1 == null) { return(null); } //obtains the axon from the target return(n1.GetAxon(other.Source)); }
/// <summary> /// Clones a given network by make a deep copy of the internal /// structor, so that the clone may be manipulated without effecting /// the original. It also replaces the internal random number generator /// with a potentialy diffrent generator. /// </summary> /// <param name="rng">Random number generator</param> /// <param name="other">Network to clone</param> private NetworkCPP(VRandom rng, NetworkCPP other) { //copies the RNG by refrence this.rng = rng; //creates a new table with the same size int size = other.nurons.Buckets; nurons = new TableOpen <Int32, NuronOld>(size); //makes a deep copy of the former network's structor foreach (var pair in other.nurons) { NuronOld copy = new NuronOld(this, pair.Item); nurons.Add(pair.Key, copy); } }
/// <summary> /// Expands the curent nural net, in place, by either inserting a /// new node along a pre-existing edge or creating a new edge. The /// probibility of either event occoring is determined by the /// existing topology. /// </summary> public void ExpandSelf() { NuronOld n1, n2; //generates a pair of random nurons bool test = RandPair(out n1, out n2); Axon target = n2.GetAxon(n1.Index); if (test && target == null) { //creates a new axon between the nurons double weight = rng.RandGauss() * SDN; n2.AddAxonInit(n1, weight); } else if (test && !target.Enabled) { //reinitilises the axon with a new weight target.Weight = rng.RandGauss() * SDN; target.Enabled = true; } else if ((n2.Level - n1.Level) > 3) { //disables the target edge double weight = target.Weight; target.Enabled = false; //creates a new node with a random funciton int index = RandIndex(); int level = (n2.Level + n1.Level) / 2; ActFunc func = RandFunc(); //aborts the operation if we fail to insert if (index < 0) { return; } //inserts the node into our data-structor NuronOld nx = new NuronOld(this, func, level, index); nurons.Add(index, nx); //adds axons to replace the missing axon nx.AddAxonInit(n1, 1.0); n2.AddAxonInit(nx, weight); } }
/// <summary> /// Preterbs the current neural net by some random amount without /// creating a clone. The rate of mutaiton determins how many of the /// network connections are preturbed. For exampe, a mutation rate /// of 0.5 indicates that half the weights will be perturbed. /// </summary> /// <param name="rate">Rate of mutation</param> public void MutateSelf(double rate) { //clamps the rate to be between zero and one rate = VMath.Clamp(rate); if (rng.RandBool(P_Node)) { //changes the activation funciton of a single node NuronOld node = RandNuron(); node.Func = RandFunc(); return; } //lists all the axons in the network var axons = ListAxons(); foreach (Axon ax in axons) { //mutates weights based on the rate of mutation if (rng.RandBool(1.0 - rate)) { continue; } if (ax.Enabled) { //permutes the weight by a small amount double delta = rng.RandGauss() * SDS; ax.Weight = ax.Weight + delta; } else { //resets the neuron to a small weight ax.Weight = rng.RandGauss() * SDS; ax.Enabled = true; } } }