Align samplers and fix cost gradient#661
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #661 +/- ##
===========================================
- Coverage 99.27% 99.23% -0.05%
===========================================
Files 64 66 +2
Lines 4813 4816 +3
===========================================
+ Hits 4778 4779 +1
- Misses 35 37 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Hi @NicolaCourtier, I have two functionality concerns with this PR as is, they are:
I think it's worth discussing the above before reviewing the remainder. Alternatively, if you split off the other changes I suspect we can merge those quite quickly. Thanks for the additions! :) |
martinjrobins
left a comment
There was a problem hiding this comment.
thanks @NicolaCourtier :) Its a nice congregation of the transformation features into a single interface, which I'm in favour of and it simplifies the code and makes the transformation application easy to find. I have some comments on the general structure of this, but since this is blocking other things and fixes bugs, it might be better to just fix a few immediate things (which I've commented below), and then merge it in. Can deal with more structural things in subsequent PRs.
I find the structure of the classes a bit confusing, I wouldn't use inheritance for this but simply transform the cost itself to a "transformed cost" which acts like any regular cost function. You can see how we've implemented this in PINTs here: https://github.com/pints-team/pints/blob/015b1e8ada5937693ab7415d038f5c101f2a78d4/pints/_transformation.py#L1184. So any callable can be transformed into a different space by the application of a transformation. And you only have to do it once, then anything downstream (optimisers, plotting, other stuff executing the cost function) doesn't need to know about the transformation
I'd be keen to chat further about how costs should be structured, might be easier to chat face-to-face or via teams rather than a PR review tho!
BradyPlanden
left a comment
There was a problem hiding this comment.
Hi Nicola, thanks for the additions and fixes. A few comments to discuss, otherwise looks good.
| """ | ||
|
|
||
| def __init__(self): | ||
| self.minimising = True |
There was a problem hiding this comment.
Should this stay as a private attribute with a property? I don't believe we support users modifying it.
There was a problem hiding this comment.
I have updated the attribute minimising to invert_cost so that we can cope with optimiser minimising by default and samplers maximising. This property is applied during run (to transform the candidate values and to inverse transform them back for the log and result). So I believe it can be changed between runs.
| def fun(x): | ||
| return self.cost_call(x, calculate_grad=self._needs_sensitivities) | ||
| return self.call_cost( | ||
| x, cost=self.cost, calculate_grad=self._needs_sensitivities |
There was a problem hiding this comment.
I believe you mentioned there was a reason you had to pass self.cost instead of accessing it through the class. Can you bring me up to speed on that?
There was a problem hiding this comment.
To confirm, it is only this line that necessitates the cost being passed as an input - it sounds like this is something we can resolve in future.
| upper = float(param.transformation.to_search(param.bounds[1])) | ||
|
|
||
| if np.isnan(lower) or np.isnan(upper): | ||
| if isinstance(param.transformation, LogTransformation) and lower == 0: |
There was a problem hiding this comment.
This offset is need for at the Cuckoo & RandomSearch optimisers at moment. For robustness, the bounds are shifted by the smallest increment on the machine to ensure they are finite. We can probably update this in the corresponding optimisers, but at the moment this change breaks those two. For reference, this was added in #595.
There was a problem hiding this comment.
I have opened issue #671 to remind us to carry out a rigorous review of bounds.
Co-authored-by: Brady Planden <55357039+BradyPlanden@users.noreply.github.com>
martinjrobins
left a comment
There was a problem hiding this comment.
looks great, thanks @NicolaCourtier
Description
These changes isolate the interface between the optimiser/sampler and the cost. The new interface class becomes the only place where the following actions are performed:
The cost interface is tested in tests/unit/test_cost_interface.py. By paying off some technical debt, we can reduce the load for future debugging!
This PR includes bug fixes for:
log_jacobian_detof theScaledTransformationas well as the corresponding unit tests.
Issue reference
Show fix
Review
Before you mark your PR as ready for review, please ensure that you've considered the following:
Type of change
Key checklist:
$ pre-commit run(or$ nox -s pre-commit) (see CONTRIBUTING.md for how to set this up to run automatically when committing locally, in just two lines of code)$ nox -s tests$ nox -s doctestYou can run integration tests, unit tests, and doctests together at once, using
$ nox -s quick.Further checks:
Thank you for contributing to our project! Your efforts help us to deliver great software.