def make_multiobjective_function(sources, bounds=None, function_type="worst_case", interpolation_method="nearest", bad_sources=None): """Make the multiobjective function""" if function_type == "multiobjective_counting": problem = make_multiobjective_function_counting( sources, bounds=bounds, interpolation_method=interpolation_method) algorithm = NSGAII( problem, variator=CompoundOperator( # TODO look further into this SBX(), HUX(), PM(), BitFlip())) elif function_type == "multiobjective_competing": if bad_sources is None: raise ValueError( "specify bad_sources for multiobjective_competing") problem = make_multiobjective_function_competing( sources, bounds=bounds, bad_sources=bad_sources, interpolation_method=interpolation_method) # TODO remove this algorithm = NSGAII(problem) else: raise ValueError("The type : {} was not valid".format(function_type)) return algorithm
def fit(self, X, y): opt_start_time = time.time() kfold = None if isinstance(self.cv, int) and self.cv == 1: X_train, X_val, y_train, y_val = train_test_split( X, y, test_size=0.2, random_state=self.random_seed, stratify=y) logger.info("Not using Cross-Validation. " "Performing single train/test split") else: is_clf = self.model.is_classifier() kfold = check_cv(self.cv, y=y, classifier=is_clf) # kfold = StratifiedKFold( # n_splits=self.cv, random_state=self.random_seed, shuffle=True # ) logger.info(f"Using Cross-Validation - {kfold}") self.ind = 0 def train_test_model(parameter): # First check if we exceeded allocated time budget current_time = time.time() elapsed_time = current_time - opt_start_time if (self.max_opt_time is not None) and (elapsed_time > self.max_opt_time): msg = ( f"Max optimization time exceeded. " f"Max Opt time = {self.max_opt_time}, Elapsed Time = {elapsed_time}, " f"NFE Completed - {self.ind}") raise MaxBudgetExceededException(msg) self.ind = self.ind + 1 logger.info(f"Training population {self.ind}") parameter = self.param_to_dict( parameter, self.model_helper.param_choices, self.model_helper.param_categories, self.model_helper.param_type, ) scorers = [get_scorer(scorer) for scorer in self.scoring] nscorers = len(scorers) try: if kfold is None: clf = self.model_helper.create_instance(parameter) clf_trained = clf.fit(X_train, y_train) obj_val = [ scorer(clf_trained, X_val, y_val) for scorer in scorers ] else: obj_scores = [[] for _ in range(nscorers)] # Perform k-fold cross-validation for train_index, test_index in kfold.split(X, y): if isinstance(X, pd.DataFrame): X_train_split, X_val_split = ( X.iloc[train_index], X.iloc[test_index], ) y_train_split, y_val_split = ( y.iloc[train_index], y.iloc[test_index], ) else: X_train_split, X_val_split = X[train_index], X[ test_index] y_train_split, y_val_split = y[train_index], y[ test_index] clf = self.model_helper.create_instance(parameter) clf_trained = clf.fit(X_train_split, y_train_split) obj_score = [ scorer(clf_trained, X_val_split, y_val_split) for scorer in scorers ] for i in range(nscorers): obj_scores[i].append(obj_score[i]) # Aggregate CV score obj_val = [np.mean(obj_scores[i]) for i in range(nscorers)] logger.debug(f"Obj k-fold scores - {obj_scores}") # By default we are solving a minimization MOO problem fitnessValue = [ self.best_score[i] - obj_val[i] for i in range(nscorers) ] logger.info(f"Train fitnessValue - {fitnessValue}") except jsonschema.ValidationError as e: logger.error(f"Caught JSON schema validation error.\n{e}") logger.error("Setting fitness (loss) values to infinity") fitnessValue = [np.inf for i in range(nscorers)] logger.info(f"Train fitnessValue - {fitnessValue}") return fitnessValue def time_check_callback(alg): current_time = time.time() elapsed_time = current_time - opt_start_time logger.info( f"NFE Complete - {alg.nfe}, Elapsed Time - {elapsed_time}") parameter_num = len(self.model_helper.param_choices) target_num = len(self.scoring) # Adjust max_evals if not a multiple of population size. This is # required as Platypus performs evaluations in multiples of # population_size. adjusted_max_evals = (self.max_evals // self.population_size) * self.population_size if adjusted_max_evals != self.max_evals: logger.info( f"Adjusting max_evals to {adjusted_max_evals} from specified {self.max_evals}" ) problem = Problem(parameter_num, target_num) problem.types[:] = self.model_helper.types problem.function = train_test_model # Set the variator based on types of decision variables varg = {} first_type = problem.types[0].__class__ all_type_same = all([isinstance(t, first_type) for t in problem.types]) # use compound operator for mixed types if not all_type_same: varg["variator"] = CompoundOperator(SBX(), HUX(), PM(), BitFlip()) algorithm = NSGAII( problem, population_size=self.population_size, **varg, ) try: algorithm.run(adjusted_max_evals, callback=time_check_callback) except MaxBudgetExceededException as e: logger.warning( f"Max optimization time budget exceeded. Optimization exited prematurely.\n{e}" ) solutions = nondominated(algorithm.result) # solutions = [s for s in algorithm.result if s.feasible]` # solutions = algorithm.result moo_solutions = [] for solution in solutions: vars = [] for pnum in range(parameter_num): vars.append(problem.types[pnum].decode( solution.variables[pnum])) vars_dict = self.param_to_dict( vars, self.model_helper.param_choices, self.model_helper.param_categories, self.model_helper.param_type, ) moo_solutions.append(self.Soln(vars_dict, solution.objectives)) logger.info(f"{vars}, {solution.objectives}") self.moo_solutions = moo_solutions pareto_models = [] for solution in self.moo_solutions: est = self.model_helper.create_instance(solution.variables) est_trained = est.fit(X, y) pareto_models.append((solution.variables, est_trained)) self.pareto_models = pareto_models return self
# instantiate the optimization algorithm to run in parallel for index, (free_node_num, fix_node_num) in enumerate( zip(free_nodes_num, fix_nodes_num)): problem = Ansys_GA(mapdl, free_node_num, fix_node_num) parent = problem.nvars * parent_mult_value #parent = 1 print(parent) history = [] GA_result_dir = os.path.join( PATH, "free_{}_fix_{}".format(free_node_num, fix_node_num)) os.makedirs(GA_result_dir, exist_ok=True) if index == 0: # 一つ目のGAでは遺伝子を引き継がない problem = Ansys_GA(mapdl, free_node_num, fix_node_num) algorithm = NSGAII(problem, population_size=parent, variator=CompoundOperator( SBX(), HUX(), PM(), BitFlip())) else: # 二回目以降のGAでは遺伝子を引き継ぐ load_GA_result_dir = os.path.join( PATH, "free_{}_fix_{}".format(free_nodes_num[index - 1], fix_nodes_num[index - 1])) load_gene_path = os.path.join(load_GA_result_dir, "parents.pk") problem = Ansys_GA(mapdl, free_node_num, fix_node_num) prior_problem = Ansys_GA(mapdl, free_nodes_num[index - 1], fix_nodes_num[index - 1]) algorithm = FixNode_NSGAII(problem, prior_problem, gene_path=load_gene_path, population_size=parent, variator=CompoundOperator( SBX(), HUX(), PM(), BitFlip())) for i in tqdm(range(generation)):
def bar_multi_GA(nx=20, ny=20, volume_frac=0.5, parent=400, generation=100, path="data"): PATH = os.path.join(path, "bar_nx_{}_ny_{}".format(nx, ny), "gen_{}_pa_{}".format(generation, parent)) os.makedirs(PATH, exist_ok=True) start = time.time() def objective(vars): y_1, y_2, y_3, x_4, nodes, widths = convert_var_to_arg(vars) edges = make_6_bar_edges(nx, ny, y_1, y_2, y_3, x_4, nodes, widths) rho = make_bar_structure(nx, ny, edges) volume = np.sum(rho) / (nx * ny) return [calc_E(rho), calc_G(rho)], [volume] def convert_var_to_arg(vars): y_1 = vars[0] y_2 = vars[1] y_3 = vars[2] x_4 = vars[3] node_y_indexes = vars[4:4 + 6 * 3] node_x_indexes = vars[4 + 6 * 3:4 + 6 * 3 * 2] nodes = np.stack([node_x_indexes, node_y_indexes], axis=1) widths = vars[4 + 6 * 3 * 2:] return y_1, y_2, y_3, x_4, nodes, widths # 2変数2目的の問題 problem = Problem(4 + 6 * 3 * 2 + 6 * 4, 2, 1) # 最小化or最大化を設定 problem.directions[:] = Problem.MAXIMIZE # 決定変数の範囲を設定 x_index_const = Integer(1, nx) # x座標に関する制約 y_index_const = Integer(1, ny) # y座標に関する制約 bar_constraint = Real(0, ny / 2) # バーの幅に関する制約 problem.types[0:3] = y_index_const problem.types[3] = x_index_const problem.types[4:4 + 6 * 3] = y_index_const problem.types[4 + 6 * 3:4 + 6 * 3 * 2] = x_index_const problem.types[4 + 6 * 3 * 2:] = bar_constraint problem.constraints[:] = "<=" + str(volume_frac) problem.function = objective problem.directions[:] = Problem.MAXIMIZE algorithm = NSGAII(problem, population_size=parent, variator=CompoundOperator(SBX(), HUX(), PM(), BitFlip())) algorithm.run(generation) # グラフを描画 fig = plt.figure() plt.scatter([s.objectives[0] for s in algorithm.result], [s.objectives[1] for s in algorithm.result], c="blue", label="infeasible solution") plt.scatter([s.objectives[0] for s in algorithm.result if s.feasible], [s.objectives[1] for s in algorithm.result if s.feasible], c="red", label='feasible solution') # 非劣解をとりだす nondominated_solutions = nondominated(algorithm.result) plt.scatter( [s.objectives[0] for s in nondominated_solutions if s.feasible], [s.objectives[1] for s in nondominated_solutions if s.feasible], c="green", label="pareto solution") plt.legend(loc='lower left') plt.xlabel("$E$") plt.ylabel("$G$") fig.savefig(os.path.join(PATH, "graph.png")) plt.close() for solution in [s for s in nondominated_solutions if s.feasible]: vars_list = [] for j in solution.variables[:3]: vars_list.append(y_index_const.decode(j)) vars_list.append(x_index_const.decode(solution.variables[3])) for j in solution.variables[4:4 + 6 * 3]: vars_list.append(y_index_const.decode(j)) for j in solution.variables[4 + 6 * 3:4 + 6 * 3 * 2]: vars_list.append(x_index_const.decode(j)) for j in solution.variables[4 + 6 * 3 * 2:]: vars_list.append(bar_constraint.decode(j)) y_1, y_2, y_3, x_4, nodes, widths = convert_var_to_arg(vars_list) edges = make_6_bar_edges(nx, ny, y_1, y_2, y_3, x_4, nodes, widths) image = make_bar_structure(nx, ny, edges) np.save( os.path.join( PATH, 'E_{}_G_{}.npy'.format(solution.objectives[0], solution.objectives[1])), image) convert_folder_npy_to_image(PATH) elapsed_time = time.time() - start with open("time.txt", mode='a') as f: f.writelines("bar_nx_{}_ny_{}_gen_{}_pa_{}:{}sec\n".format( nx, ny, generation, parent, elapsed_time))
dir_PATH = os.path.join(save_dir, "制約無10回平均") os.makedirs(dir_PATH, exist_ok=False) problem = IncrementalNodeIncrease_GA(2, 2) mean_history = [] start = time.time() for z in range(10): PATH = os.path.join(dir_PATH, str(z)) os.makedirs(PATH, exist_ok=False) history = [] # instantiate the optimization algorithm to run in parallel with ProcessPoolEvaluator(8) as evaluator: #algorithm = NSGAII(problem, population_size=parent, variator=CompoundOperator(SBX(), HUX(), PM(), BitFlip()), evaluator=evaluator) algorithm = GeneticAlgorithm(problem, population_size=parent, offspring_size=parent, variator=CompoundOperator(SBX(), HUX(), UM(), BitFlip()), evaluator=evaluator) for i in tqdm(range(generation)): algorithm.step() """ nondominated_solutions = nondominated(algorithm.result) efficiency_results = [s.objectives[0] for s in nondominated_solutions] max_efficiency = max(efficiency_results) """ max_efficiency = algorithm.fittest.objectives[0] history.append(max_efficiency) epochs = np.arange(i + 1) + 1 result_efficiency = np.array(history) fig = plt.figure() ax = fig.add_subplot(1, 1, 1) ax.plot(epochs, result_efficiency, label='efficiency')
for t in range(experient_num): PATH = os.path.join(save_dir, "{}".format(t)) os.makedirs(PATH, exist_ok=True) start = time.time() # instantiate the optimization algorithm to run in parallel for index, (free_node_num, fix_node_num) in enumerate(zip(free_nodes_num, fix_nodes_num)): problem = GA_type(free_node_num, fix_node_num) parent = problem.nvars * parent_mult_value history = [] GA_result_dir = os.path.join(PATH, "free_{}_fix_{}".format(free_node_num, fix_node_num)) os.makedirs(GA_result_dir, exist_ok=True) with ProcessPoolEvaluator(8) as evaluator: if index == 0: # 一つ目のGAでは遺伝子を引き継がない problem = GA_type(free_node_num, fix_node_num) algorithm = Customized_GeneticAlgorithm(problem, population_size=parent, variator=CompoundOperator(SBX(), HUX(), PM(), BitFlip()), evaluator=evaluator) else: # 二回目以降のGAでは遺伝子を引き継ぐ load_GA_result_dir = os.path.join(PATH, "free_{}_fix_{}".format(free_nodes_num[index - 1], fix_nodes_num[index - 1])) load_gene_path = os.path.join(load_GA_result_dir, "parents.pk") problem = GA_type(free_node_num, fix_node_num) prior_problem = GA_type(free_nodes_num[index - 1], fix_nodes_num[index - 1]) algorithm = algorithm_type(problem, prior_problem, gene_path=load_gene_path, population_size=parent, variator=CompoundOperator(SBX(), HUX(), PM(), BitFlip()), evaluator=evaluator) for i in tqdm(range(generation)): algorithm.step() efficiency_results = [s.objectives[0] for s in algorithm.result if s.feasible] # 実行可能解しか抽出しない if len(efficiency_results) != 0: max_efficiency = max(efficiency_results) else: max_efficiency = problem.penalty_value history.append(max_efficiency) epochs = np.arange(i + 1) + 1
def run(parent, generation, save_interval, save_dir="GA/result"): def objective(vars): # TODO condition edges_indicesの中身は左の方が右よりも小さいということをassertする gene_nodes_pos, gene_edges_thickness, gene_adj_element = convert_var_to_arg(vars) return [calculate_efficiency(gene_nodes_pos, gene_edges_thickness, gene_adj_element)] def make_adj_triu_matrix(adj_element, node_num, condition_edges_indices): """隣接情報を示す遺伝子から,edge_indicesを作成する関数 """ adj_matrix = np.zeros((node_num, node_num)) adj_matrix[np.triu_indices(node_num, 1)] = adj_element adj_matrix[(condition_edges_indices[:, 0], condition_edges_indices[:, 1])] = 1 edge_indices = np.stack(np.where(adj_matrix), axis=1) return edge_indices def make_edge_thick_triu_matrix(gene_edges_thickness, node_num, condition_edges_indices, condition_edges_thickness, edges_indices): """edge_thicknessを示す遺伝子から,condition_edge_thicknessを基にedges_thicknessを作成する関数 """ tri = np.zeros((node_num, node_num)) tri[np.triu_indices(node_num, 1)] = gene_edges_thickness tri[(condition_edges_indices[:, 0], condition_edges_indices[:, 1])] = condition_edges_thickness edges_thickness = tri[(edges_indices[:, 0], edges_indices[:, 1])] return edges_thickness def convert_var_to_arg(vars): nodes_pos = np.array(vars[0:gene_node_pos_num]) nodes_pos = nodes_pos.reshape([int(gene_node_pos_num / 2), 2]) edges_thickness = vars[gene_node_pos_num:gene_node_pos_num + gene_edge_thickness_num] adj_element = vars[gene_node_pos_num + gene_edge_thickness_num: gene_node_pos_num + gene_edge_thickness_num + gene_edge_indices_num] return nodes_pos, edges_thickness, adj_element def calculate_efficiency(gene_nodes_pos, gene_edges_thickness, gene_adj_element, np_save_path=False): condition_nodes_pos, input_nodes, input_vectors, output_nodes, \ output_vectors, frozen_nodes, condition_edges_indices, condition_edges_thickness\ = make_main_node_edge_info(*condition(), condition_edge_thickness=0.2) # make edge_indices edges_indices = make_adj_triu_matrix(gene_adj_element, node_num, condition_edges_indices) # make nodes_pos nodes_pos = np.concatenate([condition_nodes_pos, gene_nodes_pos]) # 条件ノードが含まれている部分グラフを抽出 G = nx.Graph() G.add_nodes_from(np.arange(len(nodes_pos))) G.add_edges_from(edges_indices) condition_node_list = input_nodes + output_nodes + frozen_nodes trigger = 0 # 条件ノードが全て接続するグラフが存在するとき,トリガーを発動する for c in nx.connected_components(G): sg = G.subgraph(c) # 部分グラフ if set(condition_node_list) <= set(sg.nodes): # 条件ノードが全て含まれているか edges_indices = np.array(sg.edges) trigger = 1 break if trigger == 0: # ペナルティを発動する return -10.0 # make edges_thickness edges_thickness = make_edge_thick_triu_matrix(gene_edges_thickness, node_num, condition_edges_indices, condition_edges_thickness, edges_indices) env = BarFemGym(nodes_pos, input_nodes, input_vectors, output_nodes, output_vectors, frozen_nodes, edges_indices, edges_thickness, frozen_nodes) env.reset() efficiency = env.calculate_simulation() if np_save_path: env.render(save_path=os.path.join(np_save_path, "image.png")) np.save(os.path.join(np_save_path, "nodes_pos.npy"), nodes_pos) np.save(os.path.join(np_save_path, "edges_indices.npy"), edges_indices) np.save(os.path.join(np_save_path, "edges_thickness.npy"), edges_thickness) return float(efficiency) node_num = 85 parent = (node_num * 2 + int(node_num * (node_num - 1) / 2) * 2) # 本来ならこれの10倍 PATH = os.path.join(save_dir, "parent_{}_gen_{}".format(parent, generation)) os.makedirs(PATH, exist_ok=True) condition_node_num = 10 gene_node_pos_num = (node_num - condition_node_num) * 2 gene_edge_thickness_num = int(node_num * (node_num - 1) / 2) gene_edge_indices_num = gene_edge_thickness_num # 2変数2目的の問題 problem = Problem(gene_node_pos_num + gene_edge_thickness_num + gene_edge_indices_num, 1) # 最小化or最大化を設定 problem.directions[:] = Problem.MAXIMIZE # 決定変数の範囲を設定 coord_const = Real(0, 1) edge_const = Real(0.1, 1) # バグが無いように0.1にする adj_constraint = Integer(0, 1) problem.types[0:gene_node_pos_num] = coord_const problem.types[gene_node_pos_num:gene_node_pos_num + gene_edge_thickness_num] = edge_const problem.types[gene_node_pos_num + gene_edge_thickness_num: gene_node_pos_num + gene_edge_thickness_num + gene_edge_indices_num] = adj_constraint problem.function = objective algorithm = NSGAII(problem, population_size=parent, variator=CompoundOperator(SBX(), HUX(), PM(), BitFlip())) history = [] for i in tqdm(range(generation)): algorithm.step() nondominated_solutions = nondominated(algorithm.result) efficiency_results = [s.objectives[0] for s in nondominated_solutions] max_efficiency = max(efficiency_results) history.append(max_efficiency) epochs = np.arange(i + 1) + 1 result_efficiency = np.array(history) fig = plt.figure() ax = fig.add_subplot(1, 1, 1) ax.plot(epochs, result_efficiency, label='efficiency') ax.set_xlim(1, max(epochs)) ax.set_xlabel('epoch') ax.legend() ax.set_title("efficiency curve") plt.savefig(os.path.join(PATH, "history.png")) plt.close() if i % save_interval == 0: save_dir = os.path.join(PATH, str(i)) max_index = efficiency_results.index(max_efficiency) max_solution = nondominated_solutions[max_index] vars = [] vars.extend([coord_const.decode(i) for i in max_solution.variables[0:gene_node_pos_num]]) vars.extend([edge_const.decode(i) for i in max_solution.variables[gene_node_pos_num:gene_node_pos_num + gene_edge_thickness_num]]) vars.extend([adj_constraint.decode(i) for i in max_solution.variables[gene_node_pos_num + gene_edge_thickness_num: gene_node_pos_num + gene_edge_thickness_num + gene_edge_indices_num]]) gene_nodes_pos, gene_edges_thickness, gene_adj_element = convert_var_to_arg(vars) calculate_efficiency(gene_nodes_pos, gene_edges_thickness, gene_adj_element, np_save_path=save_dir) np.save(os.path.join(save_dir, "history.npy"), history)