Skip to content

Commit

Permalink
refactoring v2
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinCortacero committed Dec 9, 2024
1 parent 7ca79ea commit 7568a52
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 339 deletions.
64 changes: 15 additions & 49 deletions src/kartezio/callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,73 +97,39 @@ def _compute_metrics(self, e_content):

def on_generation_end(self, n, e_content):
fitness, time, fps = self._compute_metrics(e_content)
verbose = f"[G {n:04}] {fitness:.4f} {time:.6f}s {fps}fps"
verbose = f"[G {n:06}] {fitness:.6f} {time:.6f}s {fps}fps"
print(verbose)

def on_evolution_end(self, n, e_content):
fitness, time, fps = self._compute_metrics(e_content)
verbose = f"[G {n:04}] {fitness:.4f} {time:.6f}s {fps}fps, loop done."
verbose = f"[G {n:06}] {fitness:.6f} {time:.6f}s {fps}fps, loop done."
print(verbose)


class CallbackSave(Callback):
def __init__(self, workdir, dataset, frequency=1):
super().__init__(frequency)
self.workdir = Directory(workdir).next(eventid())
self.dataset = dataset
self.json_saver = None

def set_decoder(self, parser):
super().set_decoder(parser)
self.json_saver = JsonSaver(self.dataset, self.decoder)

def save_population(self, population, n):
filename = f"G{n}.json"
filepath = self.workdir / filename
self.json_saver.save_population(filepath, population)

def save_elite(self, elite):
filepath = self.workdir / JSON_ELITE
self.json_saver.save_individual(filepath, elite)

def _callback(self, n, e_name, e_content):
if e_name == Event.END_STEP or e_name == Event.END_LOOP:
self.save_population(e_content.get_individuals(), n)
self.save_elite(e_content.individuals[0])


class CallbackSaveFitness(Callback):
def __init__(self, filename):
super().__init__()
self.filename = filename
self.data = []

def on_generation_end(self, n, e_content):
fitness = e_content.individuals[0].fitness
self.data.append(fitness)

def on_evolution_end(self, n, e_content):
np.save(self.filename, np.array(self.data))
print(f"{self.filename} saved.")


class CallbackSaveScores(Callback):
def __init__(self, filename, dataset, fitness):
def __init__(self, filename, dataset, preprocessing, fitness):
super().__init__()
self.filename = filename
self.data = []
self.dataset = dataset
self.fitness = fitness
self.train_x = dataset.train_x
self.train_y = dataset.train_y
self.test_x = dataset.test_x
self.test_y = dataset.test_y
if preprocessing:
self.train_x = preprocessing.call(self.train_x)
self.test_x = preprocessing.call(self.test_x)

def _add_new_line(self, iteration, event_content):
genotype = event_content.individuals[0].genotype
p_train = self.decoder.decode(genotype, self.dataset.train_x)[0]
p_test = self.decoder.decode(genotype, self.dataset.test_x)[0]
p_train = self.decoder.decode(genotype, self.train_x)[0]
self.fitness.mode = "train"
f_train = self.fitness.batch(self.dataset.train_y, [p_train])
if self.dataset.test_x:
f_train = self.fitness.batch(self.train_y, [p_train])
if self.test_x:
p_test = self.decoder.decode(genotype, self.test_x)[0]
self.fitness.mode = "test"
f_test = self.fitness.batch(self.dataset.test_y, [p_test])
f_test = self.fitness.batch(self.test_y, [p_test])
self.fitness.mode = "train"
else:
f_test = np.nan
Expand Down
3 changes: 3 additions & 0 deletions src/kartezio/components/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def _read(self, filepath, shape=None):
def __from_dict__(cls, dict_infos: Dict) -> "Component":
pass

def __to_dict__(self) -> Dict:
return {"scale": self.scale, "directory": str(self.directory)}


class DatasetMeta:
@staticmethod
Expand Down
9 changes: 9 additions & 0 deletions src/kartezio/components/genotype.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ def __from_dict__(cls, dict_infos: Dict) -> "Genotype":
for key, value in dict_infos["chromosomes"].items():
genotype[key] = np.asarray(value)
return genotype

def __to_dict__(self) -> Dict:
"""
Convert the genotype to a dictionary representation.
Returns:
Dict: A dictionary containing the chromosome information.
"""
return {"chromosomes": {key: value.tolist() for key, value in self._chromosomes.items()}}

def clone(self) -> "Genotype":
"""
Expand Down
35 changes: 2 additions & 33 deletions src/kartezio/components/initializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,11 @@
from kartezio.evolution.decoder import Adapter
from kartezio.mutation.base import Mutation

"""
@register(Mutation, "all_random")
class RandomInit(Mutation):
'''
Can be used to initialize genome (genome) randomly
'''
@classmethod
def __from_dict__(cls, dict_infos: Dict) -> "Mutation":
pass
def __init__(self, adapter: Adapter):
super().__init__(adapter)
def mutate(self, genotype):
# mutate genes
for i in range(self.adapter.n_nodes):
self.mutate_function(genotype, i)
self.mutate_connections(genotype, i)
self.mutate_parameters(genotype, i)
# mutate outputs
for i in range(self.adapter.n_outputs):
self.mutate_output(genotype, i)
return genotype
def random(self):
genotype = self.adapter.new_genotype()
return self.mutate(genotype)
"""


@register(Mutation, "copy")
class CopyGenotype(Mutation):
@classmethod
def __from_dict__(cls, dict_infos: Dict) -> "Component":
def __from_dict__(cls, dict_infos: Dict) -> "CopyGenotype":
pass

def __init__(self, genotype, shape, n_functions):
Expand All @@ -59,7 +28,7 @@ class RandomInit(Mutation):
"""

@classmethod
def __from_dict__(cls, dict_infos: Dict) -> "MutationAllRandomPoly":
def __from_dict__(cls, dict_infos: Dict) -> "RandomInit":
pass

def __init__(self, adapter: Adapter):
Expand Down
3 changes: 3 additions & 0 deletions src/kartezio/components/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def __init__(self, inputs: List[KType], output: KType, n_parameters: int):
@classmethod
def __from_dict__(cls, dict_infos: Dict) -> "Primitive":
return Components.instantiate("Primitive", dict_infos["name"])

def __to_dict__(self) -> Dict:
return {"name": self.name}


class Library(Component, ABC):
Expand Down
99 changes: 36 additions & 63 deletions src/kartezio/evolution/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,6 @@
from kartezio.mutation.handler import MutationHandler


class GenericModel(ABC):
@abstractmethod
def predict(self, x: List[Any]) -> List[Any]:
"""Make a prediction based on input data."""
pass


class ModelTrainer(GenericModel):
@abstractmethod
def fit(self, x: List[Any], y: List[Any]) -> "ModelTrainer":
"""Fit the model to the provided data."""
pass


class ObservableModel(Observable):
def send_event(self, name, state):
self.notify(Event(self.get_current_iteration(), name, state))
Expand Down Expand Up @@ -101,24 +87,17 @@ def initialize(self, n_iterations):
self.clear()
for updatable in self.collect_updatables():
self.attach(updatable)
# get updatable components
# self.updatables.append(self.mutation.mutation.effect)
# if self.mutation.decay:
# self.updatables.append(self.mutation.decay)
# print(self.updatables)
# attach updatables

def preprocess(self, x):
if self.preprocessing:
return self.preprocessing.call(x)
return x

def get_current_iteration(self):
return self.evolver.current_iteration

@property
def population(self):
return self.evolver.population

@property
def elite(self):
return self.population.get_elite()

def evaluation(self, x: List[Any], y: List[Any]):
y_pred = self.decoder.decode_population(self.population, x)
Expand All @@ -140,46 +119,27 @@ def evolve(self, x: List[Any], y: List[Any]):
self.send_event(Event.Events.END_STEP, state)
self.evolver.next()
self.force_event(Event.Events.END_LOOP, state)
elite = self.population.get_elite()
return elite, state

def evaluate(self, x, y):
y_pred, t = self.predict(x)
return self.evolver.fitness.batch(y, [y_pred])

return self.elite, state

def preprocess(self, x):
if self.preprocessing:
return self.preprocessing.call(x)
return x
def predict(self, x):
return self.decoder.decode(self.population.get_elite(), x)

def print_python_class(self, class_name):
python_writer = PythonClassWriter(self.decoder)
python_writer.to_python_class(class_name, self.population.get_elite())

def display_elite(self):
elite = self.population.get_elite()
print(elite[0])
print(elite.outputs)

def summary(self):
# TODO: implement summary
pass

"""
# attach callbacks
for callback in callbacks:
callback.set_decoder(self.model.decoder)
self.model.attach(callback)
return self.model
Predict the output of the model given the input.
Apply the preprocessing if it exists.
"""
x = self.preprocess(x)
return self.decoder.decode(self.elite, x)

def evaluate(self, x, y):
y_pred, _ = self.predict(x)
return self.evolver.fitness.batch(y, [y_pred])


class KartezioTrainer(ModelTrainer, ABC):
pass


class KartezioSequentialTrainer(KartezioTrainer):
class KartezioTrainer:
def __init__(
self,
n_inputs: int,
Expand Down Expand Up @@ -218,9 +178,6 @@ def fit(
# evolve the model
return self.model.evolve(x, y)

def predict(self, x: List[Any]) -> List[Any]:
return self.model.predict(x)

@property
def decoder(self) -> DecoderCGP:
return self.model.decoder
Expand Down Expand Up @@ -263,3 +220,19 @@ def set_mutation_effect(self, effect):

def set_mutation_edges(self, edges):
self.mutation.set_edges(edges)

def evaluate(self, x, y):
return self.model.evaluate(x, y)

def print_python_class(self, class_name):
python_writer = PythonClassWriter(self.decoder)
python_writer.to_python_class(class_name, self.model.population.get_elite())

def display_elite(self):
elite = self.model.elite
print(elite[0])
print(elite.outputs)

def summary(self):
# TODO: implement summary
pass
Loading

0 comments on commit 7568a52

Please sign in to comment.