Quickstart
GEFEST Framework quick start guide
How to install
Tested on python 3.9-3.10
pip install gefest
How to run
To run examples or custom config just use run_experiments and provide absolute path to config file.
You can use it as API:
from gefest.tools.run_experiments import run_experiments
path = 'C:\\Your\\Folder\\GEFEST\\cases\\synthetic\\circle\\multi_objective.py'
run_experiments(path)
Or as CLI script:
python run_experiments.py C:\Path\To\Config\python_config.py
How to design experiment with GEFEST
- To run an experiment, you need to define several entities:
Objectives
Domain
TunerParams (if needed)
OptimizationParams
They can be defined in the experiment startup script, or placed in a separate python file and loaded using gefest.core.configs.utils.load_config function.
All of them aggreagted into single OptimizationParams object.
Let’s take a step-by-step look at how to do this.
Step 0. Import required GEFEST modules.
from gefest.core.configs.optimization_params import OptimizationParams
from gefest.core.configs.tuner_params import TunerParams
from gefest.core.geometry.datastructs.structure import Structure
from gefest.core.geometry.domain import Domain
from gefest.core.opt.objective.objective import Objective
from gefest.tools.estimators.estimator import Estimator
Step 1. Define objectives using fitness function and simulator of the physical process if required.
Objective for finding a polygon that seems like circle showed below.
Inherit from Objective, pass domain and estimator through __init__. Define logic of objective evaluation in _evaluate method, which returns float value. If you want to solve multiobjective optimisation task, just define more objectives classes below.
import numpy as np
class AreaLengthRatio(Objective):
"""Area length ratio metric."""
def __init__(self, domain: Domain, estimator: Estimator = None) -> None:
super().__init__(domain, estimator)
def _evaluate(self, ind: Structure) -> float:
num = 3
num_polys = len(ind.polygons)
loss = 0
for poly in ind.polygons:
area = self.domain.geometry.get_square(poly)
length = self.domain.geometry.get_length(poly)
if area == 0:
ratio = None
else:
ratio = 1 - 4 * np.pi * area / length ** 2
loss += ratio
loss = loss + 20 * abs(num_polys - num)
return loss
Step 2. Define task domain.
Domain describes geometric constraints for individuals.
domain_cfg = Domain(
allowed_area=[
[0, 0],
[0, 300],
[300, 300],
[300, 0],
[0, 0],
],
min_poly_num=1,
max_poly_num=4,
min_points_num=3,
max_points_num=15,
polygon_side=0.0001,
min_dist_from_boundary=0.0001,
geometry_is_convex=True,
geometry_is_closed=True,
)
Step 3 Create sampler to generate population in specified domain.
By default, the standard sampler is used. You can select another sampler or define custom for spicific task. How to define your own sampler described in the tutorials section of the documentation.
Step 4. Define tuner configuraton.
You can tune coordinates of optimized structures points to achieve better objective metric using GOLEM tuners. To use this feature define TunerParams configuration.
tuner_cfg = TunerParams(
tuner_type='optuna',
n_steps_tune=10,
hyperopt_dist='uniform',
verbose=True,
timeout_minutes=60,
)
Step 5. Define OptimisationParams config.
To know more about configuration options see Configuration section of API reference.
opt_params = OptimizationParams(
optimizer='gefest_ga',
domain=domain_cfg,
tuner_cfg=tuner_cfg,
n_steps=50,
pop_size=50,
postprocess_attempts=3,
mutation_prob=0.6,
crossover_prob=0.6,
mutations=[
'rotate_poly',
'resize_poly',
'add_point',
'drop_point',
'add_poly',
'drop_poly',
'pos_change_point',
],
selector='tournament_selection',
mutation_each_prob=[0.125, 0.125, 0.15, 0.35, 0.00, 0.00, 0.25],
crossovers=[
'polygon_level',
'structure_level',
],
crossover_each_prob=[0.0, 1.0],
postprocess_rules=[
'not_out_of_bounds',
'valid_polygon_geom',
'not_self_intersects',
'not_too_close_polygons',
'not_too_close_points',
],
extra=5,
n_jobs=-1,
log_dir='logs',
run_name='run_name',
golem_keep_histoy=False,
golem_genetic_scheme_type='steady_state',
golem_surrogate_each_n_gen=5,
objectives=[
AreaLengthRatio(domain_cfg),
],
)
Step 5. Run generative design and results visualisation.
Now you can run the optimization as it was described above in How to run section of this tutorial. Let’s take a look at code in run_experiments.py script.
from loguru import logger
from tqdm import tqdm
from gefest.core.configs.utils import load_config
from gefest.core.viz.struct_vizualizer import GIFMaker
from gefest.tools.tuners.tuner import GolemTuner
config_path = 'your/config/absolute/path.py'
# Load config
opt_params = load_config(
config_path
)
# Initialize and run optimizer
optimizer = opt_params.optimizer(opt_params)
optimized_pop = optimizer.optimize()
# Optimized pop visualization
logger.info('Collecting plots of optimized structures...')
# GIFMaker object creates mp4 from optimized structures plots
gm = GIFMaker(domain=opt_params.domain)
for st in tqdm(optimized_pop):
gm.create_frame(st, {'Optimized': st.fitness})
gm.make_gif('Optimized population', 500)
# Run tuning if it defined in cofiguration
if opt_params.tuner_cfg:
tuner = GolemTuner(opt_params)
tuned_individuals = tuner.tune(optimized_pop[: opt_params.tuner_cfg.tune_n_best])
# Tuned structures visualization
logger.info('Collecting plots of tuned structures...')
gm = GIFMaker(domain=opt_params.domain)
for st in tqdm(tuned_individuals):
gm.create_frame(st, {'Tuned': st.fitness})
gm.make_gif('Tuned individuals', 500)
To plot spicific structures with matplotlib.pyplot see Visualization examples.