def maximize_expanding_volume_L(self, gp_params): """ Expanding volume following L ~ MaxIter Input parameters ---------- gp_params: parameter for Gaussian Process Returns ------- x: recommented point for evaluation """ if self.acq['name'] == 'random': x_max = [ np.random.uniform(x[0], x[1], size=1) for x in self.bounds ] x_max = np.asarray(x_max) x_max = x_max.T self.X_original = np.vstack((self.X_original, x_max)) # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(x_max)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) self.time_opt = np.hstack((self.time_opt, 0)) return # init a new Gaussian Process self.gp = PradaGaussianProcess(gp_params) # scale the data before updating the GP # convert it to scaleX self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Set acquisition function start_opt = time.time() y_max = self.Y.max() #self.L=self.estimate_L(self.scalebounds) # select the acquisition function self.acq_func = AcquisitionFunction(self.acq) # consider the expansion step # backup the previous bounds self.bounds_bk = self.bounds.copy() self.scalebounds_bk = self.scalebounds.copy() # the region considered is computed as follows: NewVol~OldVol*T/t # alternatively, we compute the radius NewL~Oldl*pow(T/t,1/d) new_radius = self.l_radius * np.power( self.MaxIter / len(self.Y_original), 1.0 / self.dim) # extra proportion extra_proportion = new_radius * 1.0 / self.l_radius #extra_radius=(new_radius-self.l_radius)/2 if extra_proportion < 1: extra_proportion = 1 max_bounds = self.bounds.copy() # expand half to the lower bound and half to the upper bound max_bounds[:, 0] = max_bounds[:, 0] - self.max_min_gap * ( extra_proportion - 1) * 0.5 max_bounds[:, 1] = max_bounds[:, 1] + self.max_min_gap * ( extra_proportion - 1) * 0.5 # make sure it is within the limit if not (self.b_limit_lower is None): temp_max_bounds_lower = [ np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx]) for idx in xrange(self.dim) ] max_bounds[:, 0] = temp_max_bounds_lower if not (self.b_limit_upper is None): temp_max_bounds_upper = [ np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx]) for idx in xrange(self.dim) ] max_bounds[:, 1] = temp_max_bounds_upper temp = [(max_bounds[d, :] - self.bounds_bk[d, 0]) * 1.0 / self.max_min_gap[d] for d in xrange(self.dim)] self.scalebounds = np.asarray(temp) # perform standard BO on the new bound (scaled) x_max_scale = acq_max(ac=self.acq_func.acq_kind, gp=self.gp, y_max=y_max, bounds=self.scalebounds, opt_toolbox=self.opt_toolbox) #val_acq=self.acq_func.acq_kind(x_max_scale,self.gp,y_max) #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0]) # record the optimization time finished_opt = time.time() elapse_opt = finished_opt - start_opt self.time_opt = np.hstack((self.time_opt, elapse_opt)) # Test if x_max is repeated, if it is, draw another one at random if np.any((self.X - x_max_scale).sum(axis=1) == 0): x_max_scale = np.random.uniform(self.scalebounds[:, 0], self.scalebounds[:, 1], size=self.scalebounds.shape[0]) # check if the estimated data point is in the old bound or new for cropping IsCropping = 0 if IsCropping == 1: flagOutside = 0 for d in xrange(self.dim): if x_max_scale[d] > self.scalebounds_bk[d, 1] or x_max_scale[ d] < self.scalebounds_bk[d, 0]: #outside the old bound flagOutside = 1 self.scalebounds[d, 0] = np.minimum(x_max_scale[d], self.scalebounds_bk[d, 0]) self.scalebounds[d, 1] = np.maximum(x_max_scale[d], self.scalebounds_bk[d, 1]) # now the scalebounds is no longer 0-1 if flagOutside == 0: # not outside the old bound self.scalebounds = self.scalebounds_bk self.bounds = self.bounds_bk.copy() else: # inside the old bound => recompute bound temp = [ self.scalebounds[d, :] * self.max_min_gap[d] + self.bounds_bk[d, 0] for d in xrange(self.dim) ] if self.dim > 1: self.bounds = np.reshape(temp, (self.dim, 2)) else: self.bounds = np.array(temp) else: temp = [ self.scalebounds[d, :] * self.max_min_gap[d] + self.bounds_bk[d, 0] for d in xrange(self.dim) ] if self.dim > 1: self.bounds = np.reshape(temp, (self.dim, 2)) else: self.bounds = np.array(temp) # compute X in original scale temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:, 0] self.X_original = np.vstack((self.X_original, temp_X_new_original)) # clone the self.X for updating GP self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)]) self.scalebounds = scalebounds.T # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(temp_X_new_original)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) # for plotting self.gp = PradaGaussianProcess(gp_params) ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # update volume and radius #self.vol=prod(self.max_min_gap) #self.l_radius=np.power(self.vol,1/self.dim) self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) / self.dim)
def maximize_volume_doubling(self, gp_params): """ Volume Doubling, double the volume (e.g., gamma=2) after every 3d evaluations Input parameters ---------- gp_params: parameter for Gaussian Process Returns ------- x: recommented point for evaluation """ if self.acq['name'] == 'random': x_max = [ np.random.uniform(x[0], x[1], size=1) for x in self.bounds ] x_max = np.asarray(x_max) x_max = x_max.T self.X_original = np.vstack((self.X_original, x_max)) # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(x_max)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) self.time_opt = np.hstack((self.time_opt, 0)) return # init a new Gaussian Process self.gp = PradaGaussianProcess(gp_params) # scale the data before updating the GP # convert it to scaleX self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Find unique rows of X to avoid GP from breaking # Set acquisition function start_opt = time.time() y_max = self.Y.max() # select the acquisition function self.acq_func = AcquisitionFunction(self.acq) self.scalebounds_bk = self.scalebounds.copy() self.bounds_bk = self.bounds # consider the expansion step after 3 iterations if (len(self.Y) % 3) == 0: new_radius = 2.0 * self.l_radius extra_radius = (new_radius - self.l_radius) / 2 max_bounds = self.bounds.copy() max_bounds[:, 0] = max_bounds[:, 0] - extra_radius max_bounds[:, 1] = max_bounds[:, 1] + extra_radius # make sure it is within the limit if not (self.b_limit_lower is None): temp_max_bounds_lower = [ np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx]) for idx in xrange(self.dim) ] max_bounds[:, 0] = temp_max_bounds_lower if not (self.b_limit_upper is None): temp_max_bounds_upper = [ np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx]) for idx in xrange(self.dim) ] max_bounds[:, 1] = temp_max_bounds_upper self.bounds = np.asarray(max_bounds).copy() temp = [(max_bounds[d, :] - self.bounds_bk[d, 0]) * 1.0 / self.max_min_gap[d] for d in xrange(self.dim)] self.scalebounds = np.asarray(temp) # perform standard BO on the new bound (scaled) x_max_scale = acq_max(ac=self.acq_func.acq_kind, gp=self.gp, y_max=y_max, bounds=self.scalebounds, opt_toolbox=self.opt_toolbox) #val_acq=self.acq_func.acq_kind(x_max_scale,self.gp,y_max) #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0]) # record the optimization time finished_opt = time.time() elapse_opt = finished_opt - start_opt self.time_opt = np.hstack((self.time_opt, elapse_opt)) # Test if x_max is repeated, if it is, draw another one at random if np.any((self.X - x_max_scale).sum(axis=1) == 0): x_max_scale = np.random.uniform(self.scalebounds[:, 0], self.scalebounds[:, 1], size=self.scalebounds.shape[0]) # compute X in original scale temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:, 0] self.X_original = np.vstack((self.X_original, temp_X_new_original)) # clone the self.X for updating GP self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)]) self.scalebounds = scalebounds.T # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(temp_X_new_original)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) # for plotting self.gp = PradaGaussianProcess(gp_params) ur = unique_rows(self.X) try: self.gp.fit(self.X[ur], self.Y[ur]) except: print "bug" # update volume and radius #self.vol=prod(self.max_min_gap) #self.l_radius=np.power(self.vol,1/self.dim) self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) / self.dim)
def maximize_unbounded_regularizer(self, gp_params): """ Unbounded Regularizer AISTAST 2016 Bobak Input parameters ---------- gp_params: parameter for Gaussian Process Returns ------- x: recommented point for evaluation """ if self.acq['name'] == 'random': x_max = [ np.random.uniform(x[0], x[1], size=1) for x in self.bounds ] x_max = np.asarray(x_max) x_max = x_max.T self.X_original = np.vstack((self.X_original, x_max)) # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(x_max)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) self.time_opt = np.hstack((self.time_opt, 0)) return # init a new Gaussian Process self.gp = PradaGaussianProcess(gp_params) # scale the data before updating the GP self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Find unique rows of X to avoid GP from breaking # Set acquisition function start_opt = time.time() y_max = self.Y.max() self.scalebounds_bk = self.scalebounds.copy() self.bounds_bk = self.bounds # consider the expansion step after 3 iterations if (len(self.Y) % 3) == 0: new_radius = 2.0 * self.l_radius extra_radius = (new_radius - self.l_radius) / 2 max_bounds = self.bounds.copy() max_bounds[:, 0] = max_bounds[:, 0] - extra_radius max_bounds[:, 1] = max_bounds[:, 1] + extra_radius # make sure it is within the limit if not (self.b_limit_lower is None): temp_max_bounds_lower = [ np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx]) for idx in xrange(self.dim) ] max_bounds[:, 0] = temp_max_bounds_lower if not (self.b_limit_upper is None): temp_max_bounds_upper = [ np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx]) for idx in xrange(self.dim) ] max_bounds[:, 1] = temp_max_bounds_upper self.bounds = np.asarray(max_bounds) temp = [(max_bounds[d, :] - self.bounds[d, 0]) * 1.0 / self.max_min_gap[d] for d in xrange(self.dim)] self.scalebounds = np.asarray(temp) # select the acquisition function self.acq['x_bar'] = np.mean(self.bounds) self.acq['R'] = np.power(self.l_radius, 1.0 / self.dim) self.acq_func = AcquisitionFunction(self.acq) # mean of the domain #acq['R'] x_max_scale = acq_max(ac=self.acq_func.acq_kind, gp=self.gp, y_max=y_max, bounds=self.scalebounds, opt_toolbox=self.opt_toolbox) #val_acq=self.acq_func.acq_kind(x_max_scale,self.gp,y_max) #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0]) # record the optimization time finished_opt = time.time() elapse_opt = finished_opt - start_opt self.time_opt = np.hstack((self.time_opt, elapse_opt)) # Test if x_max is repeated, if it is, draw another one at random if np.any((self.X - x_max_scale).sum(axis=1) == 0): x_max_scale = np.random.uniform(self.scalebounds[:, 0], self.scalebounds[:, 1], size=self.scalebounds.shape[0]) # check if the estimated data point is in the old bound or new flagOutside = 0 for d in xrange(self.dim): if x_max_scale[d] > self.scalebounds_bk[d, 1] or x_max_scale[ d] < self.scalebounds_bk[d, 0]: #outside the old bound flagOutside = 1 self.scalebounds[d, 0] = np.minimum(x_max_scale[d], self.scalebounds_bk[d, 0]) self.scalebounds[d, 1] = np.maximum(x_max_scale[d], self.scalebounds_bk[d, 1]) # now the scalebounds is no longer 0-1 if flagOutside == 0: # not outside the old bound self.scalebounds = self.scalebounds_bk else: # inside the old bound => recompute bound temp = [ self.scalebounds[d, :] * self.max_min_gap[d] + self.bounds_bk[d, 0] for d in xrange(self.dim) ] if self.dim > 1: self.bounds = np.reshape(temp, (self.dim, 2)) else: self.bounds = np.array(temp) # compute X in original scale temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:, 0] self.X_original = np.vstack((self.X_original, temp_X_new_original)) # clone the self.X for updating GP self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)]) self.scalebounds = scalebounds.T # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(temp_X_new_original)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) # for plotting self.gp = PradaGaussianProcess(gp_params) ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # update volume and radius #self.vol=prod(self.max_min_gap) #self.l_radius=np.power(self.vol,1/self.dim) self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) / self.dim)
def run_FBO(self, gp_params): """ Main optimization method for filtering strategy for BO. Input parameters ---------- gp_params: parameter for Gaussian Process Returns ------- x: recommented point for evaluation """ # for random approach if self.acq['name'] == 'random': x_max = [ np.random.uniform(x[0], x[1], size=1) for x in self.bounds ] x_max = np.asarray(x_max) x_max = x_max.T self.X_original = np.vstack((self.X_original, x_max)) # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(x_max)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) self.time_opt = np.hstack((self.time_opt, 0)) return # init a new Gaussian Process self.gp = PradaGaussianProcess(gp_params) # scale the data before updating the GP # convert it to scaleX self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Set acquisition function start_opt = time.time() # obtain the maximum on the observed set (for EI) y_max = self.Y.max() #self.L=self.estimate_L(self.scalebounds) # select the acquisition function self.acq_func = AcquisitionFunction(self.acq) # consider the expansion step # finding the maximum over the lower bound # mu(x)-kappa x sigma(x) mu_acq = {} mu_acq['name'] = 'lcb' mu_acq['dim'] = self.dim mu_acq['kappa'] = 2 acq_mu = AcquisitionFunction(mu_acq) # obtain the argmax(lcb), make sure the scale bound vs original bound x_lcb_max = acq_max(ac=acq_mu.acq_kind, gp=self.gp, y_max=y_max, bounds=self.scalebounds, opt_toolbox=self.opt_toolbox) # obtain the max(lcb) max_lcb = acq_mu.acq_kind(x_lcb_max, gp=self.gp, y_max=y_max) max_lcb = np.ravel(max_lcb) # finding the region outside the box, that has the ucb > max_lcb self.max_min_gap_bk = self.max_min_gap.copy() self.bounds_bk = self.bounds.copy() self.scalebounds_bk = self.scalebounds.copy() self.X_invasion = [] # the region considered is computed as follows: NewVol~OldVol*T/t # alternatively, we compute the radius NewL~Oldl*pow(T/t,1/d) new_radius = self.l_radius * np.power( self.MaxIter / len(self.Y_original), 1.0 / self.dim) # extra proportion extra_proportion = new_radius * 1.0 / self.l_radius #extra_radius=(new_radius-self.l_radius)/2 # check if extra radius is negative if extra_proportion < 1: extra_proportion = 1 max_bounds = self.bounds.copy() # expand half to the lower bound and half to the upper bound, X'_t max_bounds[:, 0] = max_bounds[:, 0] - self.max_min_gap * ( extra_proportion - 1) max_bounds[:, 1] = max_bounds[:, 1] + self.max_min_gap * ( extra_proportion - 1) #max_bounds[:,0]=max_bounds[:,0]-extra_radius #max_bounds[:,1]=max_bounds[:,1]+extra_radius # make sure the max_bounds is within the limit if not (self.b_limit_lower is None): temp_max_bounds_lower = [ np.maximum(max_bounds[idx, 0], self.b_limit_lower[idx]) for idx in xrange(self.dim) ] max_bounds[:, 0] = temp_max_bounds_lower if not (self.b_limit_upper is None): temp_max_bounds_upper = [ np.minimum(max_bounds[idx, 1], self.b_limit_upper[idx]) for idx in xrange(self.dim) ] max_bounds[:, 1] = temp_max_bounds_upper temp = [ (max_bounds[d, :] - self.bounds[d, 0]) * 1.0 / self.max_min_gap[d] for d in xrange(self.dim) ] max_bounds_scale = np.asarray(temp) # find suitable candidates in new regions # ucb(x) > max_lcb st max L(x) # new bound in scale space # we note that the scalebound will be changed inside this function self.max_volume(self.gp, max_bounds_scale, max_lcb) #print "new bounds scale" #print self.scalebounds # perform standard BO on the new bound (scaled) x_max_scale = acq_max(ac=self.acq_func.acq_kind, gp=self.gp, y_max=y_max, bounds=self.scalebounds, opt_toolbox=self.opt_toolbox) val_acq = self.acq_func.acq_kind(x_max_scale, self.gp, y_max) # record the optimization time finished_opt = time.time() elapse_opt = finished_opt - start_opt self.time_opt = np.hstack((self.time_opt, elapse_opt)) # Test if x_max is repeated, if it is, draw another one at random if np.any((self.X - x_max_scale).sum(axis=1) == 0): x_max_scale = np.random.uniform(self.scalebounds[:, 0], self.scalebounds[:, 1], size=self.scalebounds.shape[0]) # check if the estimated data point is in the old bound or new flagOutside = 0 for d in xrange(self.dim): if x_max_scale[d] > self.scalebounds_bk[d, 1] or x_max_scale[ d] < self.scalebounds_bk[d, 0]: #outside the old bound flagOutside = 1 self.scalebounds[d, 0] = np.minimum(x_max_scale[d], self.scalebounds_bk[d, 0]) self.scalebounds[d, 1] = np.maximum(x_max_scale[d], self.scalebounds_bk[d, 1]) else: self.scalebounds[d, :] = self.scalebounds_bk[d, :] # now the scalebounds is no longer 0-1 if flagOutside == 0: # not outside the old bound, use the old bound self.scalebounds = self.scalebounds_bk self.bounds = self.bounds_bk.copy() else: # outside the old bound => expand the bound as the minimum bound containing the old bound and the selected point temp = [ self.scalebounds[d, :] * self.max_min_gap[d] + self.bounds_bk[d, 0] for d in xrange(self.dim) ] if self.dim > 1: self.bounds = np.reshape(temp, (self.dim, 2)) else: self.bounds = np.array(temp) self.bounds_list = np.hstack((self.bounds_list, self.bounds)) # compute X in original scale temp_X_new_original = x_max_scale * self.max_min_gap + self.bounds_bk[:, 0] self.X_original = np.vstack((self.X_original, temp_X_new_original)) # clone the self.X for updating GP self.max_min_gap = self.bounds[:, 1] - self.bounds[:, 0] temp = np.divide((self.X_original - self.bounds[:, 0]), self.max_min_gap) self.X = np.asarray(temp) scalebounds = np.array([np.zeros(self.dim), np.ones(self.dim)]) self.scalebounds = scalebounds.T # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(temp_X_new_original)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) # for plotting self.gp = PradaGaussianProcess(gp_params) ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # update volume and radius #self.vol=prod(self.max_min_gap) #self.l_radius=np.power(self.vol,1/self.dim) self.l_radius = np.exp(1.0 * np.sum(np.log(self.max_min_gap)) / self.dim)
def maximize(self, init_points=5, n_iter=25, acq='ucb', kappa=2.576, **gp_params): """ Main optimization method. Parameters ---------- :param init_points: Number of randomly chosen points to sample the target function before fitting the gp. :param n_iter: Total number of times the process is to repeated. Note that currently this methods does not have stopping criteria (due to a number of reasons), therefore the total number of points to be sampled must be specified. :param acq: Acquisition function to be used, defaults to Expected Improvement. :param gp_params: Parameters to be passed to the Scikit-learn Gaussian Process object Returns ------- :return: Nothing """ # Reset timer #self.plog.reset_timer() # Set acquisition function self.util = UtilityFunction(kind=self.acq, kappa=kappa) # Initialize x, y and find current y_max if not self.initialized: #if self.verbose: #self.plog.print_header() self.init(init_points) y_max = self.Y.max() self.theta=gp_params['theta'] # Set parameters if any was passed #self.gp.set_params(**gp_params) self.gp=PradaMultipleGaussianProcess(**gp_params) # Find unique rows of X to avoid GP from breaking ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Finding argmax of the acquisition function. x_max = acq_max(ac=self.acq_func.acq_kind,gp=self.gp, y_max=y_max,bounds=self.bounds) #print "start acq max nlopt" #x_max,f_max = acq_max_nlopt(f=self.acq_func.acq_kind,gp=self.gp,y_max=y_max, #bounds=self.bounds) #print "end acq max nlopt" # Test if x_max is repeated, if it is, draw another one at random # If it is repeated, print a warning #pwarning = False if np.any((self.X - x_max).sum(axis=1) == 0): #print "x max uniform random" x_max = np.random.uniform(self.bounds[:, 0], self.bounds[:, 1], size=self.bounds.shape[0]) #print "start append X,Y" self.X = np.vstack((self.X, x_max.reshape((1, -1)))) #self.Y = np.append(self.Y, self.f(**dict(zip(self.keys, x_max)))) self.Y = np.append(self.Y, self.f(x_max)) #print "end append X,Y" #print 'x_max={:f}'.format(x_max[0]) #print "start fitting GP" # Updating the GP. ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) #print "end fitting GP" # Update maximum value to search for next probe point. if self.Y[-1] > y_max: y_max = self.Y[-1]
def maximize(self,gp_params,kappa=2): """ Main optimization method. Input parameters ---------- kappa: parameter for UCB acquisition only. gp_params: parameter for Gaussian Process Returns ------- x: recommented point for evaluation """ # init a new Gaussian Process self.gp=PradaGaussianProcess(gp_params) # Find unique rows of X to avoid GP from breaking ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Set acquisition function start_opt=time.time() acq=self.acq # select the acquisition function if acq=='nei': self.L=self.estimate_L(self.bounds) self.util = AcquisitionFunction(kind=self.acq, L=self.L) else: if acq=="ucb": self.acq_func = AcquisitionFunction(kind=self.acq, kappa=kappa) else: self.acq_func = AcquisitionFunction(kind=self.acq, kappa=kappa) y_max = self.Y.max() # select the optimization toolbox if self.opt=='nlopt': x_max,f_max = acq_max_nlopt(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) if self.opt=='scipy': x_max = acq_max(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) if self.opt=='direct': x_max = acq_max_direct(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) # record the optimization time finished_opt=time.time() elapse_opt=finished_opt-start_opt self.time_opt=np.hstack((self.time_opt,elapse_opt)) # Test if x_max is repeated, if it is, draw another one at random if np.any((self.X - x_max).sum(axis=1) == 0): x_max = np.random.uniform(self.scalebounds[:, 0], self.scalebounds[:, 1], size=self.scalebounds.shape[0]) # store X self.X = np.vstack((self.X, x_max.reshape((1, -1)))) # compute X in original scale temp_X_new_original=x_max*self.max_min_gap+self.bounds[:,0] self.X_original=np.vstack((self.X_original, temp_X_new_original)) # evaluate Y using original X self.Y = np.append(self.Y, self.f(temp_X_new_original))
def maximize(self,gp_params): """ Main optimization method. Input parameters ---------- gp_params: parameter for Gaussian Process Returns ------- x: recommented point for evaluation """ if self.stop_flag==1: return if self.acq['name']=='random': x_max = [np.random.uniform(x[0], x[1], size=1) for x in self.scalebounds] x_max=np.asarray(x_max) x_max=x_max.T self.X_original=np.vstack((self.X_original, x_max)) # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(x_max)) # update Y after change Y_original self.Y=(self.Y_original-np.mean(self.Y_original))/np.std(self.Y_original) self.time_opt=np.hstack((self.time_opt,0)) return # init a new Gaussian Process self.gp=PradaGaussianProcess(gp_params) if self.gp.KK_x_x_inv ==[]: # Find unique rows of X to avoid GP from breaking ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) acq=self.acq if acq['debug']==1: logmarginal=self.gp.log_marginal_lengthscale(gp_params['theta'],gp_params['noise_delta']) print(gp_params['theta']) print("log marginal before optimizing ={:.4f}".format(logmarginal)) self.logmarginal=logmarginal if logmarginal<-999999: logmarginal=self.gp.log_marginal_lengthscale(gp_params['theta'],gp_params['noise_delta']) if self.optimize_gp==1 and len(self.Y)%2*self.dim==0 and len(self.Y)>5*self.dim: print("Initial length scale={}".format(gp_params['theta'])) newtheta = self.gp.optimize_lengthscale(gp_params['theta'],gp_params['noise_delta'],self.scalebounds) gp_params['theta']=newtheta print("New length scale={}".format(gp_params['theta'])) # init a new Gaussian Process after optimizing hyper-parameter self.gp=PradaGaussianProcess(gp_params) # Find unique rows of X to avoid GP from breaking ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Modify search space based on selected method if self.expandSS=='expandBoundsDDB_MAP': self.expandBoundsDDB_MAP() if self.expandSS=='expandBoundsDDB_FB': self.expandBoundsDDB_FB() if self.expandSS=='expandBoundsFiltering': self.expandBoundsFiltering() if self.expandSS=='volumeDoubling' and len(self.Y)%3*self.dim==0: self.volumeDoubling() # Prevent bounds from breaching maximum limit for d in range(0,self.dim): if self.scalebounds[d,0]<0: print('Lower bound of {} in dimention {} exceeded minimum bound of {}. Scaling up.'.format(self.scalebounds[d,0],d,0)) self.scalebounds[d,0]=0 print('bound set to {}'.format(self.scalebounds)) if self.scalebounds[d,1]>max_bound_size: print('Upper bound of {} in dimention {} exceeded maximum bound of {}. Scaling down.'.format(self.scalebounds[d,1],d,max_bound_size)) self.scalebounds[d,1]=max_bound_size self.scalebounds[d,0]=min(self.scalebounds[d,0],self.scalebounds[d,1]-np.sqrt(3*self.gp.lengthscale)) print('bound set to {}'.format(self.scalebounds)) # Set acquisition function start_opt=time.time() y_max = self.Y.max() if acq['name'] in ['consensus','mes']: ucb_acq_func={} ucb_acq_func['name']='ucb' ucb_acq_func['kappa']=np.log(len(self.Y)) ucb_acq_func['dim']=self.dim ucb_acq_func['scalebounds']=self.scalebounds myacq=AcquisitionFunction(ucb_acq_func) xt_ucb = acq_max(ac=myacq.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) xstars=[] xstars.append(xt_ucb) ei_acq_func={} ei_acq_func['name']='ei' ei_acq_func['dim']=self.dim ei_acq_func['scalebounds']=self.scalebounds myacq=AcquisitionFunction(ei_acq_func) xt_ei = acq_max(ac=myacq.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) xstars.append(xt_ei) pes_acq_func={} pes_acq_func['name']='pes' pes_acq_func['dim']=self.dim pes_acq_func['scalebounds']=self.scalebounds myacq=AcquisitionFunction(pes_acq_func) xt_pes = acq_max(ac=myacq.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) xstars.append(xt_pes) self.xstars=xstars if acq['name']=='vrs': print("please call the maximize_vrs function") return if 'xstars' not in globals(): xstars=[] self.xstars=xstars self.acq['xstars']=xstars self.acq['WW']=False self.acq['WW_dim']=False self.acq_func = AcquisitionFunction(self.acq,self.bb_function) if acq['name']=="ei_mu": #find the maximum in the predictive mean mu_acq={} mu_acq['name']='mu' mu_acq['dim']=self.dim acq_mu=AcquisitionFunction(mu_acq) x_mu_max = acq_max(ac=acq_mu.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds,opt_toolbox=self.opt_toolbox) # set y_max = mu_max y_max=acq_mu.acq_kind(x_mu_max,gp=self.gp, y_max=y_max) x_max = acq_max(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds,opt_toolbox=self.opt_toolbox,seeds=self.xstars) if acq['name']=='consensus' and acq['debug']==1: # plot the x_max and xstars fig=plt.figure(figsize=(5, 5)) plt.scatter(xt_ucb[0],xt_ucb[1],marker='s',color='g',s=200,label='Peak') plt.scatter(xt_ei[0],xt_ei[1],marker='s',color='k',s=200,label='Peak') plt.scatter(x_max[0],x_max[1],marker='*',color='r',s=300,label='Peak') plt.xlim(0,1) plt.ylim(0,1) strFileName="acquisition_functions_debug.eps" fig.savefig(strFileName, bbox_inches='tight') if acq['name']=='vrs' and acq['debug']==1: # plot the x_max and xstars fig=plt.figure(figsize=(5, 5)) plt.scatter(xt_ucb[0],xt_ucb[1],marker='s',color='g',s=200,label='Peak') plt.scatter(xt_ei[0],xt_ei[1],marker='s',color='k',s=200,label='Peak') plt.scatter(x_max[0],x_max[1],marker='*',color='r',s=300,label='Peak') plt.xlim(0,1) plt.ylim(0,1) strFileName="vrs_acquisition_functions_debug.eps" #fig.savefig(strFileName, bbox_inches='tight') val_acq=self.acq_func.acq_kind(x_max,self.gp,y_max) #print x_max #print val_acq if self.stopping_criteria!=0 and val_acq<self.stopping_criteria: val_acq=self.acq_func.acq_kind(x_max,self.gp,y_max) self.stop_flag=1 print("Stopping Criteria is violated. Stopping Criteria is {:.15f}".format(self.stopping_criteria)) self.alpha_Xt= np.append(self.alpha_Xt,val_acq) mean,var=self.gp.predict(x_max, eval_MSE=True) var.flags['WRITEABLE']=True var[var<1e-20]=0 #self.Tau_Xt= np.append(self.Tau_Xt,val_acq/var) # record the optimization time finished_opt=time.time() elapse_opt=finished_opt-start_opt self.time_opt=np.hstack((self.time_opt,elapse_opt)) # store X self.X = np.vstack((self.X, x_max.reshape((1, -1)))) # evaluate Y using original X self.Y_original = np.append(self.Y_original, self.f(x_max)) # update Y after change Y_original self.Y=(self.Y_original-np.mean(self.Y_original))/np.std(self.Y_original) if self.gp.flagIncremental==1: self.gp.fit_incremental(x_max,self.Y[-1]) # if (self.acq['name']=='ei_regularizerH') or (self.acq['name']=='ei_regularizerQ'): # self.scalebounds[:,0]=self.scalebounds[:,0]+1 # self.scalebounds[:,1]=self.scalebounds[:,1]-1 # self.acq['scalebounds']=self.scalebounds self.experiment_num=self.experiment_num+1
def maximize(self, gp_params, kappa=2): """ Main optimization method. Input parameters ---------- kappa: parameter for UCB acquisition only. gp_params: parameter for Gaussian Process Returns ------- x: recommented point for evaluation """ if self.acq['name'] == 'random': x_max = [ np.random.uniform(x[0], x[1], size=1) for x in self.bounds ] x_max = np.asarray(x_max) x_max = x_max.T self.X_original = np.vstack((self.X_original, x_max)) # evaluate Y using original X #self.Y = np.append(self.Y, self.f(temp_X_new_original)) self.Y_original = np.append(self.Y_original, self.f(x_max)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original)) self.time_opt = np.hstack((self.time_opt, 0)) return # init a new Gaussian Process self.gp = PradaGaussianProcess(gp_params) # Find unique rows of X to avoid GP from breaking ur = unique_rows(self.X) self.gp.fit(self.X[ur], self.Y[ur]) # Set acquisition function start_opt = time.time() acq = self.acq y_max = self.Y.max() #self.L=self.estimate_L(self.scalebounds) # select the acquisition function if acq['name'] == 'nei': self.L = self.estimate_L(self.scalebounds) self.acq_func = AcquisitionFunction(kind=self.acq, L=self.L) else: self.acq_func = AcquisitionFunction(self.acq) if acq['name'] == "ei_mu": #find the maximum in the predictive mean mu_acq = {} mu_acq['name'] = 'mu' mu_acq['dim'] = self.dim acq_mu = AcquisitionFunction(mu_acq) x_mu_max = acq_max(ac=acq_mu.acq_kind, gp=self.gp, y_max=y_max, bounds=self.scalebounds, opt_toolbox=self.opt_toolbox) # set y_max = mu_max y_max = acq_mu.acq_kind(x_mu_max, gp=self.gp, y_max=y_max) x_max = acq_max(ac=self.acq_func.acq_kind, gp=self.gp, y_max=y_max, bounds=self.scalebounds, opt_toolbox=self.opt_toolbox) val_acq = self.acq_func.acq_kind(x_max, self.gp, y_max) #print "alpha[x_max]={:.5f}".format(np.ravel(val_acq)[0]) # check the value alpha(x_max)==0 #if val_acq<0.0001: #self.stop_flag=1 #return # select the optimization toolbox """ if self.opt=='nlopt': x_max,f_max = acq_max_nlopt(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) if self.opt=='scipy': if self.opt=='direct': x_max = acq_max_direct(ac=self.acq_func.acq_kind,gp=self.gp,y_max=y_max,bounds=self.scalebounds) """ # record the optimization time finished_opt = time.time() elapse_opt = finished_opt - start_opt self.time_opt = np.hstack((self.time_opt, elapse_opt)) # Test if x_max is repeated, if it is, draw another one at random if np.any((self.X - x_max).sum(axis=1) == 0): x_max = np.random.uniform(self.scalebounds[:, 0], self.scalebounds[:, 1], size=self.scalebounds.shape[0]) # store X self.X = np.vstack((self.X, x_max.reshape((1, -1)))) # compute X in original scale temp_X_new_original = x_max * self.max_min_gap + self.bounds[:, 0] self.X_original = np.vstack((self.X_original, temp_X_new_original)) # evaluate Y using original X #self.Y = np.append(self.Y, self.f(temp_X_new_original)) self.Y_original = np.append(self.Y_original, self.f(temp_X_new_original)) # update Y after change Y_original self.Y = (self.Y_original - np.mean(self.Y_original)) / ( np.max(self.Y_original) - np.min(self.Y_original))