Skip to content

Commit 254f327

Browse files
committed
pushing debug flags to options in order to clean things up
1 parent f270f06 commit 254f327

File tree

4 files changed

+45
-73
lines changed

4 files changed

+45
-73
lines changed

src/Drivers/hiopbbpy/BnBBoDriverEX.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ def _evaluate(self, x: np.ndarray) -> np.ndarray:
141141
'epsilon_diam' : bnbtol / 100.,
142142
'max_iter': bnbmaxiter,
143143
'max_bnbtime': bnbmaxtime,
144-
'nodes_per_batch' : 32
144+
'nodes_per_batch' : 32,
145+
'pure_BBS' : True,
146+
'sync_mode' : True,
145147
}
146148

147149
batch_size = 1

src/Drivers/hiopbbpy/BnBDriverEX.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,11 @@ def _evaluate(self, x: np.ndarray) -> np.ndarray:
139139
'epsilon_diam' : bnbtol / 100.,
140140
'max_iter': bnbmaxiter,
141141
'max_bnbtime': bnbmaxtime,
142-
'nodes_per_batch' : 32
142+
'nodes_per_batch' : 32,
143+
'pure_BBS' : False,
144+
'sync_mode' : False,
143145
}
144-
bnb = BnBAlgorithm(acqf, options=solver_options, sync_mode=True)
146+
bnb = BnBAlgorithm(acqf, options=solver_options)
145147
bnb.initialize()
146148
xstar = np.atleast_2d(bnb.optimize())
147149
ystar = acqf.evaluate(xstar)
@@ -222,10 +224,11 @@ def _evaluate(self, x: np.ndarray) -> np.ndarray:
222224
plt.fill_between(Xnode, Ylower, Yupper, color='lightblue', alpha=0.5)
223225
nonpruned_node_midpoints = np.array([node.midpoint for node in nonpruned_nodes])
224226
print("shape of nonpruned_node midpoints = ", nonpruned_node_midpoints.shape)
225-
plt.scatter(nonpruned_node_midpoints[:,0], nonpruned_node_midpoints[:,1], color='red', marker='o', s=10, label='nonpruned midpoints')
226-
plt.legend()
227-
plt.savefig('prunedregion.png')
228-
plt.close()
227+
if len(nonpruned_node_midpoints) > 0:
228+
plt.scatter(nonpruned_node_midpoints[:,0], nonpruned_node_midpoints[:,1], color='red', marker='o', s=10, label='nonpruned midpoints')
229+
plt.legend()
230+
plt.savefig('prunedregion.png')
231+
plt.close()
229232
# plot acqf upper and lower bounds on the regions defined by nodes
230233
if nx == 2 and False:
231234
acqf_upper_bounds = [node.aq_U for node in all_nodes]

src/hiopbbpy/opt/bnbalgorithm.py

Lines changed: 32 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ def sigma2_bounds(self, kL, kU, l = None, u = None):
299299

300300

301301
class BnBAlgorithm(BnBAlgorithmBase):
302-
def __init__(self, acqf, options = {}, sync_mode=False, BOit=0, saveData=False):
302+
def __init__(self, acqf, options = {}, BOit=0, saveData=False):
303303
self.acqf = acqf
304304
self.gpsurrogate = acqf.gpsurrogate
305305
super().__init__(x = self.gpsurrogate.training_x, y = self.gpsurrogate.training_y)
@@ -316,24 +316,30 @@ def __init__(self, acqf, options = {}, sync_mode=False, BOit=0, saveData=False):
316316
self.max_bnbtime = 12 * 60 # 12 minutes
317317
self.BOit = BOit
318318
self.saveData = saveData
319+
self.acqf_UB_opt = False
320+
self.pure_BBS = False # pure BBS search or hybrid BBS/BFS search
321+
self.sync_mode = False # synchronous or asynchronous evaluations
319322
# Set options form command
320323
self.epsilon_gap = options.get('epsilon_gap', self.epsilon_gap)
321324
self.epsilon_diam = options.get('epsilon_diam', self.epsilon_diam)
322325
self.epsilon_prune = options.get('epsilon_prune', self.epsilon_prune)
323326
self.max_bnbiter = options.get('max_iter', self.max_bnbiter)
324327
self.max_bnbtime = options.get('max_bnbtime', self.max_bnbtime)
325328
self.nodes_per_batch = options.get('nodes_per_batch', self.nodes_per_batch)
326-
327-
self.sync_mode = sync_mode # synchronous or asynchronous
329+
self.acqf_UB_opt = options.get('acqf_ub_opt', self.acqf_UB_opt)
330+
self.pure_BBS = options.get('pure_BBS', self.pure_BBS)
331+
self.sync_mode = options.get('sync_mode', self.sync_mode)
328332

329333
if is_running_with_mpi():
330334
num_available_workers = MPI.COMM_WORLD.Get_size() - 1
331335
if num_available_workers > 1:
332336
# roughly evenly split workers for use in bbs and bfs evaluators
333-
#num_bbs_workers = num_available_workers
334-
#num_bfs_workers = 1
335-
num_bbs_workers = np.ceil(num_available_workers * 3 / 4).astype(int)
336-
num_bfs_workers = max(1, num_available_workers - num_bbs_workers)
337+
if self.pure_BBS:
338+
num_bbs_workers = num_available_workers
339+
num_bfs_workers = 1
340+
else:
341+
num_bbs_workers = np.ceil(num_available_workers * 3 / 4).astype(int)
342+
num_bfs_workers = max(1, num_available_workers - num_bbs_workers)
337343
else:
338344
# num_available_workers == 1 or num_available_workers == 0
339345
# can occur when running on one process in which root is both master and the
@@ -380,24 +386,9 @@ def compute_acqf_bounds(self, l, u):
380386
var = np.array([var_U, var_L])
381387
acqf_bounds = self.acqf.evaluate_meansig2(mu, var)
382388

383-
#opt_solver = "SLSQP"
384-
#opt_solver_options = {'maxiter' : 200}
385-
#constraints = []
386-
#box_bounds = [[l[i], u[i]] for i in range(len(l))]
387-
#acqf_callback = {'obj' : self.acqf.scalar_evaluate}
388-
#if self.acqf.has_gradient:
389-
# acqf_callback['grad'] = self.acqf.scalar_eval_g
390-
#
391-
#opt_evaluator = Evaluator()
392-
#acqf_minimizer = minimizer_wrapper(acqf_callback, opt_solver, box_bounds, constraints, opt_solver_options)
393-
394-
#x0 = [[(l[i] + u[i]) / 2. for i in range(len(u))]]
395-
#opt_sol = opt_evaluator.run(acqf_minimizer.minimizer_callback, x0)[0]
396-
#assert (np.all(opt_sol[0] >= l) and np.all(opt_sol[0] <= u)), f"acqf minimizer not within bounds"
397-
#acqf_U = opt_sol[1]
398-
if False:
399-
opt_solver = "SLSQP"
400-
opt_solver_options = {'maxiter' : 1000}
389+
if self.acqf_UB_opt:
390+
opt_solver = "IPOPT"
391+
opt_solver_options = {'max_iter' : 1000, 'tol' : 1.e-5, 'honor_original_bounds' : 'yes', 'print_level' : 2}
401392
constraints = []
402393
box_bounds = [[l[i], u[i]] for i in range(len(l))]
403394
acqf_callback = {'obj' : self.acqf.scalar_evaluate}
@@ -419,35 +410,9 @@ def compute_acqf_bounds(self, l, u):
419410
for i in range(n_points):
420411
for j in range(self.gpsurrogate.ndim):
421412
x_points[i, j] = l[j] + (u[j] - l[j]) / (s_per_dim - 1.) * float(int(i / s_per_dim**j) % s_per_dim)
422-
#n_points = 10
423-
#sampler = qmc.LatinHypercube(len(u))
424-
#x_points = sampler.random(n=n_points)
425-
#qmc.scale(x_points, l, u)
426413
acqf_eval = self.acqf.evaluate(x_points)
427414
acqf_U = min(acqf_eval.flatten())
428-
429-
430-
#n_points = 1
431-
#x_points = np.zeros((n_points, self.gpsurrogate.ndim))
432-
#for i in range(n_points):
433-
# for j in range(self.gpsurrogate.ndim):
434-
# x_points[i, j] = (l[j] + u[j]) / 2.
435-
#acqf_eval = self.acqf.evaluate(x_points)
436-
#acqf_U = min(acqf_eval.flatten())
437-
#if acqf_U < acqf_bounds[0]:
438-
# print("ERROR in bound computations U < L")
439-
# print(f"Acquisition function evaluations for node defined by bounds: {l} {u}")
440-
# for i in range(n_points):
441-
# print(f"acqf({x_points[i,:]}) = {acqf_eval[i]}")
442-
# if np.any(acqf_eval >= acqf_bounds[0]):
443-
# print("one point evaluation >= L")
444-
# #feasible_idxs = np.argwhere(acqf_eval >= acqf_bounds[0])
445-
# #acqf_eval = acqf_eval[feasible_idxs]
446-
# #acqf_eval.sort()
447-
# #acqf_U = min(acqf_eval)
448-
# else:
449-
# print("all point evaluations < L")
450-
assert acqf_bounds[0] <= acqf_U, "acqf_U < acqf_L"
415+
assert acqf_bounds[0] <= acqf_U, "acqf_L > acqf_U"
451416

452417
return acqf_bounds[0], acqf_U
453418
def _prune_queue(self, queue, lub, eps):
@@ -581,9 +546,6 @@ def bnboptimize(self, l_init, u_init):
581546

582547
# pre-prune
583548
children_lower_bounds = [child.aq_L for child in children]
584-
#args = np.argwhere(np.array(children_lower_bounds) < self.LUB + self.epsilon_prune).flatten()
585-
#children = [children[arg] for arg in args]
586-
#print(f"{len(children)} children to be appended to bbs/bfs lists")
587549

588550
# now move pruned children to data structs for (potential) future evaluation
589551
children_lower_bounds = [child.aq_L for child in children]
@@ -597,10 +559,10 @@ def bnboptimize(self, l_init, u_init):
597559

598560
# sort children into bbs and bfs lists
599561
for child in children:
600-
if True:#len(self.queue) < 10 * self.num_bbs_workers:
562+
if self.pure_BBS or len(self.queue) < 10 * self.num_bbs_workers:
601563
heapq.heappush(self.queue, (child.aq_L, next(self._ctr), child))
602564
else:
603-
all_bfsnodes.append(child) # TODO: prepend... according to number of workers
565+
all_bfsnodes.append(child) #TODO: prepend... according to number of workers
604566
max_bbs_node_size = max(max_bbs_node_size, len(self.queue))
605567
max_bfs_node_size = max(max_bfs_node_size, len(all_bfsnodes))
606568

@@ -658,8 +620,10 @@ def bnboptimize(self, l_init, u_init):
658620
#if self.bbsevaluator.num_submitted_tasks() + self.bfsevaluator.num_submitted_tasks() > 10 * (self.num_bbs_workers + self.num_bfs_workers):
659621
# collect nodes to be branched on in list structure
660622
# only submit additional tasks if there aren't too many in the Evaluators queue
661-
#num_bbs_tasks_to_submit = 10 * self.num_bbs_workers - self.bbsevaluator.num_submitted_tasks()
662-
num_bbs_tasks_to_submit = len(self.queue)
623+
if self.sync_mode:
624+
num_bbs_tasks_to_submit = len(self.queue)
625+
else:
626+
num_bbs_tasks_to_submit = 10 * self.num_bbs_workers - self.bbsevaluator.num_submitted_tasks()
663627
if num_bbs_tasks_to_submit > 0:
664628
bbsnodes = []
665629
for i in range(num_bbs_tasks_to_submit):
@@ -675,8 +639,10 @@ def bnboptimize(self, l_init, u_init):
675639
self.bbsevaluator.submit_tasks(brancher.callback, bbsnodes)
676640

677641
# only submit additional tasks if there aren't too many in the Evaluators queue
678-
num_bfs_tasks_to_submit = 10 * self.num_bfs_workers - self.bfsevaluator.num_submitted_tasks()
679-
#num_bfs_tasks_to_submit = len(all_bfsnodes)
642+
if self.sync_mode:
643+
num_bfs_tasks_to_submit = len(all_bfsnodes)
644+
else:
645+
num_bfs_tasks_to_submit = 10 * self.num_bfs_workers - self.bfsevaluator.num_submitted_tasks()
680646
if num_bfs_tasks_to_submit > 0:
681647
bfsnodes = []
682648
for i in range(num_bfs_tasks_to_submit):
@@ -754,13 +720,14 @@ def bnboptimize(self, l_init, u_init):
754720

755721

756722
class branching_wrapper:
757-
def __init__(self, acqf, LUB=np.inf, epsilon_prune=1.e-14):
723+
def __init__(self, acqf, LUB=np.inf, epsilon_prune=1.e-14, acqf_UB_opt=False):
758724
self.LUB = LUB # least upper bound
759725
self.epsilon_prune = epsilon_prune
760726
self.acqf = acqf
761727
self.gpsurrogate = acqf.gpsurrogate
762728
self.x = self.gpsurrogate.training_x
763729
self.y = self.gpsurrogate.training_y
730+
self.acqf_UB_opt = acqf_UB_opt
764731
if not (isinstance(self.acqf, LCBacquisition) or isinstance(self.acqf, EIacquisition)):
765732
raise NotImplementedError("Unrecognized acquisition function type")
766733
self.sync_from_smt()
@@ -952,9 +919,9 @@ def compute_acqf_bounds(self, l, u):
952919
var = np.array([var_U, var_L])
953920
acqf_bounds = self.acqf.evaluate_meansig2(mu, var)
954921

955-
if False:
956-
opt_solver = "SLSQP"
957-
opt_solver_options = {'maxiter' : 1000}
922+
if self.acqf_UB_opt:
923+
opt_solver = "IPOPT"
924+
opt_solver_options = {'max_iter' : 1000, 'tol' : 1.e-5, 'honor_original_bounds' : 'yes', 'print_level' : 2}
958925
constraints = []
959926
box_bounds = [[l[i], u[i]] for i in range(len(l))]
960927
acqf_callback = {'obj' : self.acqf.scalar_evaluate}

src/hiopbbpy/opt/boalgorithm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def _find_best_point(self, x_train, y_train, x0 = None, BOit=0):
204204
)
205205
else:
206206
# Instantiate BnB with GP surrogate and BO callback
207-
bnb = BnBAlgorithm(acqf, options=self.solver_options, sync_mode=True, BOit=BOit, saveData=True)
207+
bnb = BnBAlgorithm(acqf, options=self.solver_options, BOit=BOit, saveData=True)
208208

209209
# Initialize BnB (perhaps use old set of boxes here)
210210
#bnb.initialize(queue=self.bnb_queue) do not use old box set

0 commit comments

Comments
 (0)