// Selection function to find most probable parents of the generation NN_Data[] SelectParents() { NN_Data[] parents = new NN_Data[2]; // Get the fitness of all runners combined int combinedFitness = 0; foreach (var stats in deathList) { combinedFitness += stats.framesAlive; } // Get a random value between 0 and the combinedFitness. Use this to find a probable parent for (int p_Index = 0; p_Index < 2; p_Index++) { int randFitness = Random.Range(0, combinedFitness) - deathList[0].framesAlive; int locatedID = 0; while (randFitness > 0) { locatedID++; randFitness -= deathList[locatedID].framesAlive; } parents[p_Index] = deathList[locatedID].nn_data; } return(parents); }
// Combine 2 parents' DNA using crossover & apply mutations NN_Data CrossOver(NN_Data[] parents) { float[,] ih_w = new float[parents[0].ih_w.GetLength(0), parents[0].ih_w.GetLength(1)]; float[] ih_b = new float[parents[0].ih_b.Length]; float[,] ho_w = new float[parents[0].ho_w.GetLength(0), parents[0].ho_w.GetLength(1)]; float[] ho_b = new float[parents[0].ho_b.Length]; for (int row = 0; row < ih_w.GetLength(0); row++) { for (int col = 0; col < ih_w.GetLength(1); col++) { ih_w[row, col] = parents[Random.Range(0, 2)].ih_w[row, col]; if (mutationPercentage > Random.value) { ih_w[row, col] += (Random.value - .5f) * mutationScale; } } } for (int element = 0; element < ih_b.Length; element++) { ih_b[element] = parents[Random.Range(0, 2)].ih_b[element]; if (mutationPercentage > Random.value) { ih_b[element] += (Random.value - .5f) * mutationScale; } } for (int row = 0; row < ho_w.GetLength(0); row++) { for (int col = 0; col < ho_w.GetLength(1); col++) { ho_w[row, col] = parents[Random.Range(0, 2)].ho_w[row, col]; if (mutationPercentage > Random.value) { ho_w[row, col] += (Random.value - .5f) * mutationScale; } } } for (int element = 0; element < ho_b.Length; element++) { ho_b[element] = parents[Random.Range(0, 2)].ho_b[element]; if (mutationPercentage > Random.value) { ho_b[element] += (Random.value - .5f) * mutationScale; } } NN_Data childDNA = new NN_Data(); childDNA.UpdateData(ih_w, ih_b, ho_w, ho_b); return(childDNA); }
// Get saved NN data from a playerID public static NN_Data ReadData(int playerID) { if (File.Exists(path + "Runner" + playerID.ToString() + ".txt")) { string[] lines = File.ReadAllLines(path + "Runner" + playerID.ToString() + ".txt"); string[] ih_w_rows = lines[0].Split(':'); float[,] ih_w = new float[ih_w_rows.Length, ih_w_rows[0].Split(',').Length]; for (int row = 0; row < ih_w.GetLength(0); row++) { string[] ih_w_cols = ih_w_rows[row].Split(','); for (int col = 0; col < ih_w.GetLength(1); col++) { //File.WriteAllText(path + "Debug.txt", ih_w_cols[col]); ih_w[row, col] = float.Parse(ih_w_cols[col]); } } string[] ih_b_elements = lines[1].Split(','); float[] ih_b = new float[ih_b_elements.Length]; for (int element = 0; element < ih_b_elements.Length; element++) { ih_b[element] = float.Parse(ih_b_elements[element]); } string[] ho_w_rows = lines[2].Split(':'); float[,] ho_w = new float[ho_w_rows.Length, ho_w_rows[0].Split(',').Length]; for (int row = 0; row < ho_w.GetLength(0); row++) { string[] ho_w_cols = ho_w_rows[row].Split(','); for (int col = 0; col < ho_w.GetLength(1); col++) { ho_w[row, col] = float.Parse(ho_w_cols[col]); } } string[] ho_b_elements = lines[3].Split(','); float[] ho_b = new float[ho_b_elements.Length]; for (int element = 0; element < ho_b_elements.Length; element++) { ho_b[element] = float.Parse(ho_b_elements[element]); } NN_Data readData = new NN_Data(); readData.UpdateData(ih_w, ih_b, ho_w, ho_b); return(readData); } else { return(null); } }
public void RunnerDies(int framesAlive, NN_Data nn_data) { deathCount++; deathList.Add(new RunnerDeathStats((int)Mathf.Pow((float)framesAlive, fitnessInfluence), nn_data)); // When all runners are dead use their stats to reproduce if (deathCount == numberOfRunners) { Reproduce(); } }
// Save NN data to a playerID public static void WriteData(int playerID, NN_Data data) { // Add all data values to List<string> and save to txt file List <string> lines = new List <string>() { "", "", "", "" }; for (int row = 0; row < data.ih_w.GetLength(0); row++) { for (int col = 0; col < data.ih_w.GetLength(1); col++) { lines[0] += data.ih_w[row, col].ToString() + ","; } lines[0] += ":"; } for (int element = 0; element < data.ih_b.Length; element++) { lines[1] += data.ih_b[element].ToString() + ","; } for (int row = 0; row < data.ho_w.GetLength(0); row++) { for (int col = 0; col < data.ho_w.GetLength(1); col++) { lines[2] += data.ho_w[row, col].ToString() + ","; } lines[2] += ":"; } for (int element = 0; element < data.ho_b.Length; element++) { lines[3] += data.ho_b[element].ToString() + ","; } // Clean up line endings for (int line = 0; line < lines.Count; line++) { lines[line] = lines[line].Replace(",:", ":"); lines[line] = lines[line].TrimEnd(':'); lines[line] = lines[line].TrimEnd(','); } File.WriteAllLines(path + "Runner" + playerID.ToString() + ".txt", lines); }
public NN(int playerID, int inputNodes, int hiddenNodes, int outputNodes) { NN_Data saveData = FileCtrl.ReadData(playerID); // If file exists for this playerID, read file and set NN data if (saveData != null) { nn_data.ih_w = saveData.ih_w; nn_data.ih_b = saveData.ih_b; nn_data.ho_w = saveData.ho_w; nn_data.ho_b = saveData.ho_b; } // If file does not exist for this playerID, create new set of NN_Data else { nn_data.ih_w = Math.RandomMatrix(inputNodes, hiddenNodes); nn_data.ih_b = Math.RandomLst(hiddenNodes); nn_data.ho_w = Math.RandomMatrix(hiddenNodes, outputNodes); nn_data.ho_b = Math.RandomLst(outputNodes); } }
// Genetic algorithm to create new neural networks void Reproduce() { // Breed and save children to file for (int ID = 0; ID < numberOfRunners - 1; ID++) { // Selection NN_Data[] parents = SelectParents(); // Cross Over to child DNA and mutate the child's DNA NN_Data childDNA = CrossOver(parents); // Save new genes FileCtrl.WriteData(ID, childDNA); } // Save the fittest runner on his own FileCtrl.WriteData(deathList.Count - 1, deathList[deathList.Count - 1].nn_data); FileCtrl.SaveStats(generation + 1, deathList[deathList.Count - 1].framesAlive); UnityEngine.SceneManagement.SceneManager.LoadScene(0); }
public RunnerDeathStats(int framesAlive, NN_Data nn_data) { this.framesAlive = framesAlive; this.nn_data = nn_data; }