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 run(self, graph, trainset, validset, train_config, device, verbose=False): assert isinstance(graph, ProgramGraph) log_and_print("Training RNN baseline with {} LSTM units ...".format(graph.max_num_units)) current = copy.deepcopy(graph.root_node) score = execute_and_train(current.program, validset, trainset, train_config, graph.output_type, graph.output_size, neural=True, device=device) log_and_print("Score of RNN is {:.4f}".format(1-score)) return current.program
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 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): 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, 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