Open SanPen opened 1 week ago
I had a look at it and don't believe that it is an parallelization issue in the problem definition. Check out the following code where I am implementing a custom parallelization of the objective function directly in the problem.
import numpy as np
from multiprocessing.pool import ThreadPool
from pymoo.core.problem import StarmapParallelization, Problem
from pymoo.optimize import minimize
from pymoo.algorithms.soo.nonconvex.ga import GA
from pymoo.core.problem import ElementwiseProblem
pool = ThreadPool(8)
N_VAR = 100
POP_SIZE = 5000
N_GEN = 2
def f(x):
n = len(x)
mat = np.random.random((n, n))
b = mat @ x
return np.power(b, 2).sum()
class MyProblem(ElementwiseProblem):
def __init__(self, **kwargs):
super().__init__(n_var=N_VAR, n_obj=1, n_ieq_constr=0, xl=-5, xu=5, **kwargs)
def _evaluate(self, x, out, *args, **kwargs):
out["F"] = f(x)
class MyStarmapProblem(Problem):
def __init__(self, **kwargs):
super().__init__(n_var=N_VAR, n_obj=1, n_ieq_constr=0, xl=-5, xu=5, **kwargs)
def _evaluate(self, X, out, *args, **kwargs):
out["F"] = pool.starmap(f, [[x] for x in X])
########## REGULAR ##########
problem = MyProblem()
algorithm = GA(pop_size=POP_SIZE)
res = minimize(
problem=problem,
algorithm=algorithm,
termination=('n_gen', N_GEN),
seed=1,
verbose=True
)
print('Regular:', res.exec_time)
########## THREADS ##########
runner = StarmapParallelization(pool.starmap)
# define the problem by passing the starmap interface of the thread pool
problem = MyProblem(elementwise_runner=runner)
algorithm = GA(pop_size=POP_SIZE)
res = minimize(
problem=problem,
algorithm=algorithm,
termination=('n_gen', N_GEN),
seed=1,
verbose=True
)
print('Threads:', res.exec_time)
########## CUSTOM ##########
# define the problem by passing the starmap interface of the thread pool
problem = MyStarmapProblem()
algorithm = GA(pop_size=POP_SIZE)
res = minimize(
problem=problem,
algorithm=algorithm,
termination=('n_gen', N_GEN),
seed=1,
verbose=True
)
print('CUSTOM:', res.exec_time)
########## FIN_VARALIZE ##########
pool.close()
which results in
=================================================
n_gen | n_eval | f_avg | f_min
=================================================
1 | 5000 | 2.819835E+04 | 4.097037E+03
2 | 10000 | 8.990107E+03 | 3.782367E+03
Regular: 3.7044739723205566
=================================================
n_gen | n_eval | f_avg | f_min
=================================================
1 | 5000 | 2.816409E+04 | 4.395691E+03
2 | 10000 | 9.014509E+03 | 3.813322E+03
Threads: 3.2561869621276855
=================================================
n_gen | n_eval | f_avg | f_min
=================================================
1 | 5000 | 2.822005E+04 | 4.251145E+03
2 | 10000 | 9.025169E+03 | 3.818071E+03
CUSTOM: 3.685326099395752
This is the behavior you have referred to in your issue.
The algorithm itself however, does not parallelize on threads which will still be the overhead in your case. Because the objective function runs still quite fast.
To prove this we can use a small population with a longer wait time.
from multiprocessing.pool import ThreadPool
from time import sleep
from pymoo.algorithms.soo.nonconvex.ga import GA
from pymoo.core.problem import ElementwiseProblem
from pymoo.core.problem import StarmapParallelization
from pymoo.optimize import minimize
pool = ThreadPool(8)
N_VAR = 100
POP_SIZE = 8
N_GEN = 2
class MyProblem(ElementwiseProblem):
def __init__(self, **kwargs):
super().__init__(n_var=N_VAR, n_obj=1, n_ieq_constr=0, xl=-5, xu=5, **kwargs)
def _evaluate(self, x, out, *args, **kwargs):
sleep(1)
out["F"] = 1
########## REGULAR ##########
problem = MyProblem()
algorithm = GA(pop_size=POP_SIZE)
res = minimize(
problem=problem,
algorithm=algorithm,
termination=('n_gen', N_GEN),
seed=1,
verbose=True
)
print('Regular:', res.exec_time)
########## THREADS ##########
runner = StarmapParallelization(pool.starmap)
# define the problem by passing the starmap interface of the thread pool
problem = MyProblem(elementwise_runner=runner)
algorithm = GA(pop_size=POP_SIZE)
res = minimize(
problem=problem,
algorithm=algorithm,
termination=('n_gen', N_GEN),
seed=1,
verbose=True
)
print('Threads:', res.exec_time)
########## FIN_VARALIZE ##########
pool.close()
and this will clearly show that the problem is parallelized.
=================================================
n_gen | n_eval | f_avg | f_min
=================================================
1 | 8 | 1.0000000000 | 1.0000000000
2 | 16 | 1.0000000000 | 1.0000000000
Regular: 16.23266291618347
=================================================
n_gen | n_eval | f_avg | f_min
=================================================
1 | 8 | 1.0000000000 | 1.0000000000
2 | 16 | 1.0000000000 | 1.0000000000
Threads: 2.02089524269104
Hi!
I made this example:
When I run it, this is the processing profile:
It is clearly not running in parallel. Observe that only one processor thread is not idle.
Any idea on what to do to run a GA in parallel?