Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update acquisition cost implementation #479

Merged
merged 6 commits into from
Apr 12, 2024
Merged

Conversation

uremes
Copy link
Contributor

@uremes uremes commented Apr 3, 2024

Summary:

This update removes additive_cost from the LCBSC acquisition function and adds an option to extend any acquisition function with an additive or multiplicative term.

Motivation: LCBSC was extended with an option to use additive_cost so that BOLFIRE could model the log-likelihood ratio but calculate acquisition scores based on the estimated log-likelihood ratio + log-prior. This modification made sense at the time since the option was not needed in other acquisition functions. However additive or multiplicative costs could also be used to take into account other information like variable simulation costs or unknown constraints. For example, when we consider robustness to failed simulations, one approach is to scale acquisition values with predicted success probabilities. For this reason, it would be nice to have the option available in all acquisition functions.

We could update all acquisition functions to accept and use additive_cost and multiplicative_cost, but I was worried that this would only clutter the acquisition functions when it's not clear know how much use this option will have. Hence this idea that would allow either additive or multiplicative cost (*) to be combined with any acquisition function without modifications in the acquisition function. Let me know what you think!

(*) renamed to adjustment since our current and planned examples (log-prior and success probabilities) are not really costs

Please make sure

  • You have read contribution guidelines
  • You have updated CHANGELOG.rst
  • You have listed the copyright holder for the work you are submitting (see next section)

If your contribution adds, removes or somehow changes the functional behavior of the package, please check that

  • You have included or updated all the relevant documentation, including docstrings
  • You have added appropriate functional and unit tests to ensure the new features behave as expected
  • You have run make lint, make docs and make test

and the proposed changes pass all unit tests (check step 6 of CONTRIBUTING.rst for details)

Copyright and Licensing

Please list the copyright holder for the work you are submitting (this will be you or your assignee, such as a university or company):

By submitting this pull request, the copyright holder is agreeing to license the submitted work under the following licenses:

@uremes uremes requested a review from hpesonen April 4, 2024 12:47
AdditiveAcquisition

"""
class AdditiveAcquisition(acquisition_class):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why put AdditiveAcquisition inside make_additive_acq? This seems backwards. Could it be e.g. AdjustedAcquisition class or sth for additive and multiplicative adjustments?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AdditiveAcquisition is inside make_additive_acq because the idea is that make_additive_acq makes a new acquisition class that inherits the base acquisition class provided as input.

if your comment was about the new acquisition class name, i can rename both AdditiveAcquisition and MultiplicativeAcquisition to AdjustedAcquisition. the current names are indeed not clear and can be misunderstood.

if the comment was about the approach in general, the reason i used dynamic inheritance is that our available acquisition classes have varied implementations for the acquire method and the adjusted acquisition class needs to use the same acquire method as the base class. but maybe there is a better way to do this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, it's an implementation that works for this case. We just have to be careful where and when it's being called. I guess it generates a new class every time it's being called? Even with the same AcquisitionBase-instances?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, new class every time. i understand that creates some overhead compared to predetermined classes, but i assumed that's fine since we don't call this method more than once per inference task.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Just have to make sure that users won't try out silly things with it :)

@@ -111,28 +111,28 @@ def minimize(fun,
return locs[ind_min], vals[ind_min]


class CostFunction:
"""Convenience class for modelling acquisition costs."""
class AdjustmentFunction:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have AdjustmentFunctionclass and then define the maker functions later on that return classes defined with the scope of the maker functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the maker functions were needed to make new acquisition classes that inherit from the base acquisition class that is given as input. the functions currently take as input the base acquisition class and an AdjustmentFunction instance, but i could also remove this convenience class and have make_additive_acq and make_multiplicative_acq take as input the callable that we want to use as additive or multiplicative term and the callable that returns its gradient. is that what you meant?

elfi/methods/bo/utils.py Outdated Show resolved Hide resolved
AdditiveAcquisition

"""
class AdditiveAcquisition(acquisition_class):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, it's an implementation that works for this case. We just have to be careful where and when it's being called. I guess it generates a new class every time it's being called? Even with the same AcquisitionBase-instances?

elfi/methods/bo/utils.py Outdated Show resolved Hide resolved
@uremes uremes merged commit a331349 into elfi-dev:dev Apr 12, 2024
4 checks passed
@uremes uremes deleted the update_acq_cost branch June 24, 2024 20:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants