def crossover_operation(listofprogramdicts): new_prog_dict = {} parents = random.choices(listofprogramdicts, k=2) prog_dict1, prog_dict2 = parents[0], parents[1] xover1 = random.randint(1, prog_dict1['depth']) xover2 = random.randint(2, prog_dict2['depth']) print('DEBUG: trying new crossover') new_program, crossed_over = self.crossover_helper( prog_dict1['program'], prog_dict2['program'], xover1, xover2) if crossed_over: log_and_print("Crossing over the following programs:") log_and_print( print_program(prog_dict1['program'], ignore_constants=True)) log_and_print( print_program(prog_dict2['program'], ignore_constants=True)) new_prog_dict["program"] = new_program new_prog_dict["struct_cost"], new_prog_dict[ "depth"] = graph.compute_program_cost(new_program) log_and_print("Result has structural cost {:.4f}:".format( new_prog_dict["struct_cost"])) log_and_print( print_program(new_prog_dict['program'], ignore_constants=True)) return new_prog_dict else: return None
def run(self, graph, trainset, validset, train_config, device, verbose=False): assert isinstance(graph, ProgramGraph) current = copy.deepcopy(graph.root_node) current_avg_f_score = float('inf') best_program = None best_total_cost = float('inf') best_programs_list = [] num_children_trained = 0 start_time = time.time() while not graph.is_fully_symbolic(current.program): log_and_print("CURRENT program has avg fscore {:.4f}: {}".format( current_avg_f_score, print_program(current.program, ignore_constants=(not verbose)))) children = graph.get_all_children(current, in_enumeration=True) children_mapping = { print_program(child.program, ignore_constants=True) : child for child in children } children_scores = { key : [] for key in children_mapping.keys() } costs = [child.cost for child in children] for i in range(self.num_mc_samples): child = random.choices(children, weights=costs)[0] sample = self.mc_sample(graph, child) assert graph.is_fully_symbolic(sample.program) log_and_print("Training sample program: {}".format(print_program(sample.program, ignore_constants=(not verbose)))) sample_score = execute_and_train(sample.program, validset, trainset, train_config, graph.output_type, graph.output_size, neural=False, device=device) num_children_trained += 1 log_and_print("{} total children trained".format(num_children_trained)) sample_f_score = sample.cost + sample_score children_scores[print_program(child.program, ignore_constants=True)].append(sample_f_score) if sample_f_score < best_total_cost: best_program = copy.deepcopy(sample.program) best_total_cost = sample_f_score best_programs_list.append({ "program" : best_program, "struct_cost" : sample.cost, "score" : sample_score, "path_cost" : sample_f_score, "time" : time.time()-start_time }) log_and_print("New BEST program found:") print_program_dict(best_programs_list[-1]) # (Naive) selection operation children_scores = { key : sum(val)/len(val) if len(val) > 0 else float('inf') for key,val in children_scores.items() } best_child_name = min(children_scores, key=children_scores.get) current = children_mapping[best_child_name] current_avg_f_score = children_scores[best_child_name] for key,val in children_scores.items(): log_and_print("Avg score {:.4f} for child {}".format(val,key)) log_and_print("SELECTING {} as best child node\n".format(best_child_name)) log_and_print("DEBUG: time since start is {:.3f}\n".format(time.time()-start_time)) return best_programs_list
def enumerate_helper(program_node): program_name = print_program(program_node.program, ignore_constants=True) assert not enumerated.get(program_name) enumerated[program_name] = True if graph.is_fully_symbolic(program_node.program): all_programs.append({ "program" : copy.deepcopy(program_node.program), "struct_cost" : program_node.cost, "depth" : program_node.depth }) elif program_node.depth < enumeration_depth: all_children = graph.get_all_children(program_node, in_enumeration=True) for childnode in all_children: if not enumerated.get(print_program(childnode.program, ignore_constants=True)): enumerate_helper(childnode)
def neural_h(self): data = self.base_program.submodules l = [] #populate AST traverse(data,l) train_config = { 'lr' : self.learning_rate, 'neural_epochs' : 15, 'symbolic_epochs' : self.symbolic_epochs, 'optimizer' : optim.Adam, 'lossfxn' : nn.CrossEntropyLoss(weight=self.loss_weight), #todo 'evalfxn' : label_correctness, 'num_labels' : self.num_labels } best_node_ind = 0 best_score = 0 for hole_node_ind in range(1,len(l)): hole_node = l[hole_node_ind] subprogram_str = print_program(hole_node[0]) if subprogram_str.count('(') > self.max_depth: continue near_input_type = hole_node[0].input_type near_output_type = hole_node[0].output_type near_input_size = hole_node[0].input_size near_output_size = hole_node[0].output_size # Initialize program graph starting from trained NN program_graph = ProgramGraph(DSL_DICT, CUSTOM_EDGE_COSTS, near_input_type, near_output_type, near_input_size, near_output_size, self.max_num_units, self.min_num_units, self.max_num_children, 0, self.penalty, ite_beta=self.ite_beta) ## max_depth 0 # Initialize algorithm algorithm = ASTAR_NEAR(frontier_capacity=0) score, new_prog, losses = algorithm.run_init(self.timestamp, self.base_program_name, hole_node_ind, program_graph, self.batched_trainset, self.validset, train_config, self.device) subprogram_str = print_program(hole_node[0]) log_and_print("Subprogram to replace: %s"% subprogram_str) if score > best_score: best_node_ind = hole_node_ind best_score = score log_and_print("New best: RNN Heuristic score at Node %d: %f\n" %( hole_node_ind, score)) else: log_and_print("RNN Heuristic score at Node %d: %f\n" %( hole_node_ind, score)) return best_node_ind
def add(self, item): assert len(item) == 3 assert isinstance(item[2], ProgramNode) self.prioqueue.append(item) if len(self.prioqueue) > self.capacity: # self.sort(tup_idx=0) popped_f_score, _, popped = self.pop(-1) log_and_print("POP {} with fscore {:.4f}".format( print_program(popped.program, ignore_constants=True), popped_f_score))
def test_set_eval(program, testset, output_type, output_size, num_labels, device='cpu', verbose=False): log_and_print("\n") log_and_print("Evaluating program {} on TEST SET".format(print_program(program, ignore_constants=(not verbose)))) with torch.no_grad(): test_input, test_output = map(list, zip(*testset)) true_vals = torch.tensor(flatten_batch(test_output)).to(device) predicted_vals = process_batch(program, test_input, output_type, output_size, device) metric, additional_params = label_correctness(predicted_vals, true_vals, num_labels=num_labels) log_and_print("F1 score achieved is {:.4f}".format(1 - metric)) log_and_print("Additional performance parameters: {}\n".format(additional_params))
def mcts_sample(self, graph, program_node): assert isinstance(program_node, ProgramNode) program_path = [] while not graph.is_fully_symbolic(program_node.program): children = graph.get_all_children(program_node, in_enumeration=True) children_mapping = { print_program(child.program, ignore_constants=True): child for child in children } children_scores = { key: self.program_scores[key] for key in children_mapping.keys() } child_name = self.ucb_select(children_scores) program_node = children_mapping[child_name] program_path.append( print_program(program_node.program, ignore_constants=True)) return program_node, program_path
def run(self, graph, trainset, validset, train_config, device, verbose=False): assert isinstance(graph, ProgramGraph) symbolic_programs = [] enum_depth = 1 while len(symbolic_programs) < self.max_num_programs: print("DEBUG: starting enumerative synthesis with depth {}".format(enum_depth)) symbolic_programs = self.enumerate2depth(graph, enum_depth) print("DEBUG: {} programs found".format(len(symbolic_programs))) enum_depth += 1 if enum_depth > graph.max_depth: break log_and_print("Symbolic Synthesis: generated {}/{} symbolic programs from candidate program.".format( len(symbolic_programs), self.max_num_programs)) total_eval = min(self.max_num_programs, len(symbolic_programs)) symbolic_programs.sort(key=lambda x: x["struct_cost"]) symbolic_programs = symbolic_programs[:total_eval] best_program = None best_total_cost = float('inf') best_programs_list = [] start_time = time.time() num_programs_trained = 1 for prog_dict in symbolic_programs: child_start_time = time.time() candidate = prog_dict["program"] log_and_print("Training candidate program ({}/{}) {}".format( num_programs_trained, total_eval, print_program(candidate, ignore_constants=(not verbose)))) num_programs_trained += 1 score = execute_and_train(candidate, validset, trainset, train_config, graph.output_type, graph.output_size, neural=False, device=device) total_cost = score + prog_dict["struct_cost"] log_and_print("Structural cost is {} with structural penalty {}".format(prog_dict["struct_cost"], graph.penalty)) log_and_print("Time to train child {:.3f}".format(time.time()-child_start_time)) log_and_print("Total time elapsed is: {:.3f}".format(time.time()-start_time)) if total_cost < best_total_cost: best_program = copy.deepcopy(prog_dict["program"]) best_total_cost = total_cost prog_dict["score"] = score prog_dict["path_cost"] = total_cost prog_dict["time"] = time.time()-start_time best_programs_list.append(prog_dict) log_and_print("New BEST program found:") print_program_dict(best_programs_list[-1]) return best_programs_list
def evaluate_final(self): if self.device == 'cpu': program = CPU_Unpickler(open(self.full_path, "rb").load()) else: program = pickle.load(open(self.full_path, "rb")) log_and_print(print_program(program, ignore_constants=True)) l = [] traverse(program.submodules,l) with torch.no_grad(): test_input, test_output = map(list, zip(*self.testset)) true_vals = torch.flatten(torch.stack(test_output)).float().to(self.device) predicted_vals = self.process_batch(program, test_input, self.output_type, self.output_size, self.device) metric, additional_params = label_correctness(predicted_vals, true_vals, num_labels=self.num_labels) log_and_print("F1 score achieved is {:.4f}".format(1 - metric))
def train_more_epochs(self,program_to_train): log_and_print("starting training more epochs") train_config = { 'lr' : self.learning_rate, 'neural_epochs' : 20, 'symbolic_epochs' : 20, 'optimizer' : optim.Adam, 'lossfxn' : nn.CrossEntropyLoss(weight=self.loss_weight), #todo 'evalfxn' : label_correctness, 'num_labels' : self.num_labels } near_input_type = self.base_program.input_type near_output_type = self.base_program.output_type near_input_size = self.base_program.input_size near_output_size = self.base_program.output_size # Initialize program graph starting from trained NN program_graph = ProgramGraph(DSL_DICT, CUSTOM_EDGE_COSTS, near_input_type, near_output_type, near_input_size, near_output_size, self.max_num_units, self.min_num_units, self.max_num_children, self.max_depth, self.penalty, ite_beta=self.ite_beta) # Initialize algorithm algorithm = ASTAR_NEAR(frontier_capacity=self.frontier_capacity) best_programs = algorithm.run_train_longer(self.timestamp, program_to_train, self.hole_node_ind, program_graph, self.batched_trainset, self.validset, train_config, self.device) best_program_str = [] # Print all best programs found log_and_print("\n") # log_and_print("BEST programs found:") for item in best_programs: program_struct = print_program(item["program"], ignore_constants=True) program_info = " score {:.4f} ".format(item["score"]) best_program_str.append((program_struct, program_info)) print(best_program_str) # print_program_dict(item) best_program = best_programs[-1]["program"] with torch.no_grad(): test_input, test_output = map(list, zip(*self.testset)) true_vals = torch.flatten(torch.stack(test_output)).float().to(self.device) predicted_vals = self.process_batch(best_program, test_input, self.output_type, self.output_size, self.device) metric, additional_params = label_correctness(predicted_vals, true_vals, num_labels=self.num_labels) pickle.dump(best_program, open(program_to_train + ".p", "wb")) #overfit?? log_and_print("end training more epochs")
def evaluate_neurosymb(self, program): # if self.device == 'cpu': # program = CPU_Unpickler(open("neursym.p" % self.base_program_name, "rb")).load() # else: # program = pickle.load(open("neursym.p" % self.base_program_name, "rb")) # # program= CPU_Unpickler(open("%s.p" % self.base_program_name, "rb")).load() print(print_program(program, ignore_constants=True)) l = [] traverse(program.submodules,l) with torch.no_grad(): test_input, test_output = map(list, zip(*self.testset)) true_vals = torch.flatten(torch.stack(test_output)).float().to(self.device) predicted_vals = self.process_batch(program, test_input, self.output_type, self.output_size, self.device) metric, additional_params = label_correctness(predicted_vals, true_vals, num_labels=self.num_labels) log_and_print("Test F1 score achieved is {:.4f}\n".format(1 - metric)) log_and_print(str(additional_params)) return 1- metric
def neural_h(self): data = self.base_program.submodules l = [] #populate AST traverse(data,l) train_config = { 'lr' : self.learning_rate, 'neural_epochs' : self.neural_epochs, 'symbolic_epochs' : self.symbolic_epochs, 'optimizer' : optim.Adam, 'lossfxn' : nn.CrossEntropyLoss(weight=self.loss_weight), #todo 'evalfxn' : label_correctness, 'num_labels' : self.num_labels } scores = [self.base_program_name] for hole_node_ind in range(len(l)): hole_node = l[hole_node_ind] near_input_type = hole_node[0].input_type near_output_type = hole_node[0].output_type near_input_size = hole_node[0].input_size near_output_size = hole_node[0].output_size # Initialize program graph starting from trained NN program_graph = ProgramGraph(DSL_DICT, CUSTOM_EDGE_COSTS, near_input_type, near_output_type, near_input_size, near_output_size, self.max_num_units, self.min_num_units, self.max_num_children, 0, self.penalty, ite_beta=self.ite_beta) ## max_depth 0 # Initialize algorithm algorithm = ASTAR_NEAR(frontier_capacity=0) score, new_prog, losses = algorithm.run_init(self.timestamp, self.base_program_name, hole_node_ind, program_graph, self.batched_trainset, self.validset, train_config, self.device) subprogram_str = print_program(hole_node[0]) test_score = self.evaluate_neurosymb(new_prog) stats_arr = [subprogram_str, hole_node[1], score,test_score] stats_arr.extend(losses) scores.append(stats_arr) # scores.append() # h_file = os.path.join(self.save_path, "neursym_%d.p"%hole_node_ind) # pickle.dump(new_prog, open(h_file, "wb")) h_file = os.path.join(self.save_path, "neurh.csv") with open(h_file, "w", newline="") as f: writer = csv.writer(f) writer.writerows(scores)
def execute_and_train_with_full(base_program_name, hole_node_ind, program, validset, trainset, train_config, output_type, output_size, neural=False, device='cpu', use_valid_score=False, print_every=60): #load program # pprint(type(hole_node)) # level_to_replace = hole_node[1] if device == 'cpu': base_program = CPU_Unpickler(open("%s.p" % base_program_name, "rb")).load() else: base_program = pickle.load(open("%s.p" % base_program_name, "rb")) curr_level = 0 l = [] traverse(base_program.submodules, l) # pprint(l) curr_program = base_program.submodules # print(program) # print(program.submodules) # pprint change_key( base_program.submodules, [], hole_node_ind, program.submodules["program"]) #should we just replace with program? log_and_print(print_program(base_program)) # pickle.dump(base_program, open("neursym.p", "wb")) return execute_and_train(base_program, program, validset, trainset, train_config, output_type, output_size, neural, device)
def run_near(self): # print(self.device) train_config = { 'lr' : self.learning_rate, 'neural_epochs' : self.neural_epochs, 'symbolic_epochs' : self.symbolic_epochs, 'optimizer' : optim.Adam, 'lossfxn' : nn.CrossEntropyLoss(weight=self.loss_weight), #todo 'evalfxn' : label_correctness, 'num_labels' : self.num_labels } near_input_type = self.hole_node[0].input_type near_output_type = self.hole_node[0].output_type near_input_size = self.hole_node[0].input_size near_output_size = self.hole_node[0].output_size # Initialize program graph starting from trained NN program_graph = ProgramGraph(DSL_DICT, CUSTOM_EDGE_COSTS, near_input_type, near_output_type, near_input_size, near_output_size, self.max_num_units, self.min_num_units, self.max_num_children, self.max_depth, self.penalty, ite_beta=self.ite_beta) # Initialize algorithm algorithm = ASTAR_NEAR(frontier_capacity=self.frontier_capacity) best_programs = algorithm.run(self.timestamp, self.base_program_name, self.hole_node_ind, program_graph, self.batched_trainset, self.validset, train_config, self.device) best_program_str = [] if self.algorithm == "rnn": # special case for RNN baseline best_program = best_programs else: # Print all best programs found log_and_print("\n") log_and_print("BEST programs found:") for item in best_programs: program_struct = print_program(item["program"], ignore_constants=True) program_info = "struct_cost {:.4f} | score {:.4f} | path_cost {:.4f} | time {:.4f}".format( item["struct_cost"], item["score"], item["path_cost"], item["time"]) best_program_str.append((program_struct, program_info)) print_program_dict(item) best_program = best_programs[-1]["program"] # Save best programs f = open(os.path.join(self.save_path, "best_programs.txt"),"w") f.write( str(best_program_str) ) f.close() self.program_path = os.path.join(self.save_path, "subprogram.p") pickle.dump(best_program, open(self.program_path, "wb")) self.full_path = os.path.join(self.save_path, "fullprogram.p") if self.device == 'cpu': base_program = CPU_Unpickler(open("%s.p" % self.base_program_name, "rb")).load() else: base_program = pickle.load(open("%s.p" % self.base_program_name, "rb")) curr_level = 0 l = [] traverse(base_program.submodules,l) curr_program = base_program.submodules change_key(base_program.submodules, [], self.hole_node_ind, best_program.submodules["program"]) pickle.dump(base_program, open(self.full_path, "wb")) # Save parameters f = open(os.path.join(self.save_path, "parameters.txt"),"w") parameters = ['input_type', 'output_type', 'input_size', 'output_size', 'num_labels', 'neural_units', 'max_num_units', 'min_num_units', 'max_num_children', 'max_depth', 'penalty', 'ite_beta', 'train_valid_split', 'normalize', 'batch_size', 'learning_rate', 'neural_epochs', 'symbolic_epochs', 'lossfxn', 'class_weights', 'num_iter', 'num_f_epochs', 'algorithm', 'frontier_capacity', 'initial_depth', 'performance_multiplier', 'depth_bias', 'exponent_bias', 'num_mc_samples', 'max_num_programs', 'population_size', 'selection_size', 'num_gens', 'total_eval', 'mutation_prob', 'max_enum_depth', 'exp_id', 'base_program_name', 'hole_node_ind'] for p in parameters: f.write( p + ': ' + str(self.__dict__[p]) + '\n' ) f.close()
def run(self, graph, trainset, validset, train_config, device, verbose=False): assert isinstance(graph, ProgramGraph) log_and_print("Training root program ...") current = copy.deepcopy(graph.root_node) initial_score = execute_and_train(current.program, validset, trainset, train_config, graph.output_type, graph.output_size, neural=True, device=device) log_and_print( "Initial training complete. Score from program is {:.4f} \n". format(1 - initial_score)) # Branch-and-bound search with iterative deepening current_depth = self.initial_depth current_f_score = float('inf') order = 0 frontier = ProgramNodeFrontier(capacity=self.frontier_capacity) next_frontier = ProgramNodeFrontier(capacity=self.frontier_capacity) num_children_trained = 0 start_time = time.time() best_program = None best_total_cost = float('inf') best_programs_list = [] log_and_print("Starting iterative deepening with depth {}\n".format( current_depth)) while current_depth <= graph.max_depth: log_and_print("CURRENT program has fscore {:.4f}: {}".format( current_f_score, print_program(current.program, ignore_constants=(not verbose)))) log_and_print("Current depth of program is {}".format( current.depth)) log_and_print("Creating children for current node/program") log_and_print("Total time elapsed is {:.3f}".format(time.time() - start_time)) children_nodes = graph.get_all_children(current) # prune if more than self.max_num_children if len(children_nodes) > graph.max_num_children: log_and_print("Sampling {}/{} children".format( graph.max_num_children, len(children_nodes))) children_nodes = random.sample( children_nodes, k=graph.max_num_children) # sample without replacement log_and_print("{} total children to train for current node".format( len(children_nodes))) child_tuples = [] for child_node in children_nodes: child_start_time = time.time() log_and_print("Training child program: {}".format( print_program(child_node.program, ignore_constants=(not verbose)))) is_neural = not graph.is_fully_symbolic(child_node.program) child_node.score = execute_and_train(child_node.program, validset, trainset, train_config, graph.output_type, graph.output_size, neural=is_neural, device=device) log_and_print( "Time to train child {:.3f}".format(time.time() - child_start_time)) num_children_trained += 1 log_and_print( "{} total children trained".format(num_children_trained)) child_node.parent = current child_node.children = [] order -= 1 child_node.order = order # insert order of exploration as tiebreaker for equivalent f-scores # computing path costs (f_scores) child_f_score = child_node.cost + child_node.score # cost + heuristic log_and_print("DEBUG: f-score {}".format(child_f_score)) current.children.append(child_node) child_tuples.append((child_f_score, order, child_node)) if not is_neural and child_f_score < best_total_cost: best_program = copy.deepcopy(child_node.program) best_total_cost = child_f_score best_programs_list.append({ "program": best_program, "struct_cost": child_node.cost, "score": child_node.score, "path_cost": child_f_score, "time": time.time() - start_time }) log_and_print("New BEST program found:") print_program_dict(best_programs_list[-1]) # find next current among children, from best to worst nextfound = False child_tuples.sort(key=lambda x: x[0]) for child_tuple in child_tuples: child = child_tuple[2] if graph.is_fully_symbolic(child.program): continue # don't want to expand symbolic programs (no children) elif child.depth >= current_depth: next_frontier.add(child_tuple) else: if not nextfound: nextfound = True # first child program that's not symbolic and within current_depth current_f_score, current_order, current = child_tuple log_and_print( "Found program among children: {} with f_score {}". format( print_program(current.program, ignore_constants=(not verbose)), current_f_score)) else: frontier.add(child_tuple) # put the rest onto frontier # find next node in frontier if not nextfound: frontier.sort(tup_idx=1) # DFS order log_and_print("Frontier length is: {}".format(len(frontier))) original_depth = current.depth while len(frontier) > 0 and not nextfound: current_f_score, current_order, current = frontier.pop( 0, sort_fscores=False) # DFS order if current_f_score < self.bound_modify( best_total_cost, original_depth, current.depth): nextfound = True log_and_print( "Found program in frontier: {} with f_score {}". format( print_program(current.program, ignore_constants=(not verbose)), current_f_score)) else: log_and_print( "PRUNE from frontier: {} with f_score {}".format( print_program(current.program, ignore_constants=(not verbose)), current_f_score)) log_and_print("Frontier length is now {}".format( len(frontier))) # frontier is empty, go to next stage of iterative deepening if not nextfound: assert len(frontier) == 0 log_and_print("Empty frontier, moving to next depth level") log_and_print( "DEBUG: time since start is {:.3f}\n".format(time.time() - start_time)) current_depth += 1 if current_depth > graph.max_depth: log_and_print("Max depth {} reached. Exiting.\n".format( graph.max_depth)) break elif len(next_frontier) == 0: log_and_print("Next frontier is empty. Exiting.\n") break else: log_and_print( "Starting iterative deepening with depth {}\n".format( current_depth)) frontier = copy.deepcopy(next_frontier) next_frontier = ProgramNodeFrontier( capacity=self.frontier_capacity) current_f_score, current_order, current = frontier.pop(0) if best_program is None: log_and_print("ERROR: no program found") return best_programs_list
def run(self, graph, trainset, validset, train_config, device, verbose=False): assert isinstance(graph, ProgramGraph) self.input_size = graph.input_size self.output_size = graph.output_size best_program = None best_score = float('inf') best_total = float('inf') best_programs_list = [] start_time = time.time() log_and_print("Generating all programs up to specified depth.") all_generated_programs = self.enumerative_synthesis( graph, self.max_enum_depth) random.shuffle(all_generated_programs) current_population = all_generated_programs[:self.population_size] total_trained_programs = 0 def crossover_operation(listofprogramdicts): new_prog_dict = {} parents = random.choices(listofprogramdicts, k=2) prog_dict1, prog_dict2 = parents[0], parents[1] xover1 = random.randint(1, prog_dict1['depth']) xover2 = random.randint(2, prog_dict2['depth']) print('DEBUG: trying new crossover') new_program, crossed_over = self.crossover_helper( prog_dict1['program'], prog_dict2['program'], xover1, xover2) if crossed_over: log_and_print("Crossing over the following programs:") log_and_print( print_program(prog_dict1['program'], ignore_constants=True)) log_and_print( print_program(prog_dict2['program'], ignore_constants=True)) new_prog_dict["program"] = new_program new_prog_dict["struct_cost"], new_prog_dict[ "depth"] = graph.compute_program_cost(new_program) log_and_print("Result has structural cost {:.4f}:".format( new_prog_dict["struct_cost"])) log_and_print( print_program(new_prog_dict['program'], ignore_constants=True)) return new_prog_dict else: return None def mutation_operation(mod_prog_dict): new_prog_dict = {} mutation_point = random.randrange(1, mod_prog_dict['depth']) new_prog_dict['program'] = self.mutation_helper( graph, mod_prog_dict['program'], mod_prog_dict['depth'], mutation_point, max_enumeration_depth=self.max_enum_depth) new_prog_dict["struct_cost"], new_prog_dict[ "depth"] = graph.compute_program_cost(new_prog_dict['program']) return new_prog_dict for gen_idx in range(self.num_gens): #evaluation operation: train each program and evaluate it. log_and_print( "Training generation {}'s population of programs.".format( gen_idx + 1)) for programdict in current_population: total_trained_programs += 1 child_start_time = time.time() log_and_print("Training candidate program ({}/{}) {}".format( total_trained_programs, self.total_eval, print_program(programdict['program'], ignore_constants=(not verbose)))) score = execute_and_train(programdict['program'], validset, trainset, train_config, graph.output_type, graph.output_size, neural=False, device=device) log_and_print( "Structural cost is {} with structural penalty {}".format( programdict["struct_cost"], graph.penalty)) log_and_print( "Time to train child {:.3f}".format(time.time() - child_start_time)) log_and_print("Total time elapsed is: {}".format(time.time() - start_time)) programdict["score"] = score programdict["path_cost"] = score + programdict["struct_cost"] programdict["time"] = time.time() - start_time if programdict["path_cost"] < best_total: best_program = copy.deepcopy(programdict["program"]) best_total = score + programdict["struct_cost"] best_score = score best_cost = programdict["struct_cost"] best_programs_list.append(copy.deepcopy(programdict)) log_and_print("New BEST program found:") print_program_dict(best_programs_list[-1]) if total_trained_programs > self.total_eval: break #select the best programs based on cost + score. current_population.sort(key=lambda x: x["path_cost"]) selected_population = current_population[:self.selection_size] #perform crossover on the selected population crossed_population = [] log_and_print("Beginning crossover operation.") while len(crossed_population) < self.population_size: new_prog_dict = crossover_operation(selected_population) if new_prog_dict is not None: crossed_population.append(new_prog_dict) #perform mutations on the crossed population current_population = [] for crossed_prog_dict in crossed_population: if random.random() < self.mutation_prob: log_and_print("Mutating program.") current_population.append( mutation_operation(crossed_prog_dict)) else: current_population.append(crossed_prog_dict) return best_programs_list
def run(self, graph, trainset, validset, train_config, device, verbose=False, trainset_neural=None): assert isinstance(graph, ProgramGraph) log_and_print("Training root program ...") current = copy.deepcopy(graph.root_node) dataset = trainset_neural if trainset_neural is not None else trainset initial_score = execute_and_train(current.program, validset, dataset, train_config, graph.output_type, graph.output_size, neural=True, device=device) log_and_print( "Initial training complete. Score from program is {:.4f} \n". format(1 - initial_score)) order = 0 frontier = ProgramNodeFrontier(capacity=self.frontier_capacity) frontier.add((float('inf'), order, current)) num_children_trained = 0 start_time = time.time() best_program = None best_total_cost = float('inf') best_programs_list = [] while len(frontier) != 0: current_f_score, _, current = frontier.pop(0) log_and_print("CURRENT program has fscore {:.4f}: {}".format( current_f_score, print_program(current.program, ignore_constants=(not verbose)))) log_and_print("Current depth of program is {}".format( current.depth)) log_and_print("Creating children for current node/program") children_nodes = graph.get_all_children(current) # prune if more than self.max_num_children if len(children_nodes) > graph.max_num_children: children_nodes = random.sample( children_nodes, k=graph.max_num_children) # sample without replacement log_and_print("{} total children to train for current node".format( len(children_nodes))) for child_node in children_nodes: child_start_time = time.time() log_and_print("Training child program: {}".format( print_program(child_node.program, ignore_constants=(not verbose)))) is_neural = not graph.is_fully_symbolic(child_node.program) dataset = trainset_neural if ( is_neural and trainset_neural is not None) else trainset child_node.score = execute_and_train(child_node.program, validset, dataset, train_config, graph.output_type, graph.output_size, neural=is_neural, device=device) log_and_print( "Time to train child {:.3f}".format(time.time() - child_start_time)) num_children_trained += 1 log_and_print( "{} total children trained".format(num_children_trained)) child_node.parent = current child_node.children = [] order -= 1 child_node.order = order # insert order of exploration as tiebreaker for equivalent f-scores current.children.append(child_node) # computing path costs (f_scores) child_f_score = child_node.cost + child_node.score # cost + heuristic log_and_print("DEBUG: f-score {}".format(child_f_score)) if not is_neural and child_f_score < best_total_cost: best_program = copy.deepcopy(child_node.program) best_total_cost = child_f_score best_programs_list.append({ "program": best_program, "struct_cost": child_node.cost, "score": child_node.score, "path_cost": child_f_score, "time": time.time() - start_time }) log_and_print("New BEST program found:") print_program_dict(best_programs_list[-1]) if is_neural: assert child_node.depth < graph.max_depth child_tuple = (child_f_score, order, child_node) frontier.add(child_tuple) # clean up frontier frontier.sort(tup_idx=0) while len(frontier) > 0 and frontier.peek(-1)[0] > best_total_cost: frontier.pop(-1) log_and_print("Frontier length is: {}".format(len(frontier))) log_and_print("Total time elapsed is {:.3f}".format(time.time() - start_time)) if best_program is None: log_and_print("ERROR: no program found") return best_programs_list
def run(self, timestamp, base_program_name, hole_node_ind, graph, trainset, validset, train_config, device, verbose=False): assert isinstance(graph, ProgramGraph) log_and_print("Training root program ...") current = copy.deepcopy(graph.root_node) initial_score, l, m = execute_and_train_with_full(base_program_name, hole_node_ind, current.program, validset, trainset, train_config, graph.output_type, graph.output_size, neural=True, device=device) # print("initial losses:") # print(l) # print("initial f1:") # print(m) log_and_print("Initial training complete. Score from program is {:.4f} \n".format(1 - initial_score)) order = 0 frontier = ProgramNodeFrontier(capacity=self.frontier_capacity) #mcheng priority queue frontier.add((float('inf'), order, current)) num_children_trained = 0 start_time = time.time() best_program = None best_total_cost = float('inf') best_programs_list = [] # if not os.path.exists(timestamp): # os.makedirs(timestamp) while len(frontier) != 0: current_f_score, _, current = frontier.pop(0) log_and_print("CURRENT program has fscore {:.4f}: {}".format( current_f_score, print_program(current.program, ignore_constants=(not verbose)))) log_and_print("Current depth of program is {}".format(current.depth)) log_and_print("Creating children for current node/program") children_nodes = graph.get_all_children(current) # print(children_nodes) # prune if more than self.max_num_children truncated_children = [] symbolic_children = [] if len(children_nodes) > graph.max_num_children: #keep all neural ones for c in children_nodes: is_neural = not graph.is_fully_symbolic(c.program) if is_neural: truncated_children.append(c) else: symbolic_children.append(c) n = len(truncated_children) if n < graph.max_num_children: #get weights for each child # if print_program(current.program).split('(')[-1].split(')')[0] == 'AtomToAtomModule': # weights = [] # # print(weights_dict) # for c in symbolic_children: # diff_node = print_program(c.program).split('(')[-2] # # print(print_program(c.program)) # # print(diff_node) # # try: # # weights.append(weights_dict[diff_node]) # # except IndexError: # # print('tutu') # # weights.append(0) # else: #weight equally # weights = [1] * len(symbolic_children) # #make into probabilities # sum_h = sum(weights) # probs = [i/sum_h for i in weights] # print(probs) picked_children = np.random.choice(symbolic_children, graph.max_num_children - n) #p=probs truncated_children.extend(picked_children) # truncated_children.extend(random.sample(symbolic_children, k=graph.max_num_children-n)) # sample without replacement else: print(truncated_children) truncated_children = random.sample(truncated_children, k=graph.max_num_children) children_nodes = truncated_children print(children_nodes) #todo if theres more neural children than alloewd.... log_and_print("{} total children to train for current node".format(len(children_nodes))) for child_node in children_nodes: child_start_time = time.time() log_and_print("Training child program: {}".format(print_program(child_node.program, ignore_constants=(not verbose)))) is_neural = not graph.is_fully_symbolic(child_node.program) #mcheng is not complete child_node.score, l, m = execute_and_train_with_full(base_program_name, hole_node_ind, child_node.program, validset, trainset, train_config, graph.output_type, graph.output_size, neural=is_neural, device=device) ## print losses and 1-f1 score for training # plt.close() # plt.figure() # plt.plot(l[2:]) # plt.title("losses %s" % print_program(child_node.program, ignore_constants=(not verbose))) # plt.savefig("%s/losses_%s.png" % (timestamp,print_program(child_node.program, ignore_constants=(not verbose)))) # plt.close() # plt.figure() # plt.plot(m[2:]) # plt.title("f1 %s" %print_program(child_node.program, ignore_constants=(not verbose))) # plt.savefig("%s/f1_%s.png" % (timestamp,print_program(child_node.program, ignore_constants=(not verbose)))) log_and_print("Time to train child {:.3f}".format(time.time() - child_start_time)) num_children_trained += 1 log_and_print("{} total children trained".format(num_children_trained)) child_node.parent = current child_node.children = [] order -= 1 child_node.order = order # insert order of exploration as tiebreaker for equivalent f-scores current.children.append(child_node) # computing path costs (f_scores) child_f_score = child_node.cost + child_node.score # cost + heuristic log_and_print("DEBUG: f-score {}".format(child_f_score)) if not is_neural and child_f_score < best_total_cost: best_program = copy.deepcopy(child_node.program) best_total_cost = child_f_score best_programs_list.append({ "program" : best_program, "struct_cost" : child_node.cost, "score" : child_node.score, "path_cost" : child_f_score, "time" : time.time()-start_time }) log_and_print("New BEST program found:") print_program_dict(best_programs_list[-1]) if is_neural: assert child_node.depth < graph.max_depth child_tuple = (child_f_score, order, child_node) frontier.add(child_tuple) # clean up frontier frontier.sort(tup_idx=0) while len(frontier) > 0 and frontier.peek(-1)[0] > best_total_cost: frontier.pop(-1) log_and_print("Frontier length is: {}".format(len(frontier))) log_and_print("Total time elapsed is {:.3f}".format(time.time()-start_time)) if best_program is None: log_and_print("ERROR: no program found") return best_programs_list #todo look at train fn, todo understand why some of the nodes are neural #starts with a neural fn.