Skip to content

Commit

Permalink
Some bug fixes; add classification example #5
Browse files Browse the repository at this point in the history
  • Loading branch information
rssalessio committed May 8, 2021
1 parent 01412d8 commit 02382e3
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 47 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# nnGA Library - Neural Network Genetic Algorithm Library (v0.2)
# nnGA Library - Neural Network Genetic Algorithm Library (v0.3)

Off the shelf Genetic Algorithm library for deep learning problems

Expand Down
115 changes: 115 additions & 0 deletions examples/example_multiclass_classification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Copyright (c) [2021] Alessio Russo [alessior@kth.se]. All rights reserved.
# This file is part of nnGA.
# nnGA is free software: you can redistribute it and/or modify
# it under the terms of the MIT License. You should have received a copy of
# the MIT License along with nnGA.
# If not, see <https://opensource.org/licenses/MIT>.
#
# Code author: [Alessio Russo - alessior@kth.se]
#

import sys
import numpy as np
import torch
sys.path.append("..")


from nnga import nnGA, GaussianInitializationStrategy, \
GaussianMutationStrategy, LayerBasedCrossoverStrategy, \
PopulationParameters

# Example Multiclass classification
# ------------
# In this example we see how to use Genetic Algorithms
# to solve a multiclass classification problem


def make_network(parameters=None):
neural_network = torch.nn.Sequential(
torch.nn.Linear(2, 64), torch.nn.ReLU(), torch.nn.Linear(64, 3))

if parameters:
state_dict = neural_network.state_dict()
for x, k in enumerate(state_dict.keys(), 0):
state_dict[k] = torch.tensor(parameters[x])
neural_network.load_state_dict(state_dict)
return neural_network


def fitness(idx, parameters, data):
trn_data, labels = data[0], data[1].flatten()

network = make_network(parameters)
with torch.no_grad():
y = network(trn_data)
loss = -torch.nn.CrossEntropyLoss()(y, labels.long()).item()
return loss


def on_evaluation(epoch, fitnesses, population, best_result, best_network,
data):
val_data, labels = data[0], data[1].flatten()
network = make_network(best_network)
with torch.no_grad():
y = network(val_data)
loss = torch.nn.CrossEntropyLoss()(y, labels.long()).item()
print('Evaluation loss: {} [Nats]'.format(loss))
return False


def make_dataset():
# Generate dataset
N_training = 100
N_validation = 50
N = N_training + N_validation

X0 = np.array([-1, 0]).T + 0.5 * np.random.normal(size=(N, 2))
X1 = np.array([1, 0]).T + 0.5 * np.random.normal(size=(N, 2))
X2 = np.array([0, 1]).T + 0.3 * np.random.normal(size=(N, 2))
X = np.concatenate([X0, X1, X2])

labels = np.zeros((3 * N, 1))
labels[N:2 * N] = 1
labels[2 * N:] = 2

# Training dataset
indices = np.random.permutation(3 * N)
trn_indices, val_indices = indices[:N_training], indices[N_training:]
Tdataset = ([
torch.tensor(X[trn_indices], dtype=torch.float32),
torch.tensor(labels[trn_indices], dtype=torch.float32)
])
Vdataset = ([
torch.tensor(X[val_indices], dtype=torch.float32),
torch.tensor(labels[val_indices], dtype=torch.float32)
])
return Tdataset, Vdataset


if __name__ == '__main__':
nn = make_network().state_dict()
network_structure = [list(v.shape) for _, v in nn.items()]
population = PopulationParameters(population_size=250)
mutation = GaussianMutationStrategy(network_structure, 1e-1)
crossover = LayerBasedCrossoverStrategy(network_structure)
init = GaussianInitializationStrategy(
mean=0., std=1., network_structure=network_structure)

trn_data, val_data = make_dataset()

def _fitness(args):
return fitness(*args, data=trn_data)

def _evaluate(*args):
return on_evaluation(*args, data=val_data)

ga = nnGA(
epochs=100,
fitness_function=_fitness,
population_parameters=population,
mutation_strategy=mutation,
initialization_strategy=init,
crossover_strategy=crossover,
callbacks={'on_evaluation': _evaluate},
num_processors=8)
ga.run()
21 changes: 9 additions & 12 deletions examples/example_rl_pytorch_cartpole.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@

import sys
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn

import gym
sys.path.append("..")

from nnga import nnGA, GaussianInitializationStrategy, \
GaussianMutationStrategy, LayerBasedCrossoverStrategy, \
PopulationParameters
Expand All @@ -24,8 +23,6 @@
# In this example we see how to use Genetic Algorithms
# to solve the cartpole environment

import gym


def make_network(parameters=None):
neural_network = torch.nn.Sequential(
Expand All @@ -39,10 +36,8 @@ def make_network(parameters=None):
return neural_network


def fitness(data: list):
idx, parameters, episodes = data
def fitness(idx, parameters, episodes):
env = gym.make('CartPole-v1')
episode_reward_list = []
network = make_network(parameters)

rewards = []
Expand Down Expand Up @@ -78,14 +73,16 @@ def on_evaluation(epoch, fitnesses, population, best_result, best_network):
init = GaussianInitializationStrategy(
mean=0., std=1., network_structure=network_structure)

def _fitness(args):
return fitness(*args, episodes=100)

ga = nnGA(
epochs=100,
fitness_function=fitness,
fitness_function_args=(100, ),
fitness_function=_fitness,
population_parameters=population,
mutation_strategy=mutation,
initialization_strategy=init,
crossover_strategy=crossover,
callbacks={'on_evaluation': on_evaluation},
num_processors=2)
ga.run()
num_processors=8)
ga.run()
27 changes: 10 additions & 17 deletions examples/example_rl_pytorch_lunarlander.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,23 @@
#

import sys
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn

import gym
sys.path.append("..")

from nnga import nnGA, GaussianInitializationStrategy, \
GaussianMutationStrategy, BasicCrossoverStrategy, \
PopulationParameters


# Example Reinforcement Learning - LunarLander
# ------------
# In this example we see how to use Genetic Algorithms
# to solve the discrete LunarLander environment

import gym


def make_network(parameters=None):
neural_network = torch.nn.Sequential(
torch.nn.Linear(8, 64),
torch.nn.ReLU(),
torch.nn.Linear(64, 4))
torch.nn.Linear(8, 64), torch.nn.ReLU(), torch.nn.Linear(64, 4))

if parameters:
state_dict = neural_network.state_dict()
Expand All @@ -42,10 +35,8 @@ def make_network(parameters=None):
return neural_network


def fitness(data: list):
idx, parameters, episodes = data
def fitness(idx, parameters, episodes):
env = gym.make('LunarLander-v2')
episode_reward_list = []
network = make_network(parameters)

avg_total_reward = 0.
Expand Down Expand Up @@ -84,14 +75,16 @@ def on_evaluation(epoch, fitnesses, population, best_result, best_network):
init = GaussianInitializationStrategy(
mean=0., std=1., network_structure=network_structure)

def _fitness(args):
return fitness(*args, episodes=10)

ga = nnGA(
epochs=50,
fitness_function=fitness,
fitness_function_args=(10, ),
fitness_function=_fitness,
population_parameters=population,
mutation_strategy=mutation,
initialization_strategy=init,
crossover_strategy=crossover,
callbacks={'on_evaluation': on_evaluation},
num_processors=2)
ga.run()
num_processors=8)
ga.run()
4 changes: 2 additions & 2 deletions nnga/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .crossover_strategy import *
from .population_parameters import *

__version__ = '0.2'
__version__ = '0.3'
__author__ = 'Alessio Russo'
__contributors__ = []
__date__ = '06.05.2021'
__date__ = '08.05.2021'
30 changes: 15 additions & 15 deletions nnga/nnga.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import logging
import time
from copy import deepcopy
from typing import Callable, Tuple, Mapping

from .crossover_strategy import CrossoverStrategy
from .initialization_strategy import InitializationStrategy
Expand All @@ -28,17 +29,18 @@


class nnGA(object):
def __init__(self,
epochs: int,
fitness_function: callable,
fitness_function_args: tuple,
population_parameters: PopulationParameters,
crossover_strategy: CrossoverStrategy,
initialization_strategy: InitializationStrategy,
mutation_strategy: MutationStrategy,
initial_population: list = None,
callbacks: dict = {},
num_processors: int = 1):
def __init__(
self,
epochs: int,
fitness_function: Callable[[int, list], float],
population_parameters: PopulationParameters,
crossover_strategy: CrossoverStrategy,
initialization_strategy: InitializationStrategy,
mutation_strategy: MutationStrategy,
initial_population: list = None,
callbacks: Mapping[
str, Callable[[int, list, list, float, list], float]] = {},
num_processors: int = 1):

self.__callbacks = [
'on_epoch_start', 'on_epoch_end', 'on_evaluation',
Expand All @@ -52,7 +54,6 @@ def __init__(self,
self.population = population_parameters

self.fitness_function = fitness_function
self.fitness_function_args = fitness_function_args
self.callbacks = callbacks

self.num_processors = num_processors
Expand Down Expand Up @@ -80,7 +81,7 @@ def _generate_initial_population(self) -> list:
break

population = population[:self.population.size]
logger.info('Loaded intial popolation.')
logger.info('Loaded intial population.')
return population

def _select_elite_population(self, population, fitnesses):
Expand Down Expand Up @@ -149,7 +150,7 @@ def _evolve_population(self, elite_population: list) -> list:
while len(offsprings) < self.population.offsprings_from_elite_group:
offsprings.append(
self.mutation_strategy.mutate(
np.random.choice(elite_population)))
elite_population[np.random.choice(len(elite_population))]))

offsprings.extend(deepcopy(elite_population))
# Add additional offsprings for the leader
Expand Down Expand Up @@ -184,7 +185,6 @@ def _evaluate_population(self, population: list) -> list:
__args = [(
idx,
x,
*self.fitness_function_args,
) for idx, x in enumerate(population, 0)]
fitnesses = list(processes.map(self.fitness_function, __args))
logger.info('Completed evaluation in {:.3f} [s].'.format(time.time() -
Expand Down

0 comments on commit 02382e3

Please sign in to comment.