def eval_genomes(genomes, config): for genome_id, genome in genomes: net = create(genome, config, MAP_SIZE) #Wrap the network around an agent agent = Agent(net, in_proc, out_proc) #Evaluate its fitness based on the function given above. genome.fitness = evaluation_func(agent)
def eval_genomes_novelty(genomes, config): #Re-evaluate the archive evaluator.reevaluate_archive() for genome_id, genome in genomes: net = create_f(genome, config) #Wrap the network around an agent agent = Agent(net, in_proc, out_proc) #Evaluate its fitness based on the function given above. genome.fitness = evaluation_func(genome_id, genome, agent)
def binary_3x3_optimal_genome(): Config = namedtuple("Config",["genome_config"]) Genome_config = namedtuple("Genome_config", ["input_keys", "output_keys", "activation_defs", "aggregation_function_defs"]) from utilities import identity from neat.activations import sigmoid_activation from neat.aggregations import sum_aggregation, product_aggregation activations = { "sigmoid": sigmoid_activation, "identity": identity } aggregations = { "sum": sum_aggregation, "product": product_aggregation } genome_config = Genome_config(input_keys=[-1,-2], output_keys= [0], activation_defs=activations, aggregation_function_defs=aggregations) config = Config(genome_config=genome_config) Genome = namedtuple("Genome", ["nodes", "connections"]) Node = namedtuple("Node", ['bias', 'activation', 'aggregation', 'is_isolated', 'is_switch']) Connection = namedtuple("Connection", ["key", "one2one", "extended", "uniform", "weight", "enabled", "is_mod"]) gatinglayer = Node(bias=1, activation='identity', aggregation='product', is_isolated=False, is_switch=False) switchlayer = Node(bias=0, activation='identity', aggregation='sum', is_isolated=False, is_switch=True) outputlayer = Node(bias=0, activation='identity', aggregation="sum", is_isolated=True, is_switch=False) nodes = {0: outputlayer, 1: gatinglayer, 2: switchlayer} inpgatconn = Connection(key = (-1,1), one2one=True, extended=False, uniform=True, weight=1, enabled=True, is_mod=False) inpswiconn = Connection(key = (-1,2),one2one=True, extended=True, uniform=False, weight=10, enabled=True, is_mod=False) gatswiconn = Connection(key = (1,2),one2one=True, extended=False, uniform=True, weight=0.33, enabled=True, is_mod=True) rewgatconn = Connection(key = (-2,1),one2one=True, extended=False, uniform=True, weight=1, enabled=True, is_mod=False) swioutconn = Connection(key = (2,0),one2one=True, extended=False, uniform=True, weight=1, enabled=True, is_mod=False) connections = { (-1,1) : inpgatconn, (-1,2) : inpswiconn, (-2,1) : rewgatconn, (1,2) : gatswiconn, (2,0) : swioutconn } genome = Genome(nodes, connections) import extended_maps network = extended_maps.create(genome, config, 3) import render_network render_network.draw_net(network,False, "optimal3x3") from eval import eval_one_to_one_3x3 from switch_neuron import Agent agent = Agent(network,reorder_inputs, convert_to_action) score = eval_one_to_one_3x3(agent, 1000, 100) print(score)
def run(config_file, generations, binary_file, drawfile, progressfile, statsfile): #Configuring the agent and the evaluation function from eval import eval_one_to_one_3x3 eval_func = eval_one_to_one_3x3 #Preprocessing for inputs: none in_func = reorder_inputs from solve import convert_to_action out_func = convert_to_action #Preprocessing for output - convert float to boolean # Load configuration. config = neat.Config(GuidedMapGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet, neat.DefaultStagnation, config_file) # Create the population, which is the top-level object for a NEAT run. p = neat.Population(config) # Add a stdout reporter to show progress in the terminal. p.add_reporter(neat.StdOutReporter(True)) stats = Reporters.StatReporterv2() p.add_reporter(stats) p.add_reporter(Reporters.ProgressTracker(progressfile)) #p.add_reporter(Reporters.NetRetriever()) #p.add_reporter(neat.Checkpointer(5)) # Run for up to 300 generations. winner = p.run(make_eval_fun(eval_func, in_func, out_func), generations) # Display the winning genome. print('\nBest genome:\n{!s}'.format(winner)) # Show output of the most fit genome against training data. print('\nOutput:') winner_net = create(winner, config, MAP_SIZE) winner_agent = Agent(winner_net, in_func, out_func) print("Score in task: {}".format(eval_func(winner_agent))) print("Input function: Reorder_inputs") print("Output function: convert_to_action") render_network.draw_net(winner_net, filename=drawfile) #Log the maximum fitness over generations from visualize import plot_stats plot_stats(stats, False, view=False, filename=statsfile) #Uncomment the following if you want to save the network in a binary file fp = open(binary_file, 'wb') pickle.dump(winner_net, fp) fp.close()
def solve_one_to_one_3x3(): input_keys = [-1, -2, -3, -4] output_keys = [0] switch_keys = [1, 2, 3] node_keys = [4, 5, 6] nodes = [] modulating_nodes_dict = { 'activation_function': lambda x: clamp(x,-10,10), 'integration_function': mult, 'activity': 0, 'output': 0, 'bias':1 } node_weights = {4: [(-1, 1), (-4, 1)], 5: [(-2, 1), (-4, 1)], 6: [(-3, 1), (-4, 1)]} for i in node_keys: node_dict = copy.deepcopy(modulating_nodes_dict) node_dict['weights'] = node_weights[i] nodes.append(Neuron(i, node_dict)) switch_std_weights = { 1: [(-1, 10), (-1, 0), (-1, -10)], 2: [(-2, 10), (-2, 0), (-2, -10)], 3: [(-3, 10), (-3, 0), (-3, -10)] } switch_mod_weights = { 1: [(4, 1 / 3)], 2: [(5, 1 / 3)], 3: [(6, 1 / 3)] } for key in switch_keys: nodes.append(SwitchNeuron(key, switch_std_weights[key], switch_mod_weights[key])) node_0_std = { 'activation_function': lambda x: clamp(x,-10,10), 'integration_function': sum, 'activity': 0, 'output': 0, 'weights': [(1, 1), (2, 1), (3, 1)], 'bias' : 0 } nodes.append(Neuron(0, node_0_std)) net = SwitchNeuronNetwork(input_keys, output_keys, nodes) agent = Agent(net,lambda x: x,lambda x: convert_to_action(x)) return agent
def run(config_file): #Configuring the agent and the evaluation function from eval import eval_net_xor eval_func = eval_net_xor #Preprocessing for inputs: none in_func = out_func = lambda x: x #Preprocessing for outputs: one-hot max encoding. # Load configuration. config = neat.Config(SwitchGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet, neat.DefaultStagnation, config_file) from utilities import heaviside config.genome_config.add_activation('heaviside', heaviside) # Create the population, which is the top-level object for a NEAT run. p = neat.Population(config) # Add a stdout reporter to show progress in the terminal. p.add_reporter(neat.StdOutReporter(True)) stats = Reporters.StatReporterv2() p.add_reporter(stats) #p.add_reporter(Reporters.NetRetriever()) #p.add_reporter(neat.Checkpointer(5)) # Run for up to 300 generations. winner = p.run(make_eval_fun(eval_func, in_func, out_func), 2000) # Display the winning genome. print('\nBest genome:\n{!s}'.format(winner)) # Show output of the most fit genome against training data. print('\nOutput:') winner_net = create(winner, config) winner_agent = Agent(winner_net, in_func, out_func) print("Score in task: {}".format(eval_func(winner_agent))) #for i, o in (((0,0),0), ((0,1),1), ((1,0),1), ((1,1),0)): # print(f"Input: {i}, Expected: {o}, got {winner_agent.activate(i)}") #Uncomment the following if you want to save the network in a binary file fp = open('winner_net.bin', 'wb') pickle.dump(winner_net, fp) fp.close() #visualize.draw_net(config, winner, True) visualize.plot_stats(stats, ylog=False, view=True)
def solve_tmaze(): input_keys = [-1,-2,-3,-4,-5] output_keys = [0] node_keys = [1,2,3] nodes = [] #Aggregating neuron params = { 'activation_function' : lambda x : x, 'integration_function' : sum, 'activity': 0, 'output' : 0, 'weights' : [(-1,-1), (-5,1)], 'bias':0 } nodes.append(Neuron(1,params)) m_params = { 'activation_function': lambda x: clamp(x, -0.8,0), 'integration_function': mult, 'activity': 0, 'output': 0, 'weights': [(1, 1), (-4, 1)], 'bias' : 1 } nodes.append(Neuron(2,m_params)) std_weights = [(-3,5), (-3,-5)] mod_weights = [(2,-1.25*0.5)] nodes.append(SwitchNeuron(3,std_weights,mod_weights)) o_params = { 'activation_function': tanh, 'integration_function': sum, 'activity': 0, 'output': 0, 'weights': [(3,1)], 'bias' : 0 } nodes.append(Neuron(0,o_params)) net = SwitchNeuronNetwork(input_keys,output_keys,nodes) #For input, append the bias to -1 input agent = Agent(net, append_bias, convert_to_direction) return agent
def main(): schemes = { 'switch': switch_neat.create, 'recurrent': RecurrentNetwork.create, 'switch_maps': switch_maps.create } problems = { 'xor': eval_net_xor, 'binary_association': eval_one_to_one_3x3, 'tmaze': TmazeEvaluator().eval_tmaze, 'double_tmaze': DoubleTmazeEvaluator.eval_double_tmaze, 'homing_tmaze': HomingTmazeEvaluator().eval_tmaze_homing } domain_constant = {'tmaze': 2, 'double_tmaze': 4, 'homing_tmaze': 2} parser = argparse.ArgumentParser( description="Evolve neural networks with neat") parser.add_argument( '-s', '--scheme', help= f"Choose between the available schemes: {','.join(schemes.keys())}", type=str, required=True, choices=schemes.keys()) parser.add_argument('-c', '--config', help="The config file", required=True, type=str) parser.add_argument('-g', '--generations', help="The number of generations", type=int) parser.add_argument( '-p', '--problem', help=f"Available problems: {','.join(problems.keys())}", required=True, type=str, choices=problems.keys()) parser.add_argument('--map_size', help="Set the map size for the relevant schemes", type=int) parser.add_argument('--dump', help="Dump the network in a binary file", type=str) parser.add_argument('--num_episodes', help="Number of episodes for tmaze/binary_association", type=int) parser.add_argument('--switch_interval', help="Interval of episodes for " "shuffling the associations", type=int) parser.add_argument( '--novelty', help='Use the novelty metric instead of the fitness function', action="store_true") parser.add_argument('--threshold', help='Threshold for a new genome to enter the archive', type=float, default=1) parser.add_argument( "--snap_inter", help="Snapshot interval for association problem novelty search", type=int) parser.add_argument( "--draw", help= 'Render the network to a picture. Provide the name of the picture.', type=str, default=None) parser.add_argument( "--log", help="Log the max fitness per generation to text file. (Append)", type=str, default=None) args = parser.parse_args() eval_f = problems[args.problem] in_f = identity out_f = identity genome = neat.DefaultGenome evaluator = None #Configure genome based on the encoding scheme and neurons used if args.scheme == 'switch': genome = switch_neat.SwitchGenome elif args.scheme == 'switch_maps': genome = switch_maps.SwitchMapGenome #Configure the pre-processing and post-processing functions based on #the environment if args.problem == 'binary_association': out_f = convert_to_action elif args.problem in ['tmaze', 'double_tmaze', 'homing_tmaze']: out_f = convert_to_direction #If we use the map-based encoding scheme add the map size parameter to the function #responsible for creating the network from the genotype. create_f = None if args.map_size is not None and (args.scheme in ['maps', 'switch_maps']): create_f = partial(schemes[args.scheme], map_size=args.map_size) else: create_f = schemes[args.scheme] num_episodes = 100 s_inter = 20 if args.num_episodes is not None: num_episodes = args.num_episodes if args.switch_interval is not None: s_inter = args.switch_interval #If the problem is the t-maze task, use the extra parameters episodes and switch interval if args.problem == 'tmaze': if args.novelty: evaluator = TmazeNovelty(num_episodes, samples=4, threshold=args.threshold) eval_f = evaluator.eval else: evaluator = TmazeEvaluator(num_episodes, samples=4) eval_f = evaluator.eval_tmaze elif args.problem == 'double_tmaze': if args.novelty: evaluator = DoubleTmazeNovelty(num_episodes, samples=4, threshold=args.threshold) eval_f = evaluator.eval else: evaluator = DoubleTmazeEvaluator(num_episodes, samples=4) eval_f = evaluator.eval_double_tmaze elif args.problem == 'homing_tmaze': if args.novelty: evaluator = HomingTmazeNovelty(num_episodes, samples=4, threshold=args.threshold) eval_f = evaluator.eval else: evaluator = HomingTmazeEvaluator(num_episodes, samples=4) eval_f = evaluator.eval_tmaze_homing elif args.problem == 'binary_association': if args.novelty: evaluator = AssociationNovelty(num_episodes, rand_iter=args.switch_interval, snapshot_inter=args.snap_inter, threshold=args.threshold) eval_f = evaluator.eval else: eval_f = partial(eval_one_to_one_3x3, num_episodes=num_episodes, rand_iter=s_inter) def make_eval_fun(evaluation_func, in_proc, out_proc, evaluator=None): def eval_genomes(genomes, config): for genome_id, genome in genomes: net = create_f(genome, config) #Wrap the network around an agent agent = Agent(net, in_proc, out_proc) #Evaluate its fitness based on the function given above. genome.fitness = evaluation_func(agent) def eval_genomes_novelty(genomes, config): #Re-evaluate the archive evaluator.reevaluate_archive() for genome_id, genome in genomes: net = create_f(genome, config) #Wrap the network around an agent agent = Agent(net, in_proc, out_proc) #Evaluate its fitness based on the function given above. genome.fitness = evaluation_func(genome_id, genome, agent) if args.novelty: return eval_genomes_novelty else: return eval_genomes config = neat.Config(genome, neat.DefaultReproduction, neat.DefaultSpeciesSet, neat.DefaultStagnation, args.config) config.genome_config.add_activation('heaviside', heaviside) # Create the population, which is the top-level object for a NEAT run. p = neat.Population(config) #Add a stdout reporter to show progress in the terminal. p.add_reporter(neat.StdOutReporter(True)) stats = StatisticsReporter() p.add_reporter(stats) if args.problem in ['double_tmaze', 'tmaze', 'homing_tmaze']: if args.novelty: mutator = Reporters.EvaluatorMutator(evaluator.evaluator) else: mutator = Reporters.EvaluatorMutator(evaluator) p.add_reporter(mutator) # Run for up to ... generations. if args.novelty: f = make_eval_fun(eval_f, in_f, out_f, evaluator) else: f = make_eval_fun(eval_f, in_f, out_f) winner = p.run(f, args.generations) #If we are using the novelty metric get the winner from the archive if args.novelty: winnerid = evaluator.get_best_id() winner = evaluator.archive[winnerid]['genome'] winner_agent = evaluator.archive[winnerid]['agent'] else: print('\nBest genome:\n{!s}'.format(winner)) winner_net = create_f(winner, config) winner_agent = Agent(winner_net, in_f, out_f) if args.novelty: if args.problem == 'binary_association': score = evaluator.eval_func(winner_agent)[0] else: score = evaluator.evaluator.eval_func(winner_agent)[0] else: score = eval_f(winner_agent) print("Score in task: {}".format(score)) if args.draw is not None: if args.scheme in ['maps', 'switch_maps']: map_size = args.map_size else: map_size = -1 render_network.draw_genotype(config, winner, filename=args.draw, map_size=map_size) if args.log is not None: fp = open(args.log, 'a') best_fitness = [str(c.fitness) for c in stats.most_fit_genomes] mfs = ' '.join(best_fitness) fp.write(mfs) fp.write("\n") fp.close() if args.dump is not None: fp = open(args.dump, 'wb') pickle.dump(winner, fp) fp.close() print(f'Agent pre-processing function: {in_f.__name__}') print(f'Agent post-processing function: {out_f.__name__}')