The good news: Every of Paref’s algorithms has underlying theoretical guarantees. In other words, whenever the MOO does not perform as expected, there are only two possible reasons:
a bug in the implementation of the blackbox function
the optimization did not converge to the right value
How to check if the blackbox function is implemented correctly?#
Check again if the blackbox function’s
design space dimension
target space dimension
bounds
are correct.
Next, check if the blackbox function’s __call__ method returns reasonable values by calling the
bbf.y and bbf.xattribute.
If you see any unexpected values, the blackbox function is most likely implemented incorrectly.
How to check if the optimization did succeed?#
The most common error in the optimization process results from a bad scaling of the target values.
Ensure that the target values are approximately all in the same range, ideally between 0 and 1.
Do so by subtracting and multiplying all target values by appropriate positive constants
within the __call__ methode of the blackbox function.
⚠️WARNING⚠️:
the constant with which the target values are multiplied must be strictly positive. Otherwise, the Pareto front will get changed!
do not make this functional, for example by calling a MinMaxScaler, as this would make the optimization highly unstable.
Example
Assume the first value of some 2-dimensional bbf with methoddef __call__(self, x: np.ndarray) -> np.ndarray:
... # Some code implementing the relationship between x and f(x)
return result
is known to be in the range of -100 to -1000 and the second value in the range of 0.001 to 0.002. This (rather extreme) setup would most likely cause a bad optimization. Then, the following modification would be appropriate:
def __call__(self, x: np.ndarray) -> np.ndarray:
... # Some code implementing the relationship between x and f(x)
return (result-np.array([1000,-0.001]) # Subtract the lower bounds
/np.array([900,0.001])) # Divide by the range
It is most likely that the optimization will succeed after such an adjustment.
However, sometimes this is not enough, and we need a take a closer look at the optimization process. Paref works as follows:
a GPR is trained on the evaluations
the (expensive) blackbox function is replaced by the (cheap) GPR
the concatination of the GPR with some Pareto reflection is minimized
Step 1.: check if the training did succeed
This information is provided by the Info class:
from paref.express.info import Info
info = Info(blackbox_function=bbf, training_iter=2000, learning_rate=0.05) # Create an instance of the Paref Info class
Info.model_fitness
and have a look at the plot of the training. If you recognize the plot to be ‘non-converging’
try more training iterations (e.g. training_iter=5000) and check if the training converged:
info = Info(blackbox_function=bbf, training_iter=5000, learning_rate=0.05) # Create an instance of the Paref Info class
Info.model_fitness
If you recognize the plot to be non-convex (e.g. if there are any spikes) this is
mostly likely caused by a bad scaling of the target values (see above) or a learning rate too large.
For the latter, decrease the learning rate (e.g. learning_rate=0.01) and check if the training succeeds.
You will mostly likely need to increase the number of training iterations (e.g. training_iter=5000).
You can check if those changes did succeed by calling the Info class again.
info = Info(blackbox_function=bbf, training_iter=5000, learning_rate=0.01) # Create an instance of the Paref Info class
Info.model_fitness
After determining appropriate values for the learning rate and the number of training iterations, initialize the MOO algorithm again with those values.
Step 2.: check if the GPR is a good approximation of the blackbox function
How well the GPR approximates the blackbox function is determined by two factors:the complexity of the bbf
the number of evaluations (i.e. training points)
The good news is that any GPR can approximate any bbf arbitrarily well if the number of evaluations is large enough. In other words, the optimization will succeed as long as the target space is explored sufficiently. The bad news is that there is no general rule of thumb for the number of evaluations.
However, Paref provides an indicator for the quality of the GPR by calling
from paref.express.info import Info
info = Info(blackbox_function=bbf, training_iter=2000, learning_rate=0.05) # Create an instance of the Paref Info class
Info.model_fitness
and having a look at the ‘average uncertainty’. A high uncertainty suggests a bad approximation. In such case and after ensuring all of the above steps, you will need to explore the target space further. Currently, you can only do this by
calling the
bbf.perform_lhcmethod again ormanually adding new points to the target space by calling the
bbfto some design.
We are working on additional methods for (automatically and optimally) exploring the target space. If nothing of the above worked feel free to contact me!