Skip to content

Commit

Permalink
Merge pull request IGITUGraz#23 from Meta-optimization/experiment
Browse files Browse the repository at this point in the history
Experiment class added to simplify interface between user and simulation setup/execution.
  • Loading branch information
sdiazpier authored Sep 17, 2020
2 parents 429bba8 + 53a286e commit 24116a5
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 68 deletions.
97 changes: 29 additions & 68 deletions bin/l2l-template.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import os

from l2l.utils.environment import Environment
from l2l.utils.experiment import Experiment

from l2l.logging_tools import create_shared_logger_data, configure_loggers
from l2l.optimizees.optimizee import Optimizee
from l2l.optimizees.optimizee import Optimizee, OptimizeeParameters
from l2l.optimizers.optimizer import Optimizer, OptimizerParameters
from l2l.paths import Paths

Expand All @@ -21,80 +22,40 @@


def main():
# TODO when using the template: Give some *meaningful* name here
name = 'L2L'

# TODO when using the template: make a path.conf file and write the root path there
try:
with open('bin/path.conf') as f:
root_dir_path = f.read().strip()
except FileNotFoundError:
raise FileNotFoundError(
"You have not set the root path to store your results."
" Write the path to a path.conf text file in the bin directory"
" before running the simulation"
)
paths = Paths(name, dict(run_no='test'), root_dir_path=root_dir_path)

# Load the logging config which tells us where and what to log (loglevel, destination)

print("All output logs can be found in directory ", paths.logs_path)

# Create an environment that handles running our simulation
# This initializes an environment. This environment is based on the Pypet implementation.
# Uncomment 'freeze_input', 'multipproc', 'use_scoop' and 'wrap_mode' lines to disable running the experiment
# across cores and nodes.
env = Environment(trajectory=name, filename=paths.output_dir_path, file_title='{} data'.format(name),
comment='{} data'.format(name),
add_time=True,
freeze_input=False,
multiproc=True,
automatic_storing=True,
log_stdout=False, # Sends stdout to logs
)
create_shared_logger_data(logger_names=['bin', 'optimizers'],
log_levels=['INFO', 'INFO'],
log_to_consoles=[True, True],
sim_name=name,
log_directory=paths.logs_path)
configure_loggers()

# Get the trajectory from the environment.
traj = env.trajectory

# Set JUBE params
traj.f_add_parameter_group("JUBE_params", "Contains JUBE parameters")
# Execution command
traj.f_add_parameter_to_group("JUBE_params", "exec", "python " +
os.path.join(paths.simulation_path, "run_files/run_optimizee.py"))
# Paths
traj.f_add_parameter_to_group("JUBE_params", "paths", paths)
# TODO: use the experiment module to prepare and run later the simulation
# define a directory to store the results
experiment = Experiment(root_dir_path='~/home/user/L2L/results')
# TODO when using the template: use keywords to prepare the experiment and
# create a dictionary for jube parameters
# prepare_experiment returns the trajectory and all jube parameters
jube_params = {"nodes": "2",
"walltime": "10:00:00",
"ppn": "1",
"cpu_pp": "1"}
traj, all_jube_params = experiment.prepare_experiment(name='L2L',
log_stdout=True,
**jube_params)

## Innerloop simulator
# TODO when using the template: Change the optimizee to the appropriate Optimizee class
# TODO when using the template: Change the optimizee to the appropriate
# Optimizee class
optimizee = Optimizee(traj)

# Prepare optimizee for jube runs
jube.prepare_optimizee(optimizee, paths.simulation_path)
# TODO Create optimizee parameters
optimizee_parameters = OptimizeeParameters()

## Outerloop optimizer initialization
# TODO when using the template: Change the optimizer to the appropriate Optimizer class
# and use the right value for optimizee_fitness_weights. Length is the number of dimensions of fitness, and
# negative value implies minimization and vice versa
# TODO when using the template: Change the optimizer to the appropriate
# Optimizer class and use the right value for optimizee_fitness_weights.
# Length is the number of dimensions of fitness, and negative value
# implies minimization and vice versa
optimizer_parameters = OptimizerParameters()
optimizer = Optimizer(traj, optimizee.create_individual, (1.0,), optimizer_parameters)

# Add post processing
env.add_postprocessing(optimizer.post_process)

# Run the simulation with all parameter combinations
env.run(optimizee.simulate)

## Outerloop optimizer end
optimizer.end(traj)
optimizer = Optimizer(traj, optimizee.create_individual, (1.0,),
optimizer_parameters)

# Finally disable logging and close all log-files
env.disable_logging()
experiment.run_experiment(optimizee=optimizee,
optimizee_parameters=optimizee_parameters,
optimizer=optimizer,
optimizer_parameters=optimizer_parameters)


if __name__ == '__main__':
Expand Down
158 changes: 158 additions & 0 deletions l2l/utils/experiment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import logging.config
import os

from l2l.utils.environment import Environment

from l2l.logging_tools import create_shared_logger_data, configure_loggers
from l2l.paths import Paths
import l2l.utils.JUBE_runner as jube


class Experiment(object):
def __init__(self, root_dir_path):
"""
Prepares and starts the l2l simulation.
:param root_dir_path: str, Path to the results folder. Accepts relative
paths. Will check if the folder exists and create if not.
"""
self.root_dir_path = root_dir_path
self.logger = logging.getLogger('bin.l2l')
self.paths = None
self.env = None
self.traj = None
self.optimizee = None
self.optimizer = None

def prepare_experiment(self, **kwargs):
"""
Prepare the experiment by creating the enviroment and
:param kwargs: optional dictionary, contains
- name: str, name of the run, Default: L2L-run
- trajectory_name: str, name of the trajectory, Default: trajectory
- log_stdout: bool, if stdout should be sent to logs, Default:False
- jube_parameter: dict, User specified parameter for jube.
See notes section for default jube parameter
- multiprocessing, bool, enable multiprocessing, Default: False
:return all_jube_params, dict, a dictionary with all parameters for jube
given by the user and default ones
:return traj, trajectory object
:notes
Default JUBE parameters are:
- scheduler: Slurm,
- submit_cmd: sbatch,
- job_file: job.run,
- nodes: 1,
- walltime: 01:00:00,
- ppn: 1,
- cpu_pp: 1,
- threads_pp: 4,
- mail_mode: ALL,
- err_file: stderr,
- out_file: stdout,
- tasks_per_job: 1
"""
name = kwargs.get('name', 'L2L-run')
if not os.path.isdir(self.root_dir_path):
os.mkdir(os.path.abspath(self.root_dir_path))
print('Created a folder at {}'.format(self.root_dir_path))

trajectory_name = kwargs.get('trajectory_name', 'trajectory')

self.paths = Paths(name, dict(run_num='test'),
root_dir_path=self.root_dir_path,
suffix="-" + trajectory_name)

print("All output logs can be found in directory ",
self.paths.logs_path)

# Create an environment that handles running our simulation
# This initializes an environment
self.env = Environment(
trajectory=trajectory_name,
filename=self.paths.output_dir_path,
file_title='{} data'.format(name),
comment='{} data'.format(name),
add_time=True,
automatic_storing=True,
log_stdout=kwargs.get('log_stdout', False), # Sends stdout to logs
multiprocessing=kwargs.get('multiprocessing', False)
)

create_shared_logger_data(
logger_names=['bin', 'optimizers'],
log_levels=['INFO', 'INFO'],
log_to_consoles=[True, True],
sim_name=name,
log_directory=self.paths.logs_path)
configure_loggers()

# Get the trajectory from the environment
self.traj = self.env.trajectory

# Set JUBE params
default_jube_params = {
"scheduler": "Slurm",
"submit_cmd": "sbatch",
"job_file": "job.run",
"nodes": "1",
"walltime": "01:00:00",
"ppn": "1",
"cpu_pp": "1",
"threads_pp": "4",
"mail_mode": "ALL",
"err_file": "stderr",
"out_file": "stdout",
"tasks_per_job": "1",
"exec": "python " + os.path.join(self.paths.simulation_path,
"run_files/run_optimizee.py"),
"ready_file": os.path.join(self.paths.root_dir_path,
"ready_files/ready_w_"),
"work_path": self.paths.root_dir_path,
"paths_obj": self.paths,
}
# Will contain all jube parameters
all_jube_params = {}
self.traj.f_add_parameter_group("JUBE_params",
"Contains JUBE parameters")
# Go through the parameter dictionary and add to the trjacectory
if kwargs.get('jube_parameter'):
for k, v in kwargs['jube_parameter'].items():
self.traj.f_add_parameter_group("JUBE_params", k, v)
all_jube_params[k] = v
# Default parameter are added if they are not already set by the user
for k, v in default_jube_params.items():
if k not in kwargs.get('jube_parameter').keys():
self.traj.f_add_parameter_to_group("JUBE_params", k, v)
all_jube_params[k] = v
print('JUBE parameters used: {}'.format(all_jube_params))
return self.traj, all_jube_params

def run_experiment(self, optimizee, optimizee_parameters, optimizer,
optimizer_parameters):
"""
Runs the simulation with all parameter combinations
Optimizee and optimizer object are required as well as their parameters
as namedtuples.
:param optimizee: optimizee object
:param optimizee_parameters: Namedtuple, parameters of the optimizee
:param optimizer: optimizer object
:param optimizer_parameters: Namedtuple, parameters of the optimizer
:return traj, trajectory object
:return path, Path object
"""
self.logger.info("Optimizee parameters: %s", optimizee_parameters)
self.logger.info("Optimizer parameters: %s", optimizer_parameters)
jube.prepare_optimizee(optimizee, self.paths.simulation_path)
# Add post processing
self.env.add_postprocessing(optimizer.post_process)
# Run the simulation
self.env.run(optimizee.simulate)
# Outer-loop optimizer end
optimizer.end()
# Finally disable logging and close all log-files
self.env.disable_logging()
return self.traj, self.paths

0 comments on commit 24116a5

Please sign in to comment.