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

Clarify API for GP approximations #361

Merged
merged 17 commits into from
May 8, 2023
Merged

Clarify API for GP approximations #361

merged 17 commits into from
May 8, 2023

Conversation

st--
Copy link
Member

@st-- st-- commented Apr 25, 2023

Summary
AbstractGPs.jl should define the API we expect across the ecosystem. Currently, this is not the case for GP approximations, even though they're already introduced in this package (VFE for sparse GPR).

Proposed changes
Expose posterior and approx_log_evidence as part of the API with nice generic docstrings explaining their purpose.

Related issues
Resolves #221

Also see #223, #241, #318, maybe #319

What alternatives have you considered?
Status quo: some definitions in ApproximateGPs.jl, but people not realizing that you could just use a three-parameter form for posterior, leading to more reimplementation of base FiniteGPs than would be necessary (e.g. https://github.com/SebastianCallh/IterGP.jl/blob/AbstractGPs-interface/src/gp.jl)

@codecov
Copy link

codecov bot commented Apr 25, 2023

Codecov Report

Patch coverage: 87.50% and project coverage change: -0.74 ⚠️

Comparison is base (3e5f0a5) 97.63% compared to head (501b702) 96.89%.

❗ Current head 501b702 differs from pull request most recent head f260171. Consider uploading reports for the commit f260171 to get more accurate results

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #361      +/-   ##
==========================================
- Coverage   97.63%   96.89%   -0.74%     
==========================================
  Files          10       10              
  Lines         380      387       +7     
==========================================
+ Hits          371      375       +4     
- Misses          9       12       +3     
Impacted Files Coverage Δ
src/abstract_gp.jl 100.00% <ø> (ø)
src/exact_gpr_posterior.jl 92.50% <0.00%> (-7.50%) ⬇️
src/sparse_approximations.jl 100.00% <100.00%> (ø)

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@Crown421
Copy link
Member

Should there be an AbstractGPApproximation type or so? That other packages can/ should use?

src/sparse_approximations.jl Outdated Show resolved Hide resolved
src/sparse_approximations.jl Outdated Show resolved Hide resolved
src/sparse_approximations.jl Outdated Show resolved Hide resolved
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@st--
Copy link
Member Author

st-- commented Apr 25, 2023

Should there be an AbstractGPApproximation type or so? That other packages can/ should use?

Hm... where would that be useful? Is there anything that you would be able to do with any approximation, without knowing what approximation it is (i.e. it'd be necessary as a common base type in the hierarchy)? Or just as a "type hint" (i.e. it might be better to just improve the docs)?

@st--
Copy link
Member Author

st-- commented Apr 25, 2023

Open question from #221 (comment):

should we add a struct ExactGP end "approximation" type to support a consistent API regardless of whether one is using exact GPR or a sparse approximation such as VFE/DTC?

@Crown421
Copy link
Member

Open question from #221 (comment):

should we add a struct ExactGP end "approximation" type to support a consistent API regardless of whether one is using exact GPR or a sparse approximation such as VFE/DTC?

I think this makes sense to me, with appropriate aliases for the current two argument form.

Re the above, I was thinking about a type hint, need to think about whether such a type might also be useful elsewhere.

@st-- st-- requested review from theogf and willtebbutt April 25, 2023 16:03
@Crown421
Copy link
Member

Crown421 commented Apr 25, 2023

One way I can think of where a AbstractApproximation type might be useful in starting a more general hierarchy.
Next level down would be the methods mentioned here: JuliaGaussianProcesses/ApproximateGPs.jl#84, might be some supertype of VFE, DTC (possibly others in the future like FITC)

@@ -3,6 +3,12 @@ struct PosteriorGP{Tprior,Tdata} <: AbstractGP
data::Tdata
end

struct ExactGP end

posterior(::ExactGP, fx::FiniteGP, y::AbstractVector{<:Real}) = posterior(fx, y)
Copy link
Member

Choose a reason for hiding this comment

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

I would have gone the other way around?

But maybe that's too complicated...

Copy link
Member

Choose a reason for hiding this comment

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

I find this order of arguments quite intuitive.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry I meant that the implemented definition would be posterior(::ExactPosterior, gp, y) and that posterior(gp, y) would default to it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it make any difference in practice? (I kinda like it as it is but that might just be status-quo bias too...)

Copy link
Member

Choose a reason for hiding this comment

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

In practice I think the answer is no.
Within the code, there might be something to be said for consistency. Every posterior is defined with the 3-argument form, but the exact one gets a special alias.

Copy link
Member

Choose a reason for hiding this comment

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

To be fair, there is only one posterior. Shouldn't VFE and DTC dispatched on approx_posterior?

Copy link
Member Author

Choose a reason for hiding this comment

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

@theogf what do you mean? there is no approx_posterior method..

Copy link
Member

Choose a reason for hiding this comment

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

haha somehow in my mind there was a approx_posterior method. So yeah then it's back to

  • Should we have a unique 3-args posterior API (where the 2-args default to ExactInference) ?
  • Should we just have 2-args methods and have the GP wrapped (like in ApproximateGPs) ?

Copy link
Member Author

Choose a reason for hiding this comment

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

ApproximateGPs has the 3-args posterior though, no wrapping?

src/sparse_approximations.jl Outdated Show resolved Hide resolved
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
"""
DTC(fz::FiniteGP)

Similar to `VFE`, but uses a different objective for `approx_log_evidence`.
Copy link
Member Author

Choose a reason for hiding this comment

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

Could maybe do with a better docstring but then it needs to be sorted out more thoroughly anyways (see #309) and I can't think of what it should be right now, so would leave that for some other PR/person/time...

Comment on lines +86 to +101
@testset "approx_log_evidence" begin
x = collect(Float64, range(-1.0, 1.0; length=N_cond))
f = GP(SqExponentialKernel())
fx = f(x, 0.1)
y = rand(rng, fx)

# Ensure that the elbo/dtc objective is close to the logpdf when appropriate.
@test approx_log_evidence(ApproxType(f(x)), fx, y) isa Real
@test approx_log_evidence(ApproxType(f(x)), fx, y) ≈ logpdf(fx, y)

if ApproxType === VFE
@test elbo(ApproxType(f(x)), fx, y) ==
approx_log_evidence(ApproxType(f(x)), fx, y)
@test elbo(ApproxType(f(x .+ randn(rng, N_cond))), fx, y) < logpdf(fx, y)
end
end
Copy link
Member Author

Choose a reason for hiding this comment

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

this is the main change

@st--
Copy link
Member Author

st-- commented Apr 27, 2023

Hello! What do you think needs doing/addressing/... before merging this ?

Comment on lines +174 to +179
_update_approx(f_post_approx.approx, fz_new), f_post_approx.prior, cache
)
end

_update_approx(vfe::VFE, fz_new::FiniteGP) = VFE(fz_new)
_update_approx(dtc::DTC, fz_new::FiniteGP) = DTC(fz_new)
Copy link
Member Author

Choose a reason for hiding this comment

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

is this the right way to handle this? if anyone can think of a better approach please say:)

@st-- st-- requested a review from theogf April 28, 2023 07:17
src/exact_gpr_posterior.jl Outdated Show resolved Hide resolved
src/exact_gpr_posterior.jl Outdated Show resolved Hide resolved
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

Add API for (log) marginal likelihood approximation
5 participants