void Start() { bird = GetComponent <Bird>(); neuralNet = new NeuralNetwork(GameConstants.defaultLearningRate); neuralNet.AddDenseLayer(2, new ActivationFunction(Utils.ReLU)); neuralNet.AddDenseLayer(6, new ActivationFunction(Utils.ReLU)); neuralNet.AddDenseLayer(1, new ActivationFunction(Utils.Sigmoid)); neuralNet.FinishBuilding(Utils.LinearError); this.dna = GameManager.instance.GetANewBirdDNA(); // if we dont have a valid DNA from the DNA Generator if (dna == null) { this.dna = new BirdDNA(neuralNet.GetWeights(), neuralNet.GetBiases()); } else { // we are here if we DID got a new DNA from the DNA Generator so we should actually apply it to the neural network this.neuralNet.SetWeights(this.dna.weightsOfNeuralNetwork); this.neuralNet.SetBiases(this.dna.biasesOfNeuralNetwork); } // we are adding this Evo bird to the static array that holds all Evo birds instances.Add(this); }
/// <summary> /// A Simple DNA Generator based on the best DNA's that were before it /// </summary> /// <returns>A new Bird's DNA to use, at first will be null, then will generate better ones</returns> public BirdDNA GetANewBirdDNA() { // MAIN LEARNING IS HERE AT GENERATING A BETTER BIRD'S DNA EACH GENERATION BirdDNA birdDNAToReturn = null; if (choosedBirdsDNAPool.Count < 2) { birdDNAToReturn = null; } else { // cross over the two dna's and loading the new bird's dna birdDNAToReturn = BirdDNA.CrossOver(choosedBirdsDNAPool[0].val2, choosedBirdsDNAPool[1].val2); // mutating the new dna a bit birdDNAToReturn.Mutate(GameConstants.defaultMutationChance); } return(birdDNAToReturn); }
// This function recieves a new dna and loads it to bird and its the neural network private void LoadNewBirdDNA(BirdDNA newDna) { this.dna = newDna; this.neuralNet.SetWeights(this.dna.weightsOfNeuralNetwork); this.neuralNet.SetBiases(this.dna.biasesOfNeuralNetwork); }
// static function to crossing over two bird dna // crossing over meaning taking half dna of each bird public static BirdDNA CrossOver(BirdDNA bird1, BirdDNA bird2) { // validating data dimensions if (bird1.weightsOfNeuralNetwork.Count != bird2.weightsOfNeuralNetwork.Count) { throw new DataDimensionsMismatchException(); } if (bird1.biasesOfNeuralNetwork.Count != bird2.biasesOfNeuralNetwork.Count) { throw new DataDimensionsMismatchException(); } // initializing the new weights array // now doing cross over algorithm, taking 1 info from bird and 1 from bird2 List <List <List <double> > > weightsInNewDNA = new List <List <List <double> > >(); // looping each layer and adding its weights to the 2D array for (int curLayerIndex = 0; curLayerIndex < bird1.weightsOfNeuralNetwork.Count; curLayerIndex++) { List <List <double> > curLayerNodesDna = new List <List <double> >(); // looping each weight in a specific layer and adding its weight to the 2D array for (int curNodeIndex = 0; curNodeIndex < bird1.weightsOfNeuralNetwork[curLayerIndex].Count; curNodeIndex++) { List <double> curNodeWeightsDna = new List <double>(); for (int curNodeWeightIndex = 0; curNodeWeightIndex < bird1.weightsOfNeuralNetwork[curLayerIndex][curNodeIndex].Count; curNodeWeightIndex++) { // add here a weight of either from bird1 or from bird2, one from each one or randomly // returns a number which is between 0 and 1 if (Utils.randomGenerator.NextDouble() > 0.5) { curNodeWeightsDna.Add(bird1.weightsOfNeuralNetwork[curLayerIndex][curNodeIndex][curNodeWeightIndex]); } else { curNodeWeightsDna.Add(bird2.weightsOfNeuralNetwork[curLayerIndex][curNodeIndex][curNodeWeightIndex]); } } curLayerNodesDna.Add(curNodeWeightsDna); } weightsInNewDNA.Add(curLayerNodesDna); } // initializing the new biases array List <List <double> > biasesInNewDNA = new List <List <double> >(); // looping each layer in the neural network for (int curLayerIndex = 0; curLayerIndex < bird1.biasesOfNeuralNetwork.Count; curLayerIndex++) { List <double> biasesOfNodesInCurLayer = new List <double>(); // looping each bias in a specific layer and adding its bias to the 1D array for (int curBiasIndex = 0; curBiasIndex < bird1.biasesOfNeuralNetwork[curLayerIndex].Count; curBiasIndex++) { // add here a weight of either from bird1 or from bird2, one from each one or randomly if (Utils.randomGenerator.NextDouble() > 0.5) { biasesOfNodesInCurLayer.Add(bird1.biasesOfNeuralNetwork[curLayerIndex][curBiasIndex]); } else { biasesOfNodesInCurLayer.Add(bird2.biasesOfNeuralNetwork[curLayerIndex][curBiasIndex]); } } biasesInNewDNA.Add(biasesOfNodesInCurLayer); } // creating and returning the new bird dna that was cross over between the two dna's BirdDNA birdDNAToReturn = new BirdDNA(weightsInNewDNA, biasesInNewDNA); return(birdDNAToReturn); }