Skip to content

suggest does not work as expected in constrained optimization #481

@yichenfu

Description

@yichenfu

Hi, I recently run into issues where suggest does not work as expected in constrained optimization. Based on Gardner et. al., 2014, in constrained cases, suggest should return the argmax of acquisition*p_constrain. (Assuming acquisition function is always positive, which is satisfied below.) However, in the following case, it seems like suggest only returns the argmax of acquisition but ignores p_constrain. Below is the plot for such a case.

image

The circles are data points the algorithm currently has, and the star is the next point suggest provides. The white points satisfy the constraint, and the red points do not. The contour of the GP prediction of target, acquisition function, p_constraint, and acquisition*p_constraint is shown in the figure, where we can clearly see that the next point maximize the acquisition function but ignores the constrain.

My code to reproduce the figure is attached below. Did I do anything wrong in the constrained optimization? Thanks in advance for taking your time!

import matplotlib.pyplot as plt
import numpy as np
from bayes_opt import UtilityFunction, BayesianOptimization
from scipy.optimize import NonlinearConstraint

# Synthetic data
params = np.array([[ 0.55, 0.79],[-0.65,-1.5 ],[-1.25,-0.23],[-0.25,-1.02],[-0.01, 0.13],[-1.96,-0.65],[-1.06, 0.43],[ 0.69,-1.86],[ 0.96,-0.47],[-0.98,-1.18],[-1.69, 0.95],[ 0.07,-1.26],[-0.35, 0.57],[-1.55,-1.65],[-0.75,-0.08],[ 0.26,-0.79],[ 0.39,-0.01],[-0.85,-0.7 ],[-1.46, 0.48],[-0.41,-1.72],[ 0.2, 0.84],[-1.79,-1.36],[-0.9,-0.37],[ 0.9,-1.07],[ 0.8, 0.33],[-1.2,-1.98],[-1.9, 0.25],[-0.09,-0.56],[-0.14,-0.14],[-1.38,-0.94],[-0.58, 0.71]])
target = np.array([-1.13,-1.04,-0.02,-0.74,-0.57,-0.45,-0.94,-1.1,-0.06,-0.87,-1.15,-0.88,-1.02,-1.1,-0.15,-0.49,-0.34,-0.49,-0.96,-1.12,-1.09,-0.98,-0.11,-0.6,-0.89,-1.19,-0.73,-0.3,-0.08,-0.71,-1.08])
constraint_value = np.array([0.56,0.01,0.27,0.03,0.53,0.09,0.69,0.,0.15,0.02,0.53,0.01,0.63,0.,0.36,0.06,0.42,0.08,0.67,0.,0.35,0.01,0.19,0.02,0.66,0.,0.61,0.12,0.32,0.04,0.58])

# Defind optimizer 
pbounds = {'x':[-2,1],'y':[-2,1]}
constraint = NonlinearConstraint(None,0.5,np.inf)
optimizer = BayesianOptimization(f=None, constraint=constraint, pbounds=pbounds)
print(optimizer.is_constrained)

# register data
for i in range(len(target)):
    optimizer.register(params = params[i], target = target[i], constraint_value = constraint_value[i])

# define acquisition and suggest next point
acq = UtilityFunction(kind="ei", xi=0.)
s = optimizer.suggest(acq)

# ========== plot the figure ==========
param_bounds = np.array([[-2,1],[-2,1]])
x = np.linspace(param_bounds[0,0], param_bounds[0,1],100)
y = np.linspace(param_bounds[1,0], param_bounds[1,1],100)
xy = np.array([[x_i,y_j] for y_j in y for x_i in x])
X,Y = np.meshgrid(x,y)

fig = plt.figure(figsize=(10,8))
grid = fig.add_gridspec(ncols=2,nrows=2)

fig.subplots_adjust(wspace=0.2,hspace=0.3)

# Estimation of target
ax0 = plt.subplot(grid[0,0])
target_est = optimizer._gp.predict(xy).reshape(X.shape)
plt.contourf(X,Y,target_est,levels=20)
plt.title('Target',fontsize=20)
plt.colorbar();

# Estimation of acquisition function
ax1 = plt.subplot(grid[0,1])
acq_est = acq.utility(xy,optimizer._gp,optimizer.space.target.max()).reshape(X.shape)
plt.contourf(X,Y,acq_est,levels=20)
plt.title('Acquisition',fontsize=20)
plt.colorbar()

# Estimation of p_constraint
ax2 = plt.subplot(grid[1,0])
p_constraint_est = optimizer.constraint.predict(xy).reshape(X.shape)
plt.contourf(X,Y,p_constraint_est,levels=20)
plt.title('p_constraint',fontsize=20)
plt.colorbar();

# print acquisition * p_constraint
ax3 = plt.subplot(grid[1,1])
plt.contourf(X,Y,acq_est * p_constraint_est,levels=20)
plt.title('p_const * acq',fontsize=20)
plt.colorbar();

# show all data points
res = optimizer.res
keys = list(res[0]['params'].keys())
x_ = np.array([r["params"][keys[0]] for r in res])
y_ = np.array([r["params"][keys[1]] for r in res])
a_ = np.array([r["allowed"] for r in res])

for ax in [ax0,ax1,ax2,ax3]:
    ax.scatter(x_[a_],y_[a_],c='white',s=20,edgecolors='black')
    ax.scatter(x_[~a_],y_[~a_],c='red',s=20,edgecolors='black');
    ax.scatter(s['x'],s['y'],c='magenta',s=100,edgecolors='black',marker='*');

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions