-
Notifications
You must be signed in to change notification settings - Fork 42
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
TrajectorySampler amenable to any Kernel/IndVar #606
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems ok in terms of the code, I haven't checked the maths, left some minor comments
more general notes:
- there are lots of if-else statements, I wonder if it would be a bit cleaner with kernel type dependent methods - perhaps @uri-granta has some suggestions here?
- you are missing unit tests for all of this...
P.S I don't know if it matters but gpflow is at the moment changing how heteroskedastic modeling is done
trieste/models/gpflux/sampler.py
Outdated
|
||
q_mu = self._layer.q_mu # [M, P] | ||
q_sqrt = self._layer.q_sqrt # [P, M, M] | ||
|
||
#NOTE -- I don't understand why in the original code this approach was used and not the gpflow.covariances.Kuu dispatcher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leave this as a comment for @sebastianober here in github rather than as a comment in the code :)
trieste/models/gpflux/sampler.py
Outdated
# Build the RFF objects | ||
if isinstance(self._kernel, list): | ||
|
||
self._rff = defaultdict() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you'll need to provide a type here most likely (see below), though not sure why you need defaultdict
here, it seems like you can simply do dict()
...
self._rff: DefaultDict[int, RFF] = defaultdict()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added it
thanks for the comments @hstojic , I will take care of adding unit tests now I don't think that the change in heteroskedastic modelling in GPflow would influence anything here since this is just TrajectorySampling. |
lengthscales = [2.0] * input_dim | ||
return SquaredExponential(lengthscales=lengthscales, variance=variance) | ||
|
||
def build_constant_input_dim_flexible_deep_gp(X: np.ndarray, num_layers: int, config: Config, separate_case: bool, output_dim: bool) -> DeepGP: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems like it should go to gpflux rather than being here in trieste, if its generally useful and not just for trieste needs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will probably move this architecture to tests..since that's the only place it will be ever used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great!
|
||
|
||
@dataclass | ||
class Config: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Config seems like a copy-paste, do we need to redefine it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no..it should just be an import
trieste/models/gpflux/builders.py
Outdated
Build a :class:`~gpflux.models.DeepGP` model with sensible initial parameters. We found the | ||
default configuration used here to work well in most situation, but it should not be taken as a | ||
universally good solution. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whats the key difference with the ohter builder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented a bit below
""" | ||
In this module, we test the *behaviour* of Trieste models against reference GPflux models (thus | ||
implicitly assuming the latter are correct). | ||
*NOTE:* Where GPflux models are used as the underlying model in an Trieste model, we should | ||
*not* test that the underlying model is used in any particular way. To do so would break | ||
encapsulation. For example, we should *not* test that methods on the GPflux models are called | ||
(except in the rare case that such behaviour is an explicitly documented behaviour of the | ||
Trieste model). | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this file an accident or there should be another test file for sampler?
trieste/models/gpflux/builders.py
Outdated
whiten=True, # whiten = False not supported yet in GPflux for this model | ||
) | ||
|
||
model = build_constant_input_dim_flexible_deep_gp(query_points, num_layers, config, True, dim_output) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hstojic this is the only difference..if you can think of a more efficient way of doing this, that would be grand
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you said you need build_constant_input_dim_flexible_deep_gp
only for the tests, meaning that the builder build_vanilla_flexible_deep_gp
is needed only for a test, right? you can then move the whole thing there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
otherwise there are indeed more efficient ways to do this, e.g. having a private function _build_deep_gp
which takes a function as an input, either build_constant_input_dim_flexible_deep_gp
or build_constant_input_dim_deep_gp
and then you have two public functions build_vanilla_flexible_deep_gp
and build_vanilla_deep_gp
that call the private one with these two different functions
…astian.p/trajectory_Sampler
class DeepGaussianProcessDecoupledLayer(ABC): | ||
""" | ||
Layer that samples an approximate decoupled trajectory for a GPflux | ||
:class:`~gpflux.layers.GPLayer` using Matheron's rule (:cite:`wilson2020efficiently`). Note | ||
that the only multi-output kernel that is supported is a | ||
:class:`~gpflow.kernels.SharedIndependent` kernel. | ||
:class:`~gpflux.layers.GPLayer` using Matheron's rule (:cite:`wilson2020efficiently`). | ||
Supports multi-output kernels of :class:`~gpflow.kernels.SharedIndependent` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this a layer rather than just a sampler?
] # [N, B, L + M, 1] | ||
|
||
|
||
# TODO -- probably have to re-write unflatten to accomodate for this case as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
feature_evaluations.append( | ||
unflatten(flattened_feature_evaluations[counter, :, :])[..., None] | ||
) # [N, B, L + M, 1] if Shared or [N, B, L + M, P] if separate | ||
# TODO -- check that this is acutally true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
# TODO -- check that this is acutally true | ||
feature_evaluations = tf.concat(feature_evaluations, axis=-1) | ||
|
||
# TODO -- should probably introduce a tf.debugging.assert_equal just to be sure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
""" | ||
Kmm = self._kernel.K(inducing_points, inducing_points) # [M, M] | ||
Kmm += tf.eye(tf.shape(inducing_points)[0], dtype=Kmm.dtype) * DEFAULTS.JITTER | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove?
tf.debugging.assert_shapes( | ||
[ | ||
(u_sample, ["B", "M", "P"]), | ||
] | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would be nicer with check shapes!
self._rff[counter].b.assign(self._rff[counter]._sample_bias(tf.shape(self._rff[ | ||
counter].b), dtype=self._rff[counter]._dtype)) | ||
self._rff[counter].W.assign(self._rff[counter]._sample_weights(tf.shape( | ||
self._rff[counter].W), dtype=self._rff[counter]._dtype)) | ||
else: | ||
self._rff[counter].b.assign(self._rff[counter]._bias_init(tf.shape(self._rff[ | ||
counter].b), dtype=self._rff[counter]._dtype)) | ||
self._rff[counter].W.assign(self._rff[counter]._weights_init(tf.shape(self._rff[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
# fourier_feature_eval = [] | ||
# for counter, ker in enumerate(self._kernel): | ||
# fourier_feature_eval.append(self._rff[counter].__call__(x)) # [N, L] | ||
|
||
# fourier_feature_eval = tf.stack(fourier_feature_eval, axis = 0) # [P, N, L] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this PR needs some tidying!
@sebastianober has made a different set of changes in gpflux to accomodate separate independent kernels, and made corresponding changes here in GPflux package, so I'll close this PR - but we cannot handle sep ind inducing variables, so we might need to return to this at some point |
Rewrite of Decoupled Trajectory Sampling such that it also works for
SeparateIndependent
kernels andSeparteIndependentInducingVariables
. The goal is to eventually use this for heteroskedastic likelihoods.