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

random scalarization - part 1 #689

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft

random scalarization - part 1 #689

wants to merge 2 commits into from

Conversation

hstojic
Copy link
Collaborator

@hstojic hstojic commented Feb 3, 2023

this PR implements Random scalarization acquisition builder and function, interface for scalarization functions and one example of a scalarization function

part 2 will follow with a notebook
part 3 will follow with some functions for adaptive ideal points (and possible 1-2 more scalarization functions)

still at a draft stage to collect opinions on the design
(tests are missing and docs are not ironed out)

main questions about the design:

  • I went with a dict of models approach to combine trajectories instead of a model stack, but its a bit inconsistent with the rest of multi-objective code, I kinda like the dict approach, but don't have a strong preference and we could use a model stack I guess (we would need a new type of model stack for trajectories I think, similar to HasReparamSamplerModelStack)
  • I have separated the random scalarization from scalarization functions themselves, as we could have many forms of scalarizations - since they can be quite complex, they are objects. As a result random_scalarization is more of a container, most of the work is done by Scalarizer. Not sure what's the best approach here, perhaps we should integrate the scalarizer in the random_scalarization , but then it might be more difficult to use a different scalarization function. I'm also not sure how this separation affects retracing.

@vpicheny @uri-granta @henrymoss any thoughts on these?

Copy link
Collaborator

@uri-granta uri-granta left a comment

Choose a reason for hiding this comment

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

Looks good. Some initial comments. Will obviously need more tests before it can be checked in.

from trieste.types import Tag, TensorType


IdealSpecCallable = Callable[..., TensorType]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not make this precise?

Suggested change
IdealSpecCallable = Callable[..., TensorType]
IdealSpecCallable = Callable[[Mapping[Tag, HasTrajectorySampler], datasets: Mapping[Tag, Dataset]], TensorType]

ideal = tf.cast(self._ideal_spec(models, datasets), dtype=dtype)
else:
ideal = tf.cast(self._ideal_spec, dtype=dtype)
tf.debugging.assert_shapes([(ideal, (self._num_objectives, 1))])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add a message?

def _get_ideal(
self, models: Mapping[Tag, HasTrajectorySampler], datasets: Mapping[Tag, Dataset]
) -> TensorType:
dtype = self._infer_dtype(datasets)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a bit clunky: e.g. what happens if datasets is empty, or has inconsistent dtypes, or if the dtype changes between calls? Can't we just insist that the ideal_spec returns the correct dtype?

If that's a problem, maybe:

  1. make _infer_dtype more resilient by giving an error if datasets is empty or inconsistent?
  2. save the dtype when you call prepare and check it hasn't changed in update?
  3. add a dtype parameter to _get_ideal like _sample_weights (or alternatively move the casting outside)?

) -> None:
"""
Generate all the internal variables on initialization. For example, weights in a linear
weighted sum scalarization could be sampled.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Docstring should mention parameters

return (
f"Chebyshev({self._batch_size!r},"
f"{self._num_objectives!r},"
f"{self._ideal_spec.__name__},"
Copy link
Collaborator

Choose a reason for hiding this comment

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

You could easily remove the code duplication if you want:

Suggested change
f"{self._ideal_spec.__name__},"
+ (f"{self._ideal_spec.__name__}," if callable(self._ideal_spec) else f"{self._ideal_spec!r},") +

self, models: Mapping[Tag, HasTrajectorySampler], datasets: Mapping[Tag, Dataset]
) -> None:
dtype = self._infer_dtype(datasets)
self._weights = tf.Variable( # pylint: disable=attribute-defined-outside-init
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm worried that this would create tensorflow compilation issues, if the variables don't exist straight after initialisation. I think elsewhere we've initialised similar variables to dummy values, and (if need be) tracked initialisation with a self._initialized = tf.Variable(False) variable.


self._scalarizer.prepare(models, datasets)

self._trajectory_sampler = { # pylint: disable=attribute-defined-outside-init
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is less likely to cause issues than the attribute-defined-outside-init Variables below, but would still be nice to initialise these to empty dicts and update them in place here. Similarly, you should declare self._negated_trajectory as an Optional[TrajectorySampler] and initialise it to None.

-3.2095,
id="BatchMonteCarloExpectedHypervolumeImprovement/4",
),
# pytest.param(
Copy link
Collaborator

Choose a reason for hiding this comment

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

You probably don't want to check this in :-)

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