diff --git a/__data__/A3_modified/run_0/generation_000/best_performers.pkl b/__data__/A3_modified/run_0/generation_000/best_performers.pkl new file mode 100644 index 000000000..e04792ef3 Binary files /dev/null and b/__data__/A3_modified/run_0/generation_000/best_performers.pkl differ diff --git a/__data__/A3_modified/run_0/generation_000/body_population.pkl b/__data__/A3_modified/run_0/generation_000/body_population.pkl new file mode 100644 index 000000000..54874e26d Binary files /dev/null and b/__data__/A3_modified/run_0/generation_000/body_population.pkl differ diff --git a/__data__/A3_modified/run_0/generation_001/best_performers.pkl b/__data__/A3_modified/run_0/generation_001/best_performers.pkl new file mode 100644 index 000000000..d032738ba Binary files /dev/null and b/__data__/A3_modified/run_0/generation_001/best_performers.pkl differ diff --git a/__data__/A3_modified/run_0/generation_001/body_population.pkl b/__data__/A3_modified/run_0/generation_001/body_population.pkl new file mode 100644 index 000000000..c7ee03ae9 Binary files /dev/null and b/__data__/A3_modified/run_0/generation_001/body_population.pkl differ diff --git a/__data__/A3_modified/run_0/generation_002/best_performers.pkl b/__data__/A3_modified/run_0/generation_002/best_performers.pkl new file mode 100644 index 000000000..0c45f2ae8 Binary files /dev/null and b/__data__/A3_modified/run_0/generation_002/best_performers.pkl differ diff --git a/__data__/A3_modified/run_0/generation_002/body_population.pkl b/__data__/A3_modified/run_0/generation_002/body_population.pkl new file mode 100644 index 000000000..314956bc8 Binary files /dev/null and b/__data__/A3_modified/run_0/generation_002/body_population.pkl differ diff --git a/__data__/A3_modified/run_0/generation_003/best_performers.pkl b/__data__/A3_modified/run_0/generation_003/best_performers.pkl new file mode 100644 index 000000000..8868fba65 Binary files /dev/null and b/__data__/A3_modified/run_0/generation_003/best_performers.pkl differ diff --git a/__data__/A3_modified/run_0/generation_003/body_population.pkl b/__data__/A3_modified/run_0/generation_003/body_population.pkl new file mode 100644 index 000000000..0bf81bfe7 Binary files /dev/null and b/__data__/A3_modified/run_0/generation_003/body_population.pkl differ diff --git a/__data__/A3_modified/run_0/generation_004/best_performers.pkl b/__data__/A3_modified/run_0/generation_004/best_performers.pkl new file mode 100644 index 000000000..ce81f98be Binary files /dev/null and b/__data__/A3_modified/run_0/generation_004/best_performers.pkl differ diff --git a/__data__/A3_modified/run_0/generation_004/body_population.pkl b/__data__/A3_modified/run_0/generation_004/body_population.pkl new file mode 100644 index 000000000..5487d261c Binary files /dev/null and b/__data__/A3_modified/run_0/generation_004/body_population.pkl differ diff --git a/__data__/A3_modified/run_0/generation_005/best_performers.pkl b/__data__/A3_modified/run_0/generation_005/best_performers.pkl new file mode 100644 index 000000000..ff17980ef Binary files /dev/null and b/__data__/A3_modified/run_0/generation_005/best_performers.pkl differ diff --git a/__data__/A3_modified/run_0/generation_005/body_population.pkl b/__data__/A3_modified/run_0/generation_005/body_population.pkl new file mode 100644 index 000000000..68441f64e Binary files /dev/null and b/__data__/A3_modified/run_0/generation_005/body_population.pkl differ diff --git a/__data__/A3_modified/run_0/run_0_image.png b/__data__/A3_modified/run_0/run_0_image.png new file mode 100644 index 000000000..5f4518e86 Binary files /dev/null and b/__data__/A3_modified/run_0/run_0_image.png differ diff --git a/__data__/A3_modified/run_0/run_parameters.txt b/__data__/A3_modified/run_0/run_parameters.txt new file mode 100644 index 000000000..a5782dbba --- /dev/null +++ b/__data__/A3_modified/run_0/run_parameters.txt @@ -0,0 +1,42 @@ +# Brain EA + ea_brain_config = EABrainConfig( + # General EA parameters + runs_brain = 1, + ngen_brain = 50, + pop_size_brain = 50, + cxpb_brain = 0.7, + mutpb_brain = 0.5, + elites_brain = 1, + # Network structure + hidden_size= 128, + no_hidden_layers= 3, + # Initialization function for brain genotype + init_func= partial(np.random.uniform, -1, 1), + # Mutation parameters + gauss_mut_mu= 0.0, + gauss_mut_sigma= 0.2, + gauss_mut_indpb= 0.2, + # Crossover parameters + wa_alpha= 0.4, + # Selection parameters + tourn_size= 3 + ) + ea_body_config = EABodyConfig( + # General EA parameters + runs_body= 1, + ngen_body= 1, + pop_size_body= 10, + cxpb_body= 0.5, + mutpb_body= 0.5, + elites_body= 1, # PLEASE note: If no elites, the final generation + # of a run might not contain the best + # individual over the whole run! + # Mutation parameters + gauss_mut_mu= 0.0, + gauss_mut_sigma= 0.1, + gauss_mut_indpb= 0.3, + # Crossover parameters + wa_alpha= 0.4, + # Selection parameters + tourn_size= 3, + ) diff --git a/examples/A3_modified.py b/examples/A3_modified.py index 68740f309..b78077189 100644 --- a/examples/A3_modified.py +++ b/examples/A3_modified.py @@ -270,6 +270,39 @@ def find_latest_generation(sim_config, run_id): ### === Plotting === +def plot_run_statistics(sim_config, run_id): + run_dir = sim_config.data / f"run_{run_id}" + if not run_dir.exists(): + raise FileNotFoundError(f"Run directory {run_dir} does not exist.") + + run_means = [] + run_stds = [] + run_bests = [] + for gen_dir in run_dir.iterdir(): + if gen_dir.is_dir() and gen_dir.name.startswith("generation_"): + gen_num = int(gen_dir.name.split("_")[1]) + pop, best_data = load_population_from_generation(sim_config, gen_num, run_id) + mean = np.mean([ind.fitness.values[0] for ind in pop if ind.fitness.valid]) + std = np.std([ind.fitness.values[0] for ind in pop if ind.fitness.valid]) + best = best_data.get("body_fitness", None) + run_means.append(mean) + run_stds.append(std) + run_bests.append(best) + + run_means = np.array(run_means) + run_stds = np.array(run_stds) + run_bests = np.array(run_bests) + x = np.arange(len(run_means)) + fig, ax = plt.subplots() + ax.plot(x, run_means, linestyle = "--", linewidth = 1.5, color = "blue", label = "Mean Fitness") + ax.fill_between(x, run_means - run_stds, run_means + run_stds, color="blue", alpha=0.2, label="Std. Dev.") + ax.plot(x, run_bests, linestyle = "-", linewidth = 2, color = "red", label = "Best Fitness") + ax.set_xlabel("Generation") + ax.set_ylabel("Fitness") + ax.legend() + plt.title(f"Run {run_id} - Fitness over Generations") + save_unique_png(fig, path=f"__data__/A3_modified/run_{run_id}_", ext = f".png") + def save_unique_png(fig, path = "__data__/", ext = ".png"): """Function to save plt figures with unique filenames. To prevent overwriting existing plots. @@ -283,10 +316,10 @@ def save_unique_png(fig, path = "__data__/", ext = ".png"): _type_: The path of the saved file """ i = 0 - filename = f"{path}position{ext}" + filename = f"{path}image{ext}" while os.path.exists(filename): i += 1 - filename = f"{path}position_{i}{ext}" + filename = f"{path}image_{i}{ext}" fig.savefig(filename) return filename @@ -1044,8 +1077,8 @@ def main( runs_brain = 1, ngen_brain = 50, pop_size_brain = 50, - cxpb_brain = 0.5, - mutpb_brain = 0.6, + cxpb_brain = 0.7, + mutpb_brain = 0.1, elites_brain = 1, # Network structure hidden_size= 128, @@ -1054,27 +1087,29 @@ def main( init_func= partial(np.random.uniform, -1, 1), # Mutation parameters gauss_mut_mu= 0.0, - gauss_mut_sigma= 0.1, - gauss_mut_indpb= 0.3, + gauss_mut_sigma= 0.15, + gauss_mut_indpb= 0.15, # Crossover parameters - wa_alpha= 0.4 + wa_alpha= 0.5, + # Selection parameters + tourn_size= 3 ) ea_body_config = EABodyConfig( # General EA parameters runs_body= 1, ngen_body= 1, pop_size_body= 10, - cxpb_body= 0.5, - mutpb_body= 0.5, + cxpb_body= 0.7, + mutpb_body= 0.1, elites_body= 1, # PLEASE note: If no elites, the final generation # of a run might not contain the best # individual over the whole run! # Mutation parameters gauss_mut_mu= 0.0, - gauss_mut_sigma= 0.1, - gauss_mut_indpb= 0.3, + gauss_mut_sigma= 0.15, + gauss_mut_indpb= 0.15, # Crossover parameters - wa_alpha= 0.4, + wa_alpha= 0.5, # Selection parameters tourn_size= 3, ) @@ -1174,7 +1209,7 @@ def main( Note that the renderer assumes the default network structure. If you change the network in main(), you then have to make the same changes to the interface code at the bottom of the script. """ - RENDER_GEN = 0 + RENDER_GEN = 5 RENDER_RUN = 0 """ @@ -1228,11 +1263,12 @@ def main( ) if INSPECT: # Loading itself should output the best fitness of that gen. - pop, best_data = load_population_from_generation( - sim_config = sim_config, - generation = INSPECT_GEN, - run_id = INSPECT_RUN - ) + # pop, best_data = load_population_from_generation( + # sim_config = sim_config, + # generation = INSPECT_GEN, + # run_id = INSPECT_RUN + # ) + plot_run_statistics(sim_config, INSPECT_RUN) diff --git a/src/scripts_A3/eval_tools.py b/src/scripts_A3/eval_tools.py index fe1ae6ef7..6c2db8007 100644 --- a/src/scripts_A3/eval_tools.py +++ b/src/scripts_A3/eval_tools.py @@ -42,7 +42,7 @@ def find_in_out_size( data_test = mj.MjData(model_test) # Extract input and output sizes - input_size = len(data_test.qpos) + input_size = len(data_test.qpos) + len(data_test.qvel) output_size = model_test.nu return (input_size, output_size) @@ -80,7 +80,7 @@ def nn_controller( npt.NDArray[np.float64]: Control outputs to hinges """ ## Get inputs, in this case the positions of the actuator motors (hinges) - inputs = data.qpos + inputs = np.concatenate([data.qpos, data.qvel]) ## Run the inputs through all layers of the network. for W in matrices[:-1]: