pytorch / botorch

Bayesian optimization in PyTorch
https://botorch.org/
MIT License
3.09k stars 401 forks source link

What is the role of the 'raw samplers' in optimize_acqf? #366

Closed minsoo2018 closed 4 years ago

minsoo2018 commented 4 years ago

What is the role of the 'raw samplers' in optimize_acqf? To be specific, it is hard for me to understand the line 49 in https://github.com/pytorch/botorch/blob/master/botorch/optim/optimize.py. line 49 : raw_samples: The number of samples for initialization. What is the meaning of the term "initialization" in line 49? Thanks for reading.

Balandat commented 4 years ago

Since acquisition functions are generally non-convex and pretty nasty to optimize, the way we optimize them is by starting our descent from multiple (num_restarts) initial conditions (ICs).

These ICs (if not provided manually) are generated here: https://github.com/pytorch/botorch/blob/9be18227b73818accc8f6a31bd14b3a1299deca7/botorch/optim/optimize.py#L137-L150

The way we generate the ICs inside gen_batch_initial_conditions (or the KG variant) is by using a heuristic that exploits the fast batch evaluation of acquisition functions. That is, we

  1. Compute the acquisition function value alpha at raw_samples quasi-random points in the domain in batch mode
  2. Compute a weight w = exp(eta * (alpha - mean(alpha))/std(alpha)) for a temperature parameter eta
  3. Sample num_restarts points from the quasi-random points according to w to generate the ICs

By doing so we make sure to start from high-value points, but the sampling also induces some exploration. Basically by cranking up raw_samples you are getting better and better ICs (and hence optimization quality) at the expense of compute and, in particular, memory. Because we don't optimize for each raw sample, this scales much better than increasing num_restarts.

Hope this helps

minsoo2018 commented 4 years ago

Oh, now I got it. This helped me a lot. Thank you.

Leon924 commented 2 years ago

When I input non-linear constraints to optimize_acfq, then it reminds me to provide batch_initial_conditions? how should I provide this ? in default mode, it's gen_batch_initial_conditions

Balandat commented 2 years ago

non-linear input constraints are an experimental feature and as such generation of the initial conditions from which to start the L-BFGS-B local optimizations is not supported. You will need to provide batch_initial_conditions in the same form as returned by gen_batch_initial_conditions: https://github.com/pytorch/botorch/blob/7ce7c6d9d36c0eeefd9e15bdd0355d41e16f575d/botorch/optim/initializers.py#L91-L92 That is, a num_restarts x q x d-dim tensor, where the d-dim is the dimensionality of the feature / parameter space, q is the number of points considered jointly (typically q=1 for sequential candidate generation), and each element of the num_restarts dimension corresponds to one feasible restart point. Basically, you will need to ensure that batch_initial_conditions[i][j] is a feasible parameter setting for all i, j.

Leon924 commented 2 years ago

Thanks for the quick response !

problem background: All parameters are integer values. Huge design space can not be enumerate. and I am using NEXTorch with a relax-and-round approach to do.

I add 10x1x19 batch initial conditions and define some nonlinear constraints mentioned in #1285 to feed into optimize_acqf function. But the nonlinear constraints are so special, that requires divisibility between parameters. Then the callable function is not differentiable/derivative. So can gen_candidate_scipy below solve this kind( non-derivative) none linear constraints ? not like https://github.com/facebook/Ax/issues/769#issuecomment-1022889288

https://github.com/pytorch/botorch/blob/a675968d1a64849938ec935e4a619bf984a33637/botorch/optim/optimize.py#L223-L239

actually, after I feed these non-linear -constraints into gen_candidates_scipy, it ran into errors below:

Traceback (most recent call last): File "/export1/Workspace/liqiang/tool/pycharm/pycharm-community-2019.3.5/plugins/python-ce/helpers/pydev/pydevd.py", line 1434, in _exec pydev_imports.execfile(file, globals, locals) # execute the script File "/export1/Workspace/liqiang/tool/pycharm/pycharm-community-2019.3.5/plugins/python-ce/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile exec(compile(contents+"\n", file, 'exec'), glob, loc) File "/export1/Workspace/liqiang/socgen/micropt/coreOptimizer/bo/nt/nt-random.py", line 210, in X_new, X_new_real, acq_func = Exp_random.generate_next_point(n_candidates=n_candicate) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/nextorch/bo.py", line 2133, in generate_next_point k=n_candidates) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/nextorch/bo.py", line 885, in get_top_k_candidates sequential=True) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/botorch/optim/optimize.py", line 161, in optimize_acqf sequential=False, File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/botorch/optim/optimize.py", line 235, in optimize_acqf fixed_features=fixed_features, File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/botorch/generation/gen.py", line 211, in gen_candidates_scipy options={k: v for k, v in options.items() if k not in ["method", "callback"]}, File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/scipy/optimize/_minimize.py", line 632, in minimize constraints, callback=callback, options) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/scipy/optimize/slsqp.py", line 331, in _minimize_slsqp for c in cons['ineq']])) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/scipy/optimize/slsqp.py", line 331, in for c in cons['ineq']])) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/botorch/optim/parameter_constraints.py", line 359, in f_obj cache["obj"], cache["grad"] = f_obj_and_grad(X) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/botorch/optim/parameter_constraints.py", line 350, in f_obj_and_grad obj, grad = f_np_wrapper(x, f=nlc) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/botorch/generation/gen.py", line 173, in f_np_wrapper gradf = _arrayify(torch.autograd.grad(loss, X)[0].contiguous().view(-1)) File "/export1/Workspace/liqiang/tool/anaconda3/envs/socgen-nextorch/lib/python3.7/site-packages/torch/autograd/init.py", line 277, in grad allow_unused, accumulate_grad=False) # Calls into the C++ engine to run the backward pass RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn**

which happen in https://github.com/pytorch/botorch/blob/a675968d1a64849938ec935e4a619bf984a33637/botorch/generation/gen.py#L202-L215