Welcome to the documentation of the Tensorflow-Neuroevolution framework!

_images/tfne_logo.svg

Version 0.21.1

https://img.shields.io/badge/python-v3.7%2B-informational https://badge.fury.io/py/tfne.svg https://readthedocs.org/projects/tfne/badge/?version=latest https://codecov.io/gh/PaulPauls/Tensorflow-Neuroevolution/branch/master/graph/badge.svg
Documentation of the Tensorflow-Neuroevolution framework.
Copyright: Paul Pauls

Using TFNE

Installation

TFNE, being still in the beta development phase, changes often. To get the most current working release from the PyPI repository, use the following command:

pip install tfne

To enable the rendering of genome graphs in code as well as in the TFNE Visualizer, make sure that the graphviz library is installed on the system (Graphviz Installation). For Ubuntu the following command will install graphviz from the package manager:

sudo apt install graphviz

Import the TFNE library into your code by using the same name (import tfne). The TFNE Visualizer will be available as an executable script after installation under the name tfne_visualizer.


Neuroevolution

TFNE allows for the creation and improvement of artificial neural networks through a population-based optimization process called neuroevolution. In neuroevolution artificial neural networks are represented as genomes, encoding the properties such as topology, hyperparameters, layer configuration, node values, etc. The encoding of the genomes - the genotypes - can arbitrarily be mutated and combined. This allows for the emergence of new genomes that may represent novel ways to solve the optimization problem or the emergence of genomes with combined beneficial properties of two preceding genomes. The quality of the emerging genome is determined by calculating a fitness value that represents the degree to which the artificial neural network that is represented through the genome solves the problem environment. This allows for a relative comparison between genomes.

The optimization process itself can be guided through various means in order to produce the fittest genome. Speciation for example is a popular way of guiding the evolution by clustering genomes based on aspects such as topological similarity of the neural network or similarity in the problem-solving approach. This clustering allows the identification of generally beneficial or detrimental features and allows the optimization process to be guided by focusing its evolutionary development on clusters with beneficial features.


Quick Start

The usage of TFNE is demonstrated in the examples/ directory of the Github repository (see here). The examples employ multiple neuroevolution algorithms, problem environments and approaches to the problem and will be steadily extended in future TFNE releases. The basic approach to solving a problem in TFNE is as follows:

The first step is to decide on which NE algorithm to use and to create a complete configuration for all sections and options of the chosen algorithm. This configuration file needs to be in a format readable by python’s ConfigParser class and is named config-file.cfg in the example below.

import tfne

# Optional in case the ConfigParser object is created manually
config = tfne.parse_configuration('./config-file.cfg')

ne_algorithm = tfne.algorithms.CoDeepNEAT(config)

The next step is the instantiation of the problem environment the chosen neuroevolution algorithm should be applied to. Depending on if the TF model represented through the NE algorithm’s genomes should first be trained before assigning the genome a fitness value, set the weight_training parameter of the chosen problem environment. Some problem environments do not allow for weight-training evaluation while some NE algorithms do not allow for non-weight-training evaluation. Here we are using the CIFAR10 problem environment.

environment = tfne.environments.CIFAR10nvironment(weight_training=True,
                                                  config=config,
                                                  verbosity=0)

# Alternative, though identical, creation of the environment specifying parameters explicitly
# instead of through the config
environment_alt = tfne.environments.CIFAR10nvironment(weight_training=True,
                                                      verbosity=0,
                                                      epochs=8
                                                      batch_size=None)

The instantiated NE algorithm and evaluation environment are then handed over to the driving force of the evolutionary process - the EvolutionEngine. The EvolutionEngine class prepares the start of the evolution and furthermore takes on the parameters for backup_dir_path, max_generations and max_fitness. The backup_dir_path parameter specifies the directory as string to which the evolution state backups should be saved to in order to postanalyze or visualize the evolution later. The parameters max_gnerations and max_fitness specify abort conditions for evolution.

engine = tfne.EvolutionEngine(ne_algorithm=ne_algorithm,
                              environment=environment,
                              backup_dir_path='./',
                              max_generations=64,
                              max_fitness=100.0)

The evolutionary process however is not started until calling the train() function of the set up evolutionary engine. This function returns the best genome - and therefore TF model - as judged by the evaluation environment the evolutionary process could produce.

best_genome = engine.train()
print("Best genome returned by evolution:\n")
print(best_genome)

These few and simple lines summarize the basic usage of TFNE. However, the underlying NE algorithms and environments can be extensively configured resulting in significantly different evolutionary processes. The extent to which the NE algorithms and environments can be configured and how exactly they operate is presented in their respective sections of this documentation.

TFNE however also serves as a prototyping platform for custom neuroevolution algorithms, populations, encodings and environments. The TFNE Architecture & Customization section elaborates on this functionality.


Serialization & Deserialization

All pre-implemented NE algorithms in the TFNE framework serialize and save the state of the evolution in each generation as json files. These backups serve as the input for the TFNE Visualizer or they can serve as initial states for the NE algorithms in case the evolution should be continued from a certain generation onward with a different algorithm configuration (though necessarily the same evaluation environment).

import tfne

config = tfne.parse_configuration('./config-file.cfg')

# Supply path to a backup serving as the initial state
ne_algorithm = tfne.algorithms.CoDeepNEAT(config,
                                          initial_state_file_path='./tfne_state_backup_gen_15.json')

Serialization and deserialization is also possible for single genomes, e.g. in case the best genome of the evolution should be saved and deserialized later.

# Train and save best genome
best_genome = engine.train()
best_genome_file_path = best_genome.save_genotype(save_dir_path='./')

# Load the serialized best genome and get the encoded TF model
loaded_genome = tfne.deserialization.load_genome(best_genome_file_path)
tf_model = loaded_genome.get_model()

# Alternatively, it is also possible to save the TF model directly
best_genome.save_model(file_path='./best_genome_model/')

Projects Using TFNE

  • TBD

TFNE Architecture & Customization

Framework Architecture

The following illustration shows the architecture of the TFNE framework beginning from v0.21.0 onwards. The architecture is shown via an entity-sequence diagram and omits many minor functions in order to emphasize the core evolutionary loop employed by TFNE as well as the most relevant functions of each aspect.

_images/tfne_v0.21_entity_sequence_diagram.svg

Entity-Sequence Diagram Illustrating the Architecture of TFNE


Customizing TFNE

One design goal of TFNE is to be modular and provide a basic prototyping platform for the implementation of similar experimental NE algorithms. TFNE therefore supports custom algorithms, encodings and environments and provides clear abstract interfaces that summarize the requirements for their implementations. While the abstract base classes extensively describe the requirements of the function that they are overwritten with, please also consider the architecture of the TFNE framework as listed above to get a top level view of the module usage in the evolutionary process.

The following 5 abstract base classes are currently present in TFNE and the 3 most important are listed in full:

import tfne

# Abstract Base classes in TFNE
tfne.algorithms.BaseNeuroevolutionAlgorithm()
tfne.populations.BasePopulation()
tfne.encodings.BaseEncoding()
tfne.encodings.BaseGenome()
tfne.environments.BaseEnvironment()

BaseNeuroevolutionAlgorithm (see here)

class BaseNeuroevolutionAlgorithm(object, metaclass=ABCMeta):
    """
    Interface for TFNE compatible algorithms, which encapsulate the functionality of initialization, evaluation,
    evolution and serialization.
    """

    @abstractmethod
    def initialize_population(self, environment):
        """
        Initialize the population according to the specified NE algorithm. Adhere to potential constraints set by the
        environment.
        @param environment: one instance or multiple instances of the evaluation environment
        """
        raise NotImplementedError("Subclass of BaseNeuroevolutionAlgorithm does not implement "
                                  "'initialize_population()'")

    @abstractmethod
    def evaluate_population(self, environment) -> (int, float):
        """
        Evaluate all members of the population on the supplied evaluation environment by passing each member to the
        environment and assigning the resulting fitness back to the member. Return the generation counter and the best
        achieved fitness.
        @param environment: one instance or multiple instances of the evaluation environment
        @return: tuple of generation counter and best fitness achieved by best member
        """
        raise NotImplementedError("Subclass of BaseNeuroevolutionAlgorithm does not implement 'evaluate_population()'")

    @abstractmethod
    def summarize_population(self):
        """
        Print summary of the algorithm's population to stdout to inform about progress
        """
        raise NotImplementedError("Subclass of BaseNeuroevolutionAlgorithm does not implement 'summarize_evaluation()'")

    @abstractmethod
    def evolve_population(self) -> bool:
        """
        Evolve all members of the population according to the NE algorithms specifications. Return a bool flag
        indicating if the population went extinct during the evolution
        @return: bool flag, indicating ig population went extinct during evolution
        """
        raise NotImplementedError("Subclass of BaseNeuroevolutionAlgorithm does not implement 'evolve_population()'")

    @abstractmethod
    def save_state(self, save_dir_path):
        """
        Save the state of the algorithm and the current evolutionary process by serializing all aspects to json
        compatible dicts and saving it as file to the supplied save dir path.
        @param save_dir_path: string of directory path to which the state should be saved
        """
        raise NotImplementedError("Subclass of BaseNeuroevolutionAlgorithm does not implement 'save_state()'")

    @abstractmethod
    def get_best_genome(self) -> BaseGenome:
        """
        @return: best genome so far determined by the evolutionary process
        """
        raise NotImplementedError("Subclass of BaseNeuroevolutionAlgorithm does not implement 'get_best_genome()'")

    @abstractmethod
    def get_eval_instance_count(self) -> int:
        """
        @return: int, specifying how many evaluation threads the NE algorithm uses
        """
        raise NotImplementedError("Subclass of BaseNeuroevolutionAlgorithm does not implement "
                                  "'get_eval_instance_count()'")

BaseGenome (see here)

class BaseGenome(object, metaclass=ABCMeta):
    """
    Interface for TFNE compatible genomes, which encapsulates all necessary functionality used by the algorithm,
    evaluation environment, visualizer, etc.
    """

    @abstractmethod
    def __call__(self, inputs) -> tf.Tensor:
        """
        Call genome to start inference based on the internal model. Return the results of the inference.
        @param inputs: genome model inputs
        @return: results of the genome model inference
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement '__call__()'")

    @abstractmethod
    def __str__(self) -> str:
        """
        @return: string representation of the genome
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement '__str__()'")

    @abstractmethod
    def visualize(self, show, save_dir_path, **kwargs) -> str:
        """
        Visualize the genome. If 'show' flag is set to true, display the genome after rendering. If 'save_dir_path' is
        supplied, save the rendered genome as file to that directory. Return the saved file path as string.
        @param show: bool flag, indicating whether the rendered genome should be displayed or not
        @param save_dir_path: string of the save directory path the rendered genome should be saved to.
        @param kwargs: Optional additional arguments relevant for rendering of the specific genome implementation.
        @return: string of the file path to which the rendered genome has been saved to
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'visualize()'")

    @abstractmethod
    def serialize(self) -> dict:
        """
        @return: serialized constructor variables of the genome as json compatible dict
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'serialize()'")

    @abstractmethod
    def save_genotype(self, save_dir_path) -> str:
        """
        Save genotype of genome to 'save_dir_path' directory. Return file path to which the genotype has been saved to
        as string.
        @param save_dir_path: string of the save directory path the genotype should be saved to
        @return: string of the file path to which the genotype has been saved to
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'save_genotype()'")

    @abstractmethod
    def save_model(self, file_path, **kwargs):
        """
        Save TF model of genome to specified file path.
        @param file_path: string of the file path the TF model should be saved to
        @param kwargs: Optional additional arguments relevant for TF model.save()
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'save_model()'")

    @abstractmethod
    def set_fitness(self, fitness):
        """
        Set genome fitness value to supplied parameter
        @param fitness: float of genome fitness
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'set_fitness()'")

    @abstractmethod
    def get_genotype(self) -> Any:
        """
        @return: One or multiple variables representing the genome genotype
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'get_genotype()'")

    @abstractmethod
    def get_model(self) -> tf.keras.Model:
        """
        @return: TF model represented by genome genotype
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'get_model()'")

    @abstractmethod
    def get_optimizer(self) -> Union[None, tf.keras.optimizers.Optimizer]:
        """
        Return either None or TF optimizer depending on if the genome encoding associates an optimizer with the genome
        @return: None | TF optimizer associated with genome
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'get_optimizer()'")

    @abstractmethod
    def get_id(self) -> int:
        """
        @return: int of genome ID
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'get_id()'")

    @abstractmethod
    def get_fitness(self) -> float:
        """
        @return: float of genome fitness
        """
        raise NotImplementedError("Subclass of BaseGenome does not implement 'get_fitness()'")

BaseEnvironment (see here)

class BaseEnvironment(object, metaclass=ABCMeta):
    """
    Interface for TFNE compatible environments, which are supposed to encapsulate a problem and provide the necessary
    information and functions that the TFNE pre-implemented algorithms require.
    """

    @abstractmethod
    def eval_genome_fitness(self, genome) -> float:
        """
        Evaluates the genome's fitness in either the weight-training or non-weight-training variant. Returns the
        determined genome fitness.
        @param genome: TFNE compatible genome that is to be evaluated
        @return: genome calculated fitness
        """
        raise NotImplementedError("Subclass of BaseEnvironment does not implement 'eval_genome_fitness()'")

    @abstractmethod
    def replay_genome(self, genome):
        """
        Replay genome on environment by calculating its fitness and printing it.
        @param genome: TFNE compatible genome that is to be evaluated
        """
        raise NotImplementedError("Subclass of BaseEnvironment does not implement 'replay_genome()'")

    @abstractmethod
    def duplicate(self) -> BaseEnvironment:
        """
        @return: New instance of the environment with identical parameters
        """
        raise NotImplementedError("Subclass of BaseEnvironment does not implement 'duplicate()'")

    @abstractmethod
    def get_input_shape(self) -> (int, ...):
        """
        @return: Environment input shape that is required from the applied TF models
        """
        raise NotImplementedError("Subclass of BaseEnvironment does not implement 'get_input_shape()'")

    @abstractmethod
    def get_output_shape(self) -> (int, ...):
        """
        @return: Environment output shape that is required from the applied TF models
        """
        raise NotImplementedError("Subclass of BaseEnvironment does not implement 'get_output_shape()'")

TFNE Visualizer

The TFNE Visualizer is included in the PyPI package of TFNE and offers visualization of the neuroevolution process for all pre-implemented TFNE algorithms. The TFNE Visualizer can be started as a separate script by executing tfne_visualizer from the command line or by initializing it via the following function of TFNE, optionally supplying the path to the tfne state backup that is to be visualized:

import tfne

tfne.start_visualizer('./tfne_state_backups/')

If no path to the TFNE state backup is supplied in the function call or the visualizer is started as a script from the command line, does TFNEV show the welcome window, as seen in the figure below. The welcome window allows to open a file dialog and to choose the TFNE state backup via the familiar directory interface.

_images/tfnev_welcome_illustration.png

TFNE Visualizer Welcome Window

Once a TFNE state backup folder has been selected does the visualizer automatically load all population backups, analyze the type of backup and open the visualization window for the appropriate NE algorithm. The figure below illustrates the visualization of an example CoDeepNEAT state trace that is provided with the CoDeepNEAT-MNIST example that can be found here.

_images/tfnev_demonstration.gif

TFNE Visualizer CoDeepNEAT Window

TFNE Development

Version History

v0.21.1 (3rd Sep, 2020)

  • Fix bug of missing TFNEV icons in PyPI package

  • Fix bug of logging level in examples being interpreted as string instead of int

v0.21.0 (3rd Sep, 2020)

  • Bug fix and performance optimize beta version of CoDeepNEAT, releasing CoDeepNEAT fully with all intended speciation methods

  • Implement TFNE Visualizer with capability to process CoDeepNEAT population backups

  • Create ReadTheDocs documentation for TFNE

  • Implement extensive unit tests and coverage reporting

  • Make TFNE available via PyPI

v0.2 (5th June, 2020)

  • Extensively rework framework architecture to enable higher modularity, performance and maintainability

  • Release beta version of CoDeepNEAT, including basic speciation

  • Implement MNIST and CIFAR10 environments with corresponding examples

  • Implement full periodic state backup and deserialization

v0.1 (23rd March, 2020)

  • Initial release providing prototyping framework for neuroevolution with TF 2.x

  • Implement NEAT algorithm with direct encoding and fully TF translateable phenotype

  • Implement OpenAI gym test environments and provide examples in combination with NEAT

  • Implement configurable reporting agents that backup the population and visualize genomes each generation


Future ToDos

General

  • Implement custom tf.keras.preprocessing functions as used for example in CDN paper, using tf.image API/functions. Integrate those preprocessing options into the TFNE environments.

  • Implement a test-wise multi-objective evolution environment [e.g. decreasing fitness based on age; decreasing fitness based on genome complexity]

Code Improvements

  • Implement bidirection connections for the phenotype graphs of all NEAT-like algorithms, as they currently only support feedforward graphs.

  • Replace numpy with Google JAX backend and test if it improves performance. Especially relevant for vanilla NEAT, which utilizes numpy extensively.

  • Attempt to accelerate TFNE and its algorithms (particularly vanilla NEAT)using tf.function

NEAT

  • Completely rework NEAT implementation. Accelerate implementation by parallelizing it. Test possible acceleration by using Google JAX.

  • Implement flag to either disable bias, to allow bias being a separate node or to integrate bias into nodes

DeepNEAT

  • Implement DeepNEAT. Consider layers: Attention, AveragePoolingX, BatchNormalization, BiDirectional, ConvX, Dense, Dropout, Embedding, Flatten, GRU, GlobalAvgPoolX, GlobalMaxPoolX, LSTM, MaxPoolingX, SimpleRNN

CoDeepNEAT

  • CoDeepNEAT: Create function to register new modules created outside of code structure. This way it is easier to add new modules if you use TFNE exclusively as a library.

SubGraphNEAT

SubGraphDeepNEAT

Research Ideas

  • Find way to determine if 2 genomes represent identical phenotypes or identical functions but have different genotypes and are therefore classified as different species, therefore decreasing effective pop size.

  • Implement Lamarckian Evolution for weight-training based NE algorithms (DeepNEAT, CoDeepNEAT, etc)

  • Use a gram matrix to cluster member vectors and direct evolution

CoDeepNEAT Overview

CoDeepNEAT Publication

Title

Evolving Deep Neural Networks

Authors

Risto Miikkulainen and Jason Liang and Elliot Meyerson and Aditya Rawal and Dan Fink
and Olivier Francon and Bala Raju and Hormoz Shahrzad and Arshak Navruzyan
and Nigel Duffy and Babak Hodjat

Booktitle

Artificial Intelligence in the Age of Neural Networks and Brain Computing

Editor

Robert Kozma and Cesare Alippi and Yoonsuck Choe and Francesco Carlo Morabito

Publisher

Amsterdam: Elsevier

Year

2018


CoDeepNEAT Overview

The Coevolution Deep NeuroEvolution of Augmemting Topologies (CoDeepNEAT) method was first introduced in 2018 by a Team of researchers at the University of Texas, Austin and Sentient Technologies. CoDeepNEAT is a layer evolving algorithm that aims to exploit repetitive structure in the problem domain. It does so by splitting the genome into two elements that can be combined to form a genome, though which each have their own population that is evolved separately according to the methods of neuroevolution. The two elements that make up a genome are termed the blueprint and the modules. A module is a small deep neural network of predefined complexity and configuration that is intended to represent one instance of the repetitive structure of the problem domain. Those modules are concatenated in an overarching graph, that is the blueprint. This blueprint graph is very similar to the genome graph employed by DeepNEAT though instead of nodes representing layers do the nodes of the blueprint graph represent modules, whereas a single module is often repeated multiple times in a blueprint graph. This neuroevolution method therefore aims to evolve neural network with repetitive topologies to effectively exploit repetitive structure in the problem domain. In its original publication the algorithm has very successfully been applied to image recognition, language modeling and image captioning tasks, even producing new state of the art results if given sufficient time to evolve.


Projects involving CoDeepNEAT

Cognizant LEAF framework - The evolutionary AI framework offered by cognizant. The framework is based on CoDeepNEAT according to the paper introducing LEAF to the public. Cognizant also offers an array of additional resources about evolutionary algorithms and their benefits for business and research.

[More Projects to be Added in the Future]

CoDeepNEAT Specification

Note

This documentation solely lists the algorithm & encoding specifications without concerning itself with the validity or potential of the specific choices that make up the CoDeepNEAT method.

Warning

This documentation outlines the CoDeepNEAT algorithm & encoding specifications as understood by the TFNE project. While the TFNE project aims to stay as close as possible to the original specification, does it also aim to be a superset of the configuration options of the original specification. This specification also concretizes the algorithm specification if the original specification is too vague and no code was supplied. If you find an issue with the specification or the implementation details please contact tfne@paulpauls.de. Thank you.


CoDeepNEAT Encoding

The genotype of a CoDeepNEAT genome is made up of 2 essential parts. The first part is the CoDeepNEAT blueprint, specifying the ANN topology and the training hyperparameters that will be associated with the genome. The second part is a collection of small fully functional deep neural networks, termed the CoDeepNEAT modules, that will replace the nodes in the blueprint specified ANN topology. It is important to understand these two essential parts, what they entail, their exact contribution to the final genome and how exactly they are evolved in order to fully understand the CoDeepNEAT encoding and resulting genomes.

CoDeepNEAT Blueprint

Blueprint genotype

• Blueprint graph
• Optimizer configuration

A blueprint is the fundamental building block of a CoDeepNEAT genome, specifying the genome’s basic ANN topology as well as all its hyperparameters that may be associated with that genome.

In TFNE the current extent of hyperparameters saved by blueprints is a full configuration of a Tensorflow optimizer, specifying all variables required for the training of the genome phenotype TF model. Additional hyperparameters such as possible training preprocessing operations can also be included, though are currently not part of TFNE’s CoDeepNEAT. This Tensorflow optimizer configuration is the first part of the blueprint’s genotype.

The second part of the blueprint genotype is the graph that is specifying the basic ANN topology. This graph will be referred to as the blueprint graph. The blueprint graph is a collection of node and connection gene instances. In TFNE, those node and connection gene classes are defined as listed below, demonstrating the extent of the information they contain. The purpose and functionality of these blueprint graph genes is very similar to the functionality of genome genes in the original NEAT algorithm [see NEAT], as they are adapted from those. The difference being that each node gene stores a module species and each connection gene merely indicates connections between nodes but not associated connection weights. As in NEAT is TFNE currently restricting the blueprint graph to representing a feedforward graph, though a later addition to support full recurrent graphs is planned.

class CoDeepNEATBlueprintNode:
    def __init__(self, gene_id, node, species):
        self.gene_id = gene_id
        self.node = node
        self.species = species

class CoDeepNEATBlueprintConn:
    def __init__(self, gene_id, conn_start, conn_end, enabled=True):
        self.gene_id = gene_id
        self.conn_start = conn_start
        self.conn_end = conn_end
        self.enabled = enabled

    def set_enabled(self, enabled):
        self.enabled = enabled

Each gene is assigned an ID. This ID is not unique to each gene instance but unique to each configuration of (node, species) or (conn_start, conn_end) respectively. This behavior is important to adhere to the principle of Historical Markings [see NEAT]. The node value is graph-unique integer identifier for each node and is specified in conn_start and conn_end as the start- and endpoint of the connection. Each connection can be disabled through a mutation or crossover. The species value is the ID of an existing, non-extinct module species and is relevant for the later assembly of the final genome phenotype model, combining blueprint and modules.

CoDeepNEAT Module

Module genotype

• Merge method
• Module DNN parameters

A CoDeepNEAT module is a class of small deep neural networks that can take on only limited complexity. The ANN topology as well as the parameters of the ANN layers are determined through a uniform set of parameters serving as the module genotype. However, since the set of parameters for a module instance is uniform and bounded, does this prevent the topology to become overly complex as only limited information can be stored in a CoDeepNEAT module instance. On the other hand does this allow for a direct comparison of module parameters as each module instance stores values for each module parameter.

A CoDeepNEAT module is obviously a very general concept and its specifics are highly dependent on the concrete implementation. A simple example module is the pre-implemented DenseDropout module [see CoDeepNEAT Modules], whose genotype storing has been implemented in TFNE as listed below. The module stores multiple parameters for the initial dense layer, a flag determining the presence of an optional subsequent dropout layer as well as parameters for that subsequent dropout layer. This simple class of module can only represent 2 possible ANN topologies, though it can potentially represent any valid parameter combination for the layer configuration.

class CoDeepNEATModuleDenseDropout(CoDeepNEATModuleBase):

    ...

    # Register the module parameters
    self.merge_method = merge_method
    self.units = units
    self.activation = activation
    self.kernel_init = kernel_init
    self.bias_init = bias_init
    self.dropout_flag = dropout_flag
    self.dropout_rate = dropout_rate

The uniformity of module parameters mentioned above simplifies evolutionary operations such as speciation, mutation and crossover. More importantly however does the resulting limited complexity resemble the concept of CoDeepNEAT in that it aims to evolve effective small DNNs in a repetitive network topology quickly in order to exploit the same repetitive structure in the problem environment. These repetitive and deep structures are seen in many successful recent DNNs.

The module genotype also requires a specification of a specific merge method as well as a method for downsampling input for this module. Both methods become relevant when combining blueprint and modules in the genome assembly. As the creation of an appropriate downsampling layer can be very complex is this functionality coded into the module itself in TFNE and is therefore not part of the genotype.

The section CoDeepNEAT Modules introduces multiple pre-implemented modules provided by TFNE.

CoDeepNEAT Genome

Genome genotype

• Blueprint
• 1 Module for each Mod species present in BP
• Output layers

A CoDeepNEAT genome is comprised of 1 blueprint and 1 module for each module species that is present in the nodes of the BP graph. The genome adopts all hyperparameters from the associated blueprint, which in TFNE implies the configuration of the TF optimizer used in the eventual model training.

The phenotype of the genome is a Tensorflow model that is assembled by combining the blueprint graph and modules. The basic topology of the phenotype model is dictated by the graph represented in blueprint graph. TFNE currently only supporting feedforward graphs, though we hope to implement recurrent graphs soon. Each node in that blueprint graph will be replaced by a module, depending on the species value of the node. As modules themselves are small DNNs will the resulting graph be a full DNN consisting of multiple small DNNs that are connected to each other. If a module has multiple inputs will the inputs be merged according to the merge_method genotype value of the module. If a module has an input with mismatching dimensions will the input be downsampled through the specific downsampling method associated with the module type, which in TFNE can be accessed through create_downsampling_layer(...). The genotype graph is fully assembled when appending a predefined set of output layers to the final layer of the evolved graph, in order to conform with the required output of the problem environment.

The modules that are chosen to replace the graph nodes based on their species value, are selected as follows: Each species value in the nodes of the blueprint graph is identifying an existing, non-extinct module species (a species is a cluster of similar members, see CoDeepNEAT Evolution below). For each species value that is present in the blueprint graph, select one specific module from that identified module species. The created association between species ID value and specific module is the above mentioned part of the genome genotype. In the phenotype TF model assembly replace each node with the same corresponding specific module. This way beneficial topological structure and parametrized layers are replicated throughout the final TF model in order to exploit the same repetitive structure in the problem environment.

To summarize is the exact process of translating the genome genotype into the phenotype model illustrated below:

_images/codeepneat_genome_assembly_illustration.svg

Illustration of the Assembly of a CoDeepNEAT Genome from Blueprint and Modules


CoDeepNEAT Algorithm

Unlike traditional neuroevolution algorithms does the CoDeepNEAT algorithm not operate on and evolve genomes directly, but instead primarily operates on blueprints and modules. Genomes are only assembled during the evaluation in order to determine the fitness of the associated blueprints and modules.

Initialization

see CoDeepNEAT.initialize_population(…)

CoDeepNEAT initializes a minimal population as it has been modeled after NEAT, an additive neuroevolution algorithm. The initialization is therefore very simple. All modules of the population are initialized with random parameters and assigned to a single species.

All blueprints are initialized with a minimal graph of 2 nodes and a connection. The first node is node 1, serving as a special, non mutateable, input layer. The second node is node 2, serving as the output layer and being assigned a species value identifying the single species ID all initialized modules have been assigned to. The hyperparameters of all blueprints are initialized with random parameters. As done for modules will all blueprints of the population be assigned to a single initial blueprint species.

Evaluation

[see CoDeepNEAT.evaluate_population(…)]

The CoDeepNEAT population is evaluated by assembling genomes from the population of blueprints and modules, evaluating those genomes and then transferring the achieved genome fitness back to their blueprint and module components.

For each blueprint in the population the algorithm assembles a predefined number of genomes that take that blueprint as their base. For each of these genomes that are to be assembled, specific modules of the referenced blueprint graph node species are chosen randomly from the module species. That blueprint, randomly chosen modules of all referenced module species as well as the constant set of output layers constitute a full genome genotype and generate a phenotype TF model according to the genome encoding above. The assembled genome is then applied to the evaluation environment and assigned the resulting fitness score.

If due to the random choice of modules for the blueprint graph an invalid TF model is generated from the genome genotype, the assembled genome is assigned a fitness score of 0. As the evolutionary process evolves blueprints and modules separately is it impossible to guarantee a genotype that results in a valid TF model when both blueprints and modules are paired randomly and without knowledge of that pairing during evolution.

The fitness value of the blueprints and modules is calculated after all genomes of the generation have been generated and evaluated. The fitness value of both blueprints and modules is the average fitness value of all genomes in which the respective blueprint or module was involved in.

Evolution

[see CoDeepNEAT.evolve_population(…)]

Evolving the CoDeepNEAT population can be divided into three major phases. First, the CoDeepNEAT population needs to be selected, which means that species and members of the population deemed fit enough to create offspring are selected while the rest of the population is erased. The second phase is the actual evolution, during which the parental members of the generation are mutated and crossed over in order to create novel offspring with beneficial features. The third and last phase during the evolution of a generation is the speciation of the population. The speciation clusters the members of the population in similar groups in order to identify traits and features, determine if those traits and features are beneficial and if applicable, facilitate the spread of those features or remove them from the population. The evolution of NEAT-like neuroevolution algorithms is guided through this speciation. TFNE currently supports three speciation methods for both modules and blueprints respectively, which are based on speciation methods from the original NEAT algorithm, though which have not been explicitly defined in the original research paper.

Since the different methods of speciation are very complex and take on an important role in NEAT-like neuroevolution algorithms is this specification of the CoDeepNEAT evolution subdivided into the specification of the actual mutation and crossover of the modules and blueprints as well as into the specification of the different speciation methods for them.

Module Mutation & Crossover

The actual mutation and crossover phase for modules is very simple. As during the preceding selection phase all eligible parents for offspring have been determined and the number of offspring for each species has been calculated. New modules are created by conforming to those determined parameters and mutate / crossover the intended amount of parents until the determined amount of offspring for each species has been reached. New modules are not automatically assigned the same species as their parents but are to be assigned to a species independently in the following speciation phase. In TFNE, if the mod_spec_reinit_extinct parameter has been set to true will the amount of modules belonging to species that went extinct in the preceding phase be reinitialized and treated as regular offspring that will be speciated in the following phase.

Mutation - Mutation for modules is the simple perturbation of the parameters of the parent module. The extent and manner in which this takes place is left up to the concrete implementation of module class. TFNE’s pre-implemented modules perturb the parent module’s parameters during mutation by selecting the offspring parameter from a normal distribution with the parent parameter value as the mean and the size of the standard distribution set via config. Mutating categorical parameters is done by randomly choosing a new value. TFNE also supports a config parameter (mod_max_mutation) that specifies the maximum degree in percent to which the parent parameters can be mutated.

Crossover - Crossover for modules is again left up to the concrete module class implementation. In TFNE pre-implemented modules, crossover is performed by averaging out the sortable parameters of both parent modules while categorical parameters are carried over from the fitter parent module.

Blueprint Mutation & Crossover

The mutation and crossover phase for blueprints is very similar to that of modules, with the exception of having different explicit mutation and crossover operations and an extra constraint regarding the extinction of module species. The first step of the mutation and crossover phase for blueprints is the check of all parental blueprints if their blueprint graphs contain references to module species (in the species value of the nodes) that are going extinct during this generation’s evolution. If so, the parent’s blueprint graph is mutated by replacing all references to extinct module species with references to randomly chosen non-extinct module species. The resulting mutated blueprint is then kept as a potential parent instead of the non-valid blueprint.

The rest of the mutation and crossover phase for blueprints is identical to that of modules. New offspring for each species is generated according to the predetermined amount. The type of mutation or crossover through which the offspring is generated is determined via percentage chance set via the config. Reinitialized blueprints will be generated if the bp_spec_reinit_extinct config parameter has been enabled. All generated offspring will be speciated in the following phase.

Add Connection Mutation - This mutation adds one or multiple connections to the blueprint graph. Activating a disabled connection also counts as an added connection. The connection start and end nodes are chosen randomly. In TFNE, the amount of connections to add to the blueprint graph is determined by the bp_max_mutation config value, though at least 1.

Add Node Mutation - This mutation adds one or multiple nodes to the blueprint graph. Nodes are added by placing them in the middle of existing and enabled connections. The chosen connection is disabled and 1 node and 2 connection genes are added. The species value of the new node is chosen randomly. In TFNE, the amount of nodes to add to the blueprint graph is determined by the bp_max_mutation config value, though at least 1.

Remove Connection Mutation - This mutation removes one or multiple connections from the blueprint graph. Connections are removed randomly, though only connections that are not the last incoming or outgoing connections are considered (as not to desert a node and therefore also effectively remove a node). In TFNE, the amount of connections to remove from the blueprint graph is determined by the bp_max_mutation config value, though removing 0 connections due to none being available is valid. This mutation was not included in the original specification, as NEAT-like neuroevolution algorithms are exclusively additive.

Remove Node Mutation - This mutation removes one or multiple nodes from the blueprint graph. Nodes that are to be removed are chosen randomly, though the input and output node are unavailable. All connections interacting with the removed node are also removed and replaced by connections between all incoming nodes to all outgoing nodes of the node to be removed. In TFNE, the amount of nodes to remove from the blueprint graph is determined by the bp_max_mutation config value, though removing 0 nodes due to none being available is valid. This mutation was not included in the original specification, as NEAT-like neuroevolution algorithms are exclusively additive.

Node Species Mutation - This mutation changes one or multiple node species values of the blueprint graph. Nodes that are to be mutated are chosen randomly. The new species value of mutated nodes is chosen randomly from all existing, non-extinct module species. In TFNE, the amount of nodes to mutate in the blueprint graph is determined by the bp_max_mutation config value, though at least 1.

Optimizer Mutation - This mutation changes one or multiple parameters of the blueprint associated optimizer. Categorical parameters are mutated by choosing randomly from all available values. Sortable parameters are mutated by choosing a value from a normal distribution with the parent parameter value as the mean and the size of the standard distribution set via config. In TFNE, the amount of optimizer parameters to mutate is determined by the bp_max_mutation config value, though at least 1.

Crossover - Crossover combines the blueprint graphs of both parent blueprints and carries over the hyperparameters of the fitter parent blueprint to create a new offspring. The blueprint graphs are combined by merging all genes of both blueprint graphs. If a gene, identified by its ID, occurs in both parent blueprint graphs, choose randomly. This crossover can create recurrent blueprint graphs In TFNE, as the architecture currently only supports feedforward graphs, is the blueprint graph adjusted by removing recurrent nodes and connections and connecting orphaned nodes (generated by removing recurrent nodes/connections) to the input and output node respectively.

Module Speciation Type: basic

Basic module speciation essentially has the effect of there being only 1 species for each available module type. If only module type is set to be available via the evolution config, then all modules are assigned to the same species.

The offspring for each module species is determined during the selection phase. It is calculated by first determining the intended size of each module species post evolution and then subtracting the amount of elite modules from this intended size. Elite modules are the best modules of the population, which are also carried over to the next generation without change. The amount of elite modules carried over can be set via the configuration. The intended size of each module species is calculated as follows: Let fi be the average fitness of species i. Let p be the total module population size. Let si be the intended size of species i post evolution:

\[s_i = \frac{f_i}{\sum f_i} p\]

In words, the intended size of each module species post evolution corresponds to its share of the total average fitness multiplied by the total population size. Consideration of mathematical edge cases can be seen in the TFNE implementation.

Basic parental module selection is performed removing all modules from each species that do not pass the configuration specified reproduction threshold (see mod_spec_reprod_thres). This reproduction threshold specifies a percentile threshold which potential parent modules have to pass. All modules that do not pass this percentile threshold are removed from the population.

Basic module speciation is extremely simple in that all newly generated modules will be assigned to the same species as the other modules of the same type.

Blueprint Speciation Type: basic

Basic blueprint speciation is very similar to its basic module speciation counterpart. However, since there are no multiple blueprint types possible, are all blueprints constantly assigned to species 1.

Offspring calculation for blueprints in the basic speciation theme is very simple in that corresponds to the blueprint population size minus the elite blueprints for this generation. Elite blueprints are determined analogue to elite modules in the basic speciation scheme in that they are the best blueprints of the generation that are carried over unchanged to the next generation and the amount can be set via the configuration.

Basic parental blueprint selection is performed analogue to basic module parent selection in that blueprints have to be in a higher percentile threshold within the species than specified in the configuration in order to be eligible as parents.

Basic blueprint speciation is extremely simple in that all newly generated blueprints will be assigned to species 1.

Module Speciation Type: param-distance-fixed

The param-distance-fixed speciation scheme clusters the modules into species according to the relative distance of the module parameters. If the parameter distance between a module and the rest of the species is above a certain threshold, does this module found a new species.

In parameter distance (both fixed and dynamic) speciation schemes is it necessary for module species to have a module representative. This species representative is required to have a parameter distance to all other modules in the species that is lower than the config specified threshold for justifying a new species. When calculating the parameter distance of a new module towards an existing module species is this performed by calculating the parameter distance between the module species representative and the new module. The first module that is founding a new module species is considered its species representative.

Since it is possible to generate new species in the parameter distance speciation schemes is it also possible for species to go extinct. In the selection phase, if the average fitness of species has been stagnating for a configuration specified amount of generations will this species be extinguished. In TFNE, a species is considered stagnating if the average fitness has not improved once over the specified timeframe. If the mod_spec_reinit_extinct configuration parameter has been enabled via the configuration will the population share that was intended for the extinguished species be reinitialized as new modules during the mutation & crossover phase. If the reinitialization parameter is disabled, will the population share that was intended for the extinguished species instead be divided among the persisting species.

During the selection phase and before parental modules for the generation are determined is it possible to rebase the module species representative in parameter distance speciation schemes if the configuration parameter mod_spec_rebase_repr is enabled. Rebasing the representative of each module species selects the fittest module of each species as the new module species representative that fulfills the representative requirement of a lower parameter distance to all other modules of the species than the configuration specified threshold.

The calculation of assigned offspring for each module species in parameter distance speciation is very similar to basic module speciation. The assigned offspring is calculated during the selection phase by first determining the intended size of each module species post evolution and then subtracting the amount of elite modules from this intended size. Elite modules are the best modules of the population as well as all module species representatives. These elite modules are carried over to the next generation without change. The amount of elite modules carried over can be set via the configuration. The intended size of each module species is calculated as follows: Let fi be the average fitness of species i. Let p be the total module population size. Let si be the intended size of species i post evolution:

\[s_i = \frac{f_i}{\sum f_i} p\]

In words, the intended size of each module species post evolution corresponds to its share of the total average fitness multiplied by the total population size. Consideration of mathematical edge cases can be seen in the TFNE implementation.

Parental module selection in the parameter distance speciation scheme is identical to that of the basic speciation scheme. All modules that do not pass the configuration specified reproduction percentile threshold (see mod_spec_reprod_thres) are not eligible as parents and are removed from the population.

The speciation phase of the parameter distance scheme functions as follows: Each new module determines the parameter distance to each existing species. The distance to a species is determined by calculating the distance to the species representative. If the new module has a distance below the configuration specified species distance (mod_spec_distance) to one or multiple species, assign the new module to the closest species, meaning the species with the lowest distance. If no existing module species has a distance lower than the config specified distance threshold, create a new species with the new module as its representative.

The exact calculation of the parameter distance between two modules is left up to the concrete module class implementation. In TFNE pre-implemented modules is the parameter distance between two modules calculated by first determining their congruence and then subtracting the actual congruence from the perfect congruence of 1.0. The congruence of continuous parameters is calculated by their relative distance. The congruence of categorical parameters is either 1.0 in case they are the same or it’s 1 divided by the amount of possible values for that specific parameter.

Module Speciation Type: param-distance-dynamic

Dynamic parameter distance speciation is identical to the fixed parameter distance speciation scheme, with 1 addition. The dynamic parameter distance speciation scheme has the additional configuration parameter mod_spec_species_count, which specifies the desired amount of species present throughout the evolutionary process. The desired species count is achieved by adjusting the mod_spec_distance configuration parameter throughout the evolution at the end of the speciation phase.

The exact process of adjusting the module species distance parameter is adaptable. In TFNE, if the actual module species count is lower than the desired module species count then the mod_spec_distance parameter is decreased by 5% in order to make the process of creating new species more sensitive. If the actual module species count is higher than the desired module species count then the distance between all module species representatives is calculated and the mod_spec_distance parameter is replaced by the value that would eliminate all module species except for the desired amount of most distant species.

Blueprint Speciation Type: gene-overlap-fixed

Note

The blueprint gene overlap (both fixed and dynamic) speciation scheme is nearly analogue identical to the module parameter distance speciation schemes, with the exception of the specification on how to calculate the distance between blueprints. For the sake of autonomy though is the whole speciation scheme repeated and slightly adapted. If you are familiar with the module parameter distance speciation scheme feel free to skip to the end at which the calculation of blueprint distance is specified.

The gene-overlap-fixed speciation scheme clusters the blueprints into species according to the percentual amount of overlapping genes in between blueprints. If the gene overlap between a blueprint and the rest of the species is above a certain threshold, does this blueprint found a new species.

In gene overlap (both fixed and dynamic) speciation schemes is it necessary for blueprint species to have a blueprint representative. This species representative is required to have a gene overlap distance to all other blueprints in the species that is lower than the config specified threshold for justifying a new species. When calculating the gene overlap distance of a new blueprint towards an existing blueprint species is this performed by calculating the gene overlap distance between the blueprint species representative and the new blueprint. The first blueprint that is founding a new blueprint species is considered its species representative.

Since it is possible to generate new species in the gene overlap speciation schemes is it also possible for species to go extinct. In the selection phase, if the average fitness of species has been stagnating for a configuration specified amount of generations will this species be extinguished. In TFNE, a species is considered stagnating if the average fitness has not improved once over the specified timeframe. If the bp_spec_reinit_extinct configuration parameter has been enabled via the configuration will the population share that was intended for the extinguished species be reinitialized as new blueprints during the mutation & crossover phase. If the reinitialization parameter is disabled, will the population share that was intended for the extinguished species instead be divided among the persisting species.

During the selection phase and before parental blueprints for the generation are determined is it possible to rebase the blueprint species representative in gene overlap speciation schemes if the configuration parameter bp_spec_rebase_repr is enabled. Rebasing the representative of each blueprint species selects the fittest blueprint of each species as the new blueprint species representative that fulfills the representative requirement of a lower gene overlap distance to all other blueprints of the species than the configuration specified threshold.

The assigned offspring for each blueprint species is calculated during the selection phase by first determining the intended size of each blueprint species post evolution and then subtracting the amount of elite blueprints from this intended size. Elite blueprints are the best blueprints of the population as well as all blueprint species representatives. These elite blueprints are carried over to the next generation without change. The amount of elite blueprints carried over can be set via the configuration. The intended size of each blueprint species is calculated as follows: Let fi be the average fitness of species i. Let p be the total blueprint population size. Let si be the intended size of species i post evolution:

\[s_i = \frac{f_i}{\sum f_i} p\]

In words, the intended size of each blueprint species post evolution corresponds to its share of the total average fitness multiplied by the total population size. Consideration of mathematical edge cases can be seen in the TFNE implementation.

Parental blueprint selection in the gene overlap speciation scheme is identical to that of the basic speciation scheme. All blueprints that do not pass the configuration specified reproduction percentile threshold (see bp_spec_reprod_thres) are not eligible as parents and are removed from the population.

The speciation phase of the gene overlap speciation scheme functions as follows: Each new blueprint determines the gene overlap distance to each existing species. The distance to a species is determined by calculating the distance to the species representative. If the new blueprint has a distance below the configuration specified species distance (bp_spec_distance) to one or multiple species, assign the new blueprint to the closest species, meaning the species with the lowest distance. If no existing blueprint species has a distance lower than the config specified distance threshold, create a new species with the new blueprint as its representative.

The gene overlap distance between two blueprints is calculated by first determining their congruence and then subtracting the actual congruence from the perfect congruence of 1.0. The congruence of two blueprints is calculated by determining the percentual overlap of each blueprint towards the other blueprint and then averaging out that percentual overlap.

Blueprint Speciation Type: gene-overlap-dynamic

Dynamic gene overlap speciation is identical to the fixed gene overlap speciation scheme, with 1 addition. The dynamic gene overlap speciation scheme has the additional configuration parameter bp_spec_species_count, which specifies the desired amount of species present throughout the evolutionary process. The desired species count is achieved by adjusting the bp_spec_distance configuration parameter throughout the evolution at the end of the speciation phase.

The exact process of adjusting the blueprint species distance parameter is adaptable. In TFNE, if the actual blueprint species count is lower than the desired blueprint species count then the bp_spec_distance parameter is decreased by 5% in order to make the process of creating new species more sensitive. If the actual blueprint species count is higher than the desired blueprint species count then the distance between all blueprint species representatives is calculated and the bp_spec_distance parameter is replaced by the value that would eliminate all blueprint species except for the desired amount of most distant species.

CoDeepNEAT Configuration

Example CoDeepNEAT Configuration

Note

This example configuration includes an [EVALUATION] section not specific to the CoDeepNEAT algorithm’s configuration, though which has been included for the purpose of providing a full, functional config file.

[EVALUATION]
epochs        = 8
batch_size    = None
preprocessing = None

[POPULATION]
bp_pop_size    = 25
mod_pop_size   = 45
genomes_per_bp = 4

[GENOME]
dtype                = 'float32'
available_modules    = ['Conv2DMaxPool2DDropout']
available_optimizers = ['SGD', 'Adam']
output_layers        = [{'class_name': 'Flatten', 'config': {}},
                        {'class_name': 'Dense', 'config': {'units': 10, 'activation': 'softmax'}}]

[MODULE_SPECIATION]
mod_spec_type            = 'param-distance-dynamic'
mod_spec_species_count   = 4
mod_spec_distance        = 0.3
mod_spec_mod_elitism     = 2
mod_spec_min_offspring   = 1
mod_spec_reprod_thres    = 0.5
mod_spec_max_stagnation  = 15
mod_spec_species_elitism = 2
mod_spec_rebase_repr     = True
mod_spec_reinit_extinct  = False

[MODULE_EVOLUTION]
mod_max_mutation   = 0.3
mod_mutation_prob  = 0.8
mod_crossover_prob = 0.2

[BP_SPECIATION]
bp_spec_type            = 'gene-overlap-dynamic'
bp_spec_species_count   = 3
bp_spec_distance        = 0.3
bp_spec_bp_elitism      = 2
bp_spec_min_offspring   = 1
bp_spec_reprod_thres    = 0.5
bp_spec_max_stagnation  = 15
bp_spec_species_elitism = 2
bp_spec_rebase_repr     = True
bp_spec_reinit_extinct  = True

[BP_EVOLUTION]
bp_max_mutation            = 0.3
bp_mutation_add_conn_prob  = 0.2
bp_mutation_add_node_prob  = 0.2
bp_mutation_rem_conn_prob  = 0.05
bp_mutation_rem_node_prob  = 0.05
bp_mutation_node_spec_prob = 0.3
bp_mutation_optimizer_prob = 0.1
bp_crossover_prob          = 0.1

[MODULE_CONV2DMAXPOOL2DDROPOUT]
merge_method  = [{'class_name': 'Concatenate', 'config': {'axis': -1}},
                 {'class_name': 'Add', 'config': {}}]
filters       = {'min': 32, 'max': 256, 'step': 32, 'stddev': 32}
kernel_size   = [1, 2, 3]
strides       = [1]
padding       = ['valid', 'same']
activation    = ['linear', 'elu', 'relu']
kernel_init   = ['glorot_uniform']
bias_init     = ['zeros']
max_pool_flag = 0.5
max_pool_size = [2]
dropout_flag  = 0.5
dropout_rate  = {'min': 0.1, 'max': 0.7, 'step': 0.1, 'stddev': 0.2}

[OPTIMIZER_SGD]
learning_rate = {'min': 0.0001, 'max': 0.1, 'step': 0.0001, 'stddev': 0.02}
momentum      = {'min': 0.68, 'max': 0.99, 'step': 0.01, 'stddev': 0.05}
nesterov      = [True, False]

[OPTIMIZER_ADAM]
learning_rate = {'min': 0.0001, 'max': 0.1, 'step': 0.0001, 'stddev': 0.02}
beta_1        = {'min': 0.6, 'max': 1.5, 'step': 0.05, 'stddev': 0.2}
beta_2        = {'min': 0.8, 'max': 1.2, 'step': 0.001, 'stddev': 0.1}
epsilon       = {'min': 1e-8, 'max': 1e-6, 'step': 1e-8, 'stddev': 1e-7}

[POPULATION] Config Parameters

bp_pop_size

Value Range: int > 0

Description: Size of the Blueprint population throughout the evolution. The population size is constant.

mod_pop_size

Value Range: int > 0

Description: Size of the Module population throughout the evolution. The population size is constant.

genomes_per_bp

Value Range: int > 0

Description: Specifies the amount of genomes that are created from blueprints and modules for the evaluation phase of each generation. Each blueprint is accordingly often used as the base topology to create genomes.


[GENOME] Config Parameters

dtype

Value Range: valid Tensorflow datatype

Description: Datatype of the genome phenotype, being a Tensorflow model.

available_modules

Value Range: list of strings of valid TFNE CoDeepNEAT modules

Description: Specifies the module types that will be created during the CoDeepNEAT evolution. The association of module string name to module implementation is in a simple association file within the CoDeepNEAT encoding. This association file registers the names of all pre-implemented CoDeepNEAT modules and can easily be extended to register custom-created modules.

available_optimizers

Value Range: list of strings of valid Tensorflow Optimizers

Description: Specifies the possibly used optimizers that are associated with CoDeepNEAT blueprints. Valid values are string representations of all Tensorflow Optimizers, as TFNE uses Tensorflow deserialization of the optimizers.

output_layers

Value Range: list of dictionaries that represent deserializable Tensorflow layers

Description: Specifies the layers and their configuration that will be appended to the evolved CoDeepNEAT genome in order to control the output despite fitness oriented evolution of the phenotype. The output layers will be appended to the genome in the same order in which they are listed.


[MODULE_SPECIATION] Config Parameters

mod_spec_type

Value Range: ‘basic’ | ‘param-distance-fixed’ | ‘param-distance-dynamic’

Description: Sets speciation method for modules. Can be set to either a basic speciation; a speciation based on the parameter distance of the modules with fixed parameter distance; or a speciation based on the parameter distance of the modules but with dynamically changing parameter distance. For details of these speciation methods, check the CoDeepNEAT specification.

mod_spec_species_count

Value Range: int > 0

Description: [Only applicable when using ‘param-distance-dynamic’ speciation] Specifies the desired species count the dynamic parameter distance speciation scheme should aim for when adjusting the species distance. The species count considers the total amount of species and is not considered per module type.

mod_spec_distance

Value Range: 1.0 >= float >= 0

Description: [Only applicable when using ‘param-distance-fixed’ or ‘param-distance-dynamic’ speciation] Specifies minimum distance of 2 modules such that they are classified into 2 different species.

mod_spec_mod_elitism

Value Range: int >= 0

Description: Specifies the amount of best modules in each species that will be carried over unchanged into the next generation after the evolution. The module elitism has to be at least 1 in order to carry over at least one species representative upon which newly evolved modules are judged if they belong into the same species.

mod_spec_min_offspring

Value Range: int >= 0

Description: Specifies the minimum amount of newly generated offspring for each species, in case the average fitness of the species becomes so relatively low that it isn’t assigned offspring otherwise.

mod_spec_reprod_thres

Value Range: 1.0 >= float >= 0

Description: Specifies the minimum relative fitness threshold of a module compared with other modules in its species in order for the module to be considered a possible parent for reproduction. E.g. if the value 0.4 is chosen then for a module to be considered an eligible parent for the species its fitness has be higher than the bottom 40 percent of the species (or in other words: it has to belong to the top 60% of modules in the species).

mod_spec_max_stagnation

Value Range: int > 0

Description: [Only applicable when using ‘param-distance-fixed’ or ‘param-distance-dynamic’ speciation] Specifies the maximum number of generations a species does not improve its average fitness before it will be considered stagnating and therefore will go extinct. This stagnation is defined as not producing in either of the last x generations an average fitness better than the fitness x generations ago.

mod_spec_species_elitism

Value Range: int >= 0

Description: [Only applicable when using ‘param-distance-fixed’ or ‘param-distance-dynamic’ speciation] Specifies the minimum amount of species that are to survive, regardless of the consideration that they are stagnating or not. The minimum amount of surviving species are the best of the current generation.

mod_spec_rebase_repr

Value Range: bool

Description: [Only applicable when using ‘param-distance-fixed’ or ‘param-distance-dynamic’ speciation] Specifies if after each evolution the species representatives should be rebased to the best module of the species that also holds the minimal distance to all other species representatives as specified in via mod_spec_species_distance.

mod_spec_reinit_extinct

Value Range: bool

Description: [Only applicable when using ‘param-distance-fixed’ or ‘param-distance-dynamic’ speciation] Specifies if the population size occupied by a species should be reinitialized to new modules upon species extinction or if the population size occupied by the extinct species should be divided among the remaining species.


[MODULE_EVOLUTION] Config Parameters

mod_max_mutation

Value Range: 1.0 >= float >= 0

Description: Specifies the maximum percentage to which a module is mutated during evolution from one generation to the next.

mod_mutation_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new module is evolved through mutation of an eligible parent module. Evolution probabilities of modules must add up to 1.

mod_crossover_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new module is evolved through crossover of two eligible parent modules. Evolution probabilities of modules must add up to 1.


[BP_SPECIATION] Config Parameters

bp_spec_type

Value Range: ‘basic’ | ‘gene-overlap-fixed’ | ‘gene-overlap-dynamic’

Description: Sets speciation method for blueprints. Can be set to either a basic speciation; a speciation based on the gene overlap of the blueprints with fixed overlap distance; or a speciation based on the gene overlap of the blueprints but with dynamically changing overlap distance. For details of these speciation methods, check the CoDeepNEAT specification.

bp_spec_species_count

Value Range: int > 0

Description: [Only applicable when using ‘gene-overlap-dynamic’ speciation] Specifies the desired species count the dynamic gene overlap distance speciation scheme should aim for when adjusting the species.

bp_spec_distance

Value Range: 1.0 >= float >= 0

Description: [Only applicable when using ‘gene-overlap-fixed’ or ‘gene-overlap-dynamic’ speciation] Specifies the minimum distance of 2 blueprints such that they are classified into 2 different species.

bp_spec_bp_elitism

Value Range: int >= 0

Description: Specifies the amount of best blueprints in each species that will be carried over unchanged into the next generation after the evolution. The blueprint elitism has to be at least 1 in order to carry over at least one species representative upon which newly evolved modules are judged if they belong into the same species.

bp_spec_min_offspring

Value Range: int >= 0

Description: Specifies the minimum amount of newly generated offspring for each species, in case the average fitness of the species becomes so relatively low that it isn’t assigned offspring otherwise.

bp_spec_reprod_thres

Value Range: 1.0 >= float >= 0

Description: Specifies the minimum relative fitness threshold of a blueprint compared with other blueprints in its species in order for the blueprint to be considered a possible parent for reproduction. E.g. if the value 0.4 is choosen then for a blueprint to be considered an eligible parent for the species its fitness has to be higher than the bottom 40 percent of the species (or in other words: it has to belong to the top 60% of blueprints in the species).

bp_spec_max_stagnation

Value Range: int > 0

Description: [Only applicable when using ‘gene-overlap-fixed’ or ‘gene-overlap-dynamic’ speciation] Specifies the maximum number of generations a species does not improve its average fitness before it will be considered stagnating and therefore will go extinct. This stagnation is defined as not producing in either of the last x generations an average fitness better than the fitness x generations ago.

bp_spec_species_elitism

Value Range: int >= 0

Description: [Only applicable when using ‘gene-overlap-fixed’ or ‘gene-overlap-dynamic’ speciation] Specifies the minimum amount of species that are to survive, regardless of the consideration that they are stagnating or not. The minimum amount of surviving species are the best of the current generation.

bp_spec_rebase_repr

Value Range: bool

Description: [Only applicable when using ‘gene-overlap-fixed’ or ‘gene-overlap-dynamic’ speciation] Specifies if after each evolution the species representatives should be rebased to the best blueprint of the species that also holds the minimal distance to all other species representatives as specified via bp_spec_species_distance.

bp_spec_reinit_extinct

Value Range: bool

Description: [Only applicable when using ‘gene-overlap-fixed’ or ‘gene-overlap-dynamic’ speciation] Specifies if the population size occupied by a species should be reinitialized to new blueprints upon species extinction or if the population size occupied by the extinct species should be divided among the remaining species.


[BP_EVOLUTION] Config Parameters

bp_max_mutation

Value Range: 1.0 >= float >= 0

Description: Specifies the maximum percentage to which a blueprint is mutated during evolution from one generation to the next.

bp_mutation_add_conn_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new blueprint is evolved by adding a connection to an eligible parent blueprint. Evolution probabilities of blueprints must add up to 1.

bp_mutation_add_node_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new blueprint is evolved by adding a node to an eligible parent blueprint. Evolution probabilities of blueprints must add up to 1.

bp_mutation_rem_conn_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new blueprint is evolved by removing a connection from an eligible parent blueprint. Evolution probabilities of blueprints must add up to 1.

bp_mutation_rem_node_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new blueprint is evolved by removing a node from an eligible parent blueprint. Evolution probabilities of blueprints must add up to 1.

bp_mutation_node_spec_prob

Value Range: 1.0 >= float > 0

Description: Specifies the probability that a new blueprint is evolved by mutating the species of the blueprint nodes from an eligible parent blueprint. Evolution probabilities of blueprints must add up to 1.

bp_mutation_optimizer_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new blueprint is evolved by mutating the config options of the blueprint associated optimizer of an eligible parent blueprint. Evolution probabilities of blueprints must add up to 1.

bp_crossover_prob

Value Range: 1.0 >= float >= 0

Description: Specifies the probability that a new blueprint is evolved by crossing over 2 eligible parent blueprints. Evolution probabilities of blueprints must add up to 1.


[MODULE_<MODULE>] Config Parameters

[MODULE_<MODULE>] config parameters specify the configuration options for a module type that has been listed to be available in the GENOME/available_modules configuration parameter. The specific module has to be written in all capital letters.

See the TFNE documentation section on pre-implemented modules for a list of possible configuration parameters for the respective module class.


[OPTIMIZER_<OPTIMIZER>] Config Parameters

TFNE supports all deserializable Tensorflow optimizers. For a list of those optimizers, see the official Tensorflow API. The possible values the optimizers can adapt can be configured in 3 ways:

If the optimizer parameter should have a fixed value, specify that fixed value in the configuration.

If the optimizer parameter is continuous and the optimal value is to be determined by evolution, specify the minimum (min) and maximum (max) value of the optimizer as well as the possible step (step) between different values in a python dict style. Also specify the standard deviation (stddev) that should be applied when mutating the parameter and a new value is chosen for the parameter from a normal distribution.

If the optimizer parameter is discrete and the optimal value is to be determined by evolution, specify all possible values of the parameter in a python list style.

The following code showcases each style of specifying a parameter value or value range for the Stochastic Gradient Descent optimizer:

[OPTIMIZER_SGD]
learning_rate = {'min': 0.0001, 'max': 0.1, 'step': 0.0001, 'stddev': 0.02}
momentum      = 0.7
nesterov      = [True, False]

CoDeepNEAT Modules

This section of the CoDeepNEAT documentation covers pre-implemented module classes that are available in TFNE. An important part of CoDeepNEAT is its extendability by defining one’s own module classes and evolve them. See the last paragraph of this section below to learn how to add your own modules to TFNE and what to consider by inheriting from the TFNE abstract module interface.


Dense-Dropout Module

This is a very simple module. The represented deep neural network consists of a guaranteed dense layer followed by an optional dropout layer. This module has 7 parameters that can be set by the configuration. Of these 7 parameters, 5 are providing parameters for the encoded deep neural network layer and 2 parameters are relevant for the TFNE CoDeepNEAT evolution. Explicitly:

  • merge_method - list of TF deserializable strings specifying a valid merge layer

  • dropout_flag - float [0; 1.0] specifying the probability of the optional dropout layer in the final module DNN

The full list of all parameters can be seen in the paragraph below. Please consult the excellent TF API for the documentation of the parameters concerning the layers.

Downsampling mismatched input, mutating the parameters, module crossover and parameter distance calculation are implemented as follows for this module:

Downsampling - Downsampling not yet implemented for this module.

Mutation - Continuous parameters are mutated by drawing a random value from a normal distribution with the parent parameter value as the mean and the stddev set via the configuration. Categorical parameters supplied via a list of preselected values are mutated by choosing a new value randomly.

Crossover - Modules are crossed over by averaging out their continuous parameters and choosing the value of the fitter module for categorical parameters.

Parameter Distance - First determining the congruence between 2 module parameter sets and then subtract the actual congruence from the perfect congruence of 1.0. The congruence of continuous parameters is calculated by their relative distance. The congruence of categorical parameters is either 1.0 in case they are the same or it’s 1 divided by the amount of possible values for that specific parameter.

[MODULE_DENSEDROPOUT] Config Parameters

[MODULE_DENSEDROPOUT]
merge_method = ...
units        = ...
activation   = ...
kernel_init  = ...
bias_init    = ...
dropout_flag = ...
dropout_rate = ...

All layer parameters can be configured in 3 different ways:

If the layer parameter should have a fixed value, specify that fixed value in the configuration.

If the layer parameter is continuous and the optimal value is to be determined by evolution, specify the minimum (min) and maximum (max) value of the layer parameter as well as the possible step (step) between different values in a python dict style. Also specify the standard deviation (stddev) that should be applied when mutating the parameter and a new value is chosen for the parameter from a normal distribution.

If the layer parameter is discrete or should only be chosen from a preselected list and the optimal value is to be determined by evolution, specify all possible values of the parameter in a python list style.


Conv2D-MaxPool2D-Dropout Module

The deep neural network represented by this module consists of a guaranteed Conv2D layer, followed by an optional MaxPooling2D layer, followed by an optional Dropout layer. This module has 12 parameters that can be set by the configuration. Of these 12 parameters, 9 are providing parameters for the encoded deep neural network layer and 3 parameters are relevant for the TFNE CoDeepNEAT evolution. Explicitly:

  • merge_method - list of TF deserializable strings specifying a valid merge layer

  • max_pool_flag - float [0; 1.0] specifying the probability of the optional Max Pooling layer in the final module DNN

  • dropout_flag - float [0; 1.0] specifying the probability of the optional dropout layer in the final module DNN

The full list of all parameters can be seen in the paragraph below. Please consult the excellent TF API for the documentation of the parameters concerning the layers.

Downsampling mismatched input, mutating the parameters, module crossover and parameter distance calculation are implemented as follows for this module:

Downsampling - Mismatched input is downsampled by inserting an additional Conv2D layer between the mismatched input and the module DNN. This Conv2D layer converts the input to the largest possible input shape to preserve as much information as possible.

Mutation - Continuous parameters are mutated by drawing a random value from a normal distribution with the parent parameter value as the mean and the stddev set via the configuration. Categorical parameters supplied via a list of preselected values are mutated by choosing a new value randomly.

Crossover - Modules are crossed over by averaging out their continuous parameters and choosing the value of the fitter module for categorical parameters.

Parameter Distance - First determining the congruence between 2 module parameter sets and then subtract the actual congruence from the perfect congruence of 1.0. The congruence of continuous parameters is calculated by their relative distance. The congruence of categorical parameters is either 1.0 in case they are the same or it’s 1 divided by the amount of possible values for that specific parameter.

[MODULE_CONV2DMAXPOOL2DDROPOUT] Config Parameters

[MODULE_CONV2DMAXPOOL2DDROPOUT]
merge_method  = ...
filters       = ...
kernel_size   = ...
strides       = ...
padding       = ...
activation    = ...
kernel_init   = ...
bias_init     = ...
max_pool_flag = ...
max_pool_size = ...
dropout_flag  = ...
dropout_rate  = ...

All layer parameters can be configured in 3 different ways:

If the layer parameter should have a fixed value, specify that fixed value in the configuration.

If the layer parameter is continuous and the optimal value is to be determined by evolution, specify the minimum (min) and maximum (max) value of the layer parameter as well as the possible step (step) between different values in a python dict style. Also specify the standard deviation (stddev) that should be applied when mutating the parameter and a new value is chosen for the parameter from a normal distribution.

If the layer parameter is discrete or should only be chosen from a preselected list and the optimal value is to be determined by evolution, specify all possible values of the parameter in a python list style.


Defining Your Own Modules

Defining your own TFNE CoDeepNEAT modules is simple as all required functionality is dictated by the abstract module interface seen below. The required functionality and output of each method is documented in its respective docstrings. This abstract module interface can be included by inheriting from tfne.encodings.codeepneat.modules.CoDeepNEATModuleBase.

To make the newly created TFNE compatible module usable by TFNE you have to include an association between the module string name and the module class implementation in the file tfne/encodings/codeepneat/modules/codeepneat_module_association.py. We are working on making this process simpler in a future release.

CoDeepNEAT Abstract Module Interface

class CoDeepNEATModuleBase(object, metaclass=ABCMeta):
    """
    Base class and interface for TFNE CoDeepNEAT compatible modules, ensuring that modules provide layer creation,
    downsampling, mutation and crossover functionality. This base class also provides common functionality required
    by all modules like parameter saving and simple setter/getter methods.
    """

    def __init__(self, config_params, module_id, parent_mutation, dtype):
        """
        Base class of all TFNE CoDeepNEAT modules, saving common parameters.
        @param config_params: dict of the module parameter range supplied via config
        @param module_id: int of unique module ID
        @param parent_mutation: dict summarizing the mutation of the parent module
        @param dtype: string of deserializable TF dtype
        """
        self.config_params = config_params
            self.module_id = module_id
        self.parent_mutation = parent_mutation
        self.dtype = dtype
        self.fitness = 0

    @abstractmethod
    def __str__(self) -> str:
        """
        @return: string representation of the module
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement '__str__()'")

    @abstractmethod
    def create_module_layers(self) -> (tf.keras.layers.Layer, ...):
        """
        Instantiate all TF layers represented by the module and return as iterable tuple
        @return: iterable tuple of instantiated TF layers
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement 'create_module_layers()'")

    @abstractmethod
    def create_downsampling_layer(self, in_shape, out_shape) -> tf.keras.layers.Layer:
        """
        Create layer associated with this module that downsamples the non compatible input shape to the input shape of
        the current module, which is the output shape of the downsampling layer.
        @param in_shape: int tuple of incompatible input shape
        @param out_shape: int tuple of the intended output shape of the downsampling layer
        @return: instantiated TF keras layer that can downsample incompatible input shape to a compatible input shape
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement 'create_downsampling_layer()'")

    @abstractmethod
    def create_mutation(self,
                        offspring_id,
                        max_degree_of_mutation) -> CoDeepNEATModuleBase:
        """
        Create a mutated module and return it
        @param offspring_id: int of unique module ID of the offspring
        @param max_degree_of_mutation: float between 0 and 1 specifying the maximum degree of mutation
        @return: instantiated TFNE CoDeepNEAT module with mutated parameters
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement 'create_mutation()'")

    @abstractmethod
    def create_crossover(self,
                         offspring_id,
                         less_fit_module,
                         max_degree_of_mutation) -> CoDeepNEATModuleBase:
        """
        Create a crossed over module and return it
        @param offspring_id: int of unique module ID of the offspring
        @param less_fit_module: second module of same type with less fitness
        @param max_degree_of_mutation: float between 0 and 1 specifying the maximum degree of mutation
        @return: instantiated TFNE CoDeepNEAT module with crossed over parameters
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement 'create_crossover()'")

    @abstractmethod
    def serialize(self) -> dict:
        """
        @return: serialized constructor variables of the module as json compatible dict
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement 'serialize()'")

    @abstractmethod
    def get_distance(self, other_module) -> float:
        """
        Calculate the distance between 2 TFNE CoDeepNEAT modules with high values indicating difference, low values
        indicating similarity
        @param other_module: second TFNE CoDeepNEAT module to which the distance has to be calculated
        @return: float between 0 and 1. High values indicating difference, low values indicating similarity
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement 'get_distance()'")

    @abstractmethod
    def get_module_type(self) -> str:
        """
        @return: string representation of module type as used in CoDeepNEAT config
        """
        raise NotImplementedError("Subclass of CoDeepNEATModuleBase does not implement 'get_module_name()'")

    def set_fitness(self, fitness):
        self.fitness = fitness

    def get_id(self) -> int:
        return self.module_id

    def get_fitness(self) -> float:
        return self.fitness

    def get_merge_method(self) -> dict:
        return self.merge_method

XOR Environment

Overview

The XOR problem is a classic problem in ML research and particularly relevant for research in Neuroevolution, as it is a very simple problem that nonetheless can only be solved if an applied ANN features hidden nodes. The XOR problem measures an ANNs ability to reproduce the XOR function, which takes 2 binary inputs and produces 1 binary output according to the following truth table:

A_in

B_in

out

0

0

0

0

1

1

1

0

1

1

1

0

This function can not be replicated by a minimal topology graph when attempting to learn the associations purely by training the associated weights and biases. It therefore requires an additional hidden node in the topology graph and is therefore particularly interesting for the research of neuroevolution algorithms and their ability to generate novel and beneficial topological structures. See the figure below for the most efficient topological mutation when starting from a minimal topology.

_images/xor_evolution_illustration.svg

Beneficial Topological Mutation from minimal topology for the XOR problem


Specifications

Supports Weight-Training Eval

True

Supports Non-Weight-Training Eval

True

Input Shape

(2,)

required Output Shape

(1,)

The fitness is calculated as the inverse cross-entropy loss between the actual and the predicted outputs, multiplied by 100 to get the degree of accuracy in percent.


[EVALUATION] Config Parameters

Weight-Training Evaluation

epochs

Value Range: int > 0

Description: Specifies the amount of epochs a genome phenotype is to be trained on the environment before evaluating its fitness.

batch_size

Value Range: int > 0 | None

Description: Supplied batch_size value for the model.fit function. batch_size is the number of training examples used for a single iteration of backpropagating the gradient of the loss function.

Non-Weight-Training Evaluation

None

MNIST Environment

Overview

“The MNIST database (Modified National Institute of Standards and Technology database) is a large database of handwritten digits that is commonly used for training various image processing systems. The database is also widely used for training and testing in the field of machine learning. It was created by “re-mixing” the samples from NIST’s original datasets. The creators felt that since NIST’s training dataset was taken from American Census Bureau employees, while the testing dataset was taken from American high school students, it was not well-suited for machine learning experiments. Furthermore, the black and white images from NIST were normalized to fit into a 28x28 pixel bounding box and anti-aliased, which introduced grayscale levels.”

from Wikipedia


Specifications

Supports Weight-Training Eval

True

Supports Non-Weight-Training Eval

True

Input Shape

(28, 28, 1)

required Output Shape

(10,)

The fitness is calculated through the keras accuracy metric, calculating the percentage of how many of the test images are classified correctly.


[EVALUATION] Config Parameters

Weight-Training Evaluation

epochs

Value Range: int > 0

Description: Specifies the amount of epochs a genome phenotype is to be trained on the environment before evaluating its fitness.

batch_size

Value Range: int > 0 | None

Description: Supplied batch_size value for the model.fit function. batch_size is the number of training examples used for a single iteration of backpropagating the gradient of the loss function.

Non-Weight-Training Evaluation

None

CIFAR10 Environment

Overview

“The CIFAR-10 dataset (Canadian Institute For Advanced Research) is a collection of images that are commonly used to train machine learning and computer vision algorithms. It is one of the most widely used datasets for machine learning research. The CIFAR-10 dataset contains 60,000 32x32 color images in 10 different classes. The 10 different classes represent airplanes, cars, birds, cats, deer, dogs, frogs, horses, ships, and trucks. There are 6,000 images of each class.

Computer algorithms for recognizing objects in photos often learn by example. CIFAR-10 is a set of images that can be used to teach a computer how to recognize objects. Since the images in CIFAR-10 are low-resolution (32x32), this dataset can allow researchers to quickly try different algorithms to see what works. Various kinds of convolutional neural networks tend to be the best at recognizing the images in CIFAR-10.

CIFAR-10 is a labeled subset of the 80 million tiny images dataset. When the dataset was created, students were paid to label all of the images.”

from Wikipedia


Specifications

Supports Weight-Training Eval

True

Supports Non-Weight-Training Eval

True

Input Shape

(32, 32, 3)

required Output Shape

(10,)

The fitness is calculated through the keras accuracy metric, calculating the percentage of how many of the test images are classified correctly.


[EVALUATION] Config Parameters

Weight-Training Evaluation

epochs

Value Range: int > 0

Description: Specifies the amount of epochs a genome phenotype is to be trained on the environment before evaluating its fitness.

batch_size

Value Range: int > 0 | None

Description: Supplied batch_size value for the model.fit function. batch_size is the number of training examples used for a single iteration of backpropagating the gradient of the loss function.

Non-Weight-Training Evaluation

None