Conversation
|
Hi @Osburg, this looks really great. I love it. For me it would be fine to completely drop the formulaic support. It is also a really clever way of making the formulas torch executable. One question: by explicitly setting the locals, is it safe to injections? Have a look also at this discussion (meta-pytorch/botorch#1279). But nevertheless, I would definitely go for the new router. Btw, this would also make point two in this discussion here: #514 (comment) obsolete ;) Two other comments:
|
|
Hey @jduerholt, cool, thx for the feedback :)
Cheers |
|
But then, let us keep the caching stuff out of this PR, but include the fallback to |
|
Again regarding the removal of formulaic: we will need some basic parser from the user input to a string that we use for model evaluation. Implementing a parser for formulas in wilkinson notation as general as the one from formulaic is not worth the effort i guess (then we could just stick to formulaic and have less pain :D). If we stick to removing formulaic i would suggest to expect from the user to define the model term by term, i.e. they would have to write out the long expression above. The only special rule that I would implement is that a constant term "1" is added unless a term "- 1" occurs in the formula. What do you think @jduerholt? Best |
|
@Osburg: from my understanding, the main advantage of using pytorch for everything is much faster solving of the problems, or? And getting rid of formulaic is a nice thing in addition, or? Is there a possibility for having formulaic and the much faster designs? cc: @dlinzner-bcs @bertiqwerty what is your optinion? Which more complex terms needs to be implemented? Writing the full formula is fine for me, as I always have to look up this wilkinson notation ... |
|
So far formulaic had two purposes:
The idea of this PR is still to get rid of the second point. What I am not convinced of anymore is that we should also get rid of formulaic when it comes to the first point, bc this step is done only once in the beginning and allows us to not painfully implement our own formula parser covering all kinds of edge cases. Edit: So yes! There is a possibility of having both formulaic and the much faster designs! Which is to not use formulaic for point 2, but for point 1! :) |
I think keeping formulaic for the parsing is the sensible choice. So no implementation of function parsing needed from my side. |
|
Thank you @Osburg very much for this cool addition! Do you think it will help in making our tests more stable, as passing the jacobians will make the optimizers job easier -> less constraint violations? |
|
Hmm, I doubt that it will improve the designs by a lot, since I think we did not have accuracy problems before. It is just a lot faster. So the tests will run faster, but not "better". I think the reason for the instability is that sometimes we end up in a different local minimum that the global minimum, to improve stability of the tests I guess we would have to add some more near-optimal designs which are acceptable for passing the tests. I thought the constraint violation issues were fixed by not throwing an error when a constraint is slightly violated but only a warning, right? At least in the cases that I had a look at there has never been a significant constraint violation, but only idk a violation of 1e-4 instead of the tolerated 1e-6 (which is both a practically fulfilled constraint from my understanding :D) |
|
Thanks Aaron! Looks like a nice speed-up.
def _evaluate_tensor(self, D: Tensor) -> Tensor:
"""Evaluate the objective function on the design matrix as a tensor."""
var_dict = {var: D[:, i] for i, var in enumerate(self.vars)}
var_dict["torch"] = torch
X = eval(str(self.model_terms_string_expression), {}, var_dict)
return self._criterion(X)probably also induces a risk because of the
I am fine merging this variant, since security does not get worse but speed gets better. |
|
Ah, another quick thing. Off-topic, but can you @dlinzner-bcs or @bertiqwerty ask Rosona if my mails arrive her? :D Sent her an answer some time ago and I am not sure if it landed in spam or she is just busy. |
I would then also opt for keeping formulaic as parser but go for pytorch for differentiation. I think this is the best compromise, then we couple it with scipy.minimize as fallback optimizer if ipopt is not available. |
|
Hi @jduerholt, I addressed the points you mentioned in your review. Also, I dropped the access of ipopt using the scipy interface, and instead I use the |
|
Hi @Osburg, I am on a business trip, I will have a final look the latest on Wednesday, hope this fine! One question: how does removing the scipy interface relates to our idea to use a default scipy optimizer (LBFGS, SLQP) when IPOPT is not installed? Best, Johannes |
|
Sure, no hurries. In the last commit I added the fallback to |
jduerholt
left a comment
There was a problem hiding this comment.
Looks good to me. Thanks. I only let some minor comments.
We also need to update the doc that it is not necessary to have ipopt installed. But we can do this in a seperate PR.
…ome other mior changes
|
Hey @jduerholt, I think I addressed all the points you mentioned in your review in the last commit. Cheers, Aaron :) |
|
Looks good to me. Can you merge main in? The we can merge it. |
|
An error occurs in
Cheers Edit: I changed |
* Add chemistry flavour to getting started * Fix input key in doe plots * Add BayesOpt examples to examples.md * Create symbolic links for examples
* refactorings and thoughts * added structure for data-models for Optimizers * after hooks * moved optimizer-dependent data-model fields, and validators * after hooks * moved descriptor/categorical/discrete method field from botorch strategy model, to botorch optimizer data-model * after hooks * moved data-model tests * renamed appearances of num... to n... * data-model tests run * after hooks * included Optimizer mapping in mapper_actual.py * initialized optimizer in strategy __init__, using mapper function * moved methods, WIP changing input structures * WIP: moving methods to Optimizer * WIP * WIP: changing method signatures * after hooks * some dubugging * after hooks * adapted (some) tests to acq. optimizer data model call * added testfile for optimizer * added strategy mapping for benchmark fixes * debugged: missing domain,... args in function calls * after hooks * moved discrete optimization to Optimizer base class Added flag in data-model controlling exhaustive categorical search space optim * added categoric search to optimizer base-class * added test for all-categoric optimization (optimize_acqf_discrete) * after hooks * removed commented test-cases * added type-annotations * changed method "is_constraint_implemented" from classmethod to conventional method. For Bofire strategies, this matches to the same method on the optimizer * after hooks * WIP: debugging tests * WIP: debugging tests * WIP: debugging tests * WIP: debugging tests * fixed invalid test * Update bofire/data_models/strategies/predictives/acqf_optimization.py Co-authored-by: Johannes P. Dürholt <johannespeter.duerholt@evonik.com> * Update bofire/data_models/strategies/api.py Co-authored-by: Johannes P. Dürholt <johannespeter.duerholt@evonik.com> * easy fixes from PR requirements * after hooks * fix qparego.py constraint function -> reference to general strategy validation function * after hooks * made "is_constraint_implemented" an abstract method * moved Botorch-Optimizer specific validators to BotorchOptimizer data-model * after hooks * used AnyAcqfOpt... instead of abstract base class in BotorchStrategy * after hooks * moving BotorchOptimizer dependent parts of "get_fixed_features" to BotorchOptimizer class * moved Botorch-parts of "get_categorical_combinations" to BotorchBoptimizer * after hooks * debugged data-model tests * after hooks * lsrbo should be working again * fix notebook * fix notebook * fix type * update doc string on lsrbo * fix lsrbo * fix notebook * update tests * move method * implemented requested changes * after hooks --------- Co-authored-by: gdiwt <lukas.hebing@bayer.com> Co-authored-by: Lukas Hebing <92095234+LukasHebing@users.noreply.github.com>
* Remove try/except when calling `sample_q_batches_from_polytope` * Fix bug where seed is randomized if seed==0 * Strategy now uses a seed sequence instead of rng to generate seeds * Stategy.__init__ uses the Seed Sequence directly to initialise the seed * Random seed for strategy now limited to 32 bits * Bump python version in workflow * Increase fidelity threshold for MF test
…559) * add retries * check if test ever passed * add comments * reintroduce sampling for seeding does * reintroduce sampling for seeding does --------- Co-authored-by: linznedd <linznedd@basfad.basf.net>
|
@jduerholt I addressed the points you mentioned and fixed the test |
jduerholt
left a comment
There was a problem hiding this comment.
Looks good to me. Thanks!
Puuh, this is a good question. I think, there is not a good solution to this. |
This PR adds the possibility to do the model matrix evaluation also in pytorch using autograd. This has several advantages:
These changes facilitate the usage of Hessian information during optimization using
torch.autograd.functional.hessian(), since also nonlinear constraints can be defined via pytorch functions, all Hessians should by now be convenient to calculate.Tests are missing, first wanted to wait for your opinions @jduerholt, @dlinzner-bcs
Also I kept the option to do the objective evaluation the old way (but should be removed eventually)