Implementation of a Parametrised Reduced Functional#241
Conversation
…educedFunctional` where parameters can be updated but are not included in the derivative calculations: 1. Adds a `parameter_update` method 2. Parameters are appended at the end of the list of optimization controls, so `derivative_components` is not a required argument. 3. The `derivative` method returns only derivative corresponding to optimization controls.
|
In the current implementation prf = ParameterisedReducedFunctional(functional, user_controls, parameters)
assert len(prf.controls) == len(user_controls) + len(parameters)This will also be a problem later because the optimisers will expect: len(prf.derivative()) == len(prf.controls)when you will actually have (correctly): len(prf.derivative()) == len(prf.user_controls)If this is the case then you may need to override the To get around this, you may have to instead inherit from the |
…e abstract base class
|
In this intermediate implementation, the However, a lot of the code is duplicated, and, as @colinjcotter suggested, a more efficient way to do this would be to call |
…dFunctional` internally: - Instead of inheriting the `AbstractReducedFunctional` or `ReducedFunctional` classes, `ParametrisedReducedFunctional` simply calls a `ReducedFunctional` object internally and passes the controls and parameters together as `all_controls`
`ParametrisedReducedFunctional` must be a subclass of `AbstractReducedFunctional` Co-authored-by: Josh Hope-Collins <jhc.jss@gmail.com>
…h component of the parameter list must first be wrapped in `Control`.
1. Basic test to check `call`, `derivative` and `parameter_update` methods 2. Combination tests with single/multiple controls and single/multiple parameters 3. Tests to check behaviour of `controls` and `parameters` property 4. Evaluation on a more complex example 5. Tests to check behaviour in case of multiple parameter updates before call.
…cedFunctional` with `derivative_components`.
| functional. Input is a list of Controls. | ||
| eval_cb_pos (function): Callback function after evaluating the | ||
| functional. Inputs are the functional value and a list of Controls. | ||
| derivative_cb_pre_for_controls (function): Callback function before evaluating |
There was a problem hiding this comment.
This is a very large number of arguments for init! Why not keep derivative_cb_pre etc and make the calling signature derivative_cb_pre(controls, parameters) instead of jut derivative_cb_pre(controls) like in ReducedFunctional?
| if parameters is None: | ||
| raise ValueError("Parameters must be provided. If no parameters are needed, use ReducedFunctional instead.") | ||
| if len(Enlist(parameters)) == 0: | ||
| raise ValueError("Parameters list cannot be empty. If no parameters are needed, use ReducedFunctional instead.") |
There was a problem hiding this comment.
Personally I would be fine with allowing zero parameters, but this is an API choice and could be something to discuss in the meeting.
| assert min(taylor_results["R0"]["Rate"]) >= 0.95, f"Error in R0 rate: {taylor_results['R0']['Rate']}" | ||
| assert min(taylor_results["R1"]["Rate"]) >= 1.95, f"Error in R1 rate: {taylor_results['R1']['Rate']}" | ||
| assert min(taylor_results["R2"]["Rate"]) >= 2.95, f"Error in R2 rate: {taylor_results['R2']['Rate']}" |
There was a problem hiding this comment.
If something failed I want to see more information.
| assert min(taylor_results["R0"]["Rate"]) >= 0.95, f"Error in R0 rate: {taylor_results['R0']['Rate']}" | |
| assert min(taylor_results["R1"]["Rate"]) >= 1.95, f"Error in R1 rate: {taylor_results['R1']['Rate']}" | |
| assert min(taylor_results["R2"]["Rate"]) >= 2.95, f"Error in R2 rate: {taylor_results['R2']['Rate']}" | |
| assert min(taylor_results["R0"]["Rate"]) >= 0.95, f"Error in R0 rate: {taylor_results['R0']}" | |
| assert min(taylor_results["R1"]["Rate"]) >= 1.95, f"Error in R1 rate: {taylor_results['R1']}" | |
| assert min(taylor_results["R2"]["Rate"]) >= 2.95, f"Error in R2 rate: {taylor_results['R2']}" |
Change `complex_expression` to `complicated_expression` in test Co-authored-by: Josh Hope-Collins <jhc.jss@gmail.com>
Correction in the description of PRF in the doctoring Co-authored-by: Josh Hope-Collins <jhc.jss@gmail.com>
Correction for typo in callback name Co-authored-by: Josh Hope-Collins <jhc.jss@gmail.com>
Co-authored-by: Josh Hope-Collins <jhc.jss@gmail.com>
Co-authored-by: Josh Hope-Collins <jhc.jss@gmail.com>
Co-authored-by: Josh Hope-Collins <jhc.jss@gmail.com>
|
Considering the discussion at the Firedrake meeting, the following commits rewrite |
1. `ParametrisedReducedFunctional` has been removed in favour of a `ReducedFunctional` that accepts `parameters` as an argument, along with a check to make sure either `derivative_components` or `parameters` is passed, but not both simultaneously. 2. If `parameters` is passed, a new `ReducedFunctional` object is created recursively. Methods will check if the `parameters` attribute is present to branch out their implementation. 3. Derivative callback include a `parameters` argument in their signature.
…est to validate initialization of `ReducedFunctional` with either `derivative_components` or `parameters`
|
@JHopeCollins, with respect to the recent CI failure: @no_annotations
def derivative(self, adj_input=1.0, apply_riesz=False):
values = [c.tape_value() for c in self.controls]
> controls = self.derivative_cb_pre(self.parameters if hasattr(self, "_parameters") else None, self.controls)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E TypeError: EnsembleReducedFunctional.<lambda>() takes 1 positional argument but 2 were givenThis happens because the derivative callback now has the signature |
If the user has not passed parameters then we shouldn't change the callback interface otherwise we will break current code before the deprecation cycle is done. For now the callback signature will depend on whether parameters are passed or not. |
Current method to use parameters
The
derivative_componentsoptional argument ofReducedFunctionalis used after adding parameters to the list of controls, to specify which components are to be zeroed out (by omitting them fromderivative_components). This allows the user to update parameters by calling the Reduced Functional while zeroing out the gradient with respect to the parameters.Parametrised Reduced Functional
ParametrisedReducedFunctionalis a subclass ofReducedFunctionalwith wrappingcallandderivativemethods, with the parameters as attributes. Theparameter_updatemethod is called to update parameters. The parameters are not included in the derivative calculation and the optional argumentderivative_componentsis not required.