Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ jobs:
matrix:
version:
- '1'
- '1.6'
- 'nightly'
os:
- ubuntu-latest
Expand All @@ -28,12 +27,12 @@ jobs:
arch: x64
coverage: true
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: actions/cache@v1
- uses: actions/cache@v5
env:
cache-name: cache-artifacts
with:
Expand Down
57 changes: 24 additions & 33 deletions .github/workflows/DocNav.yml
Original file line number Diff line number Diff line change
@@ -1,49 +1,40 @@
name: Add Navbar
name: Rebuild docs with newest navbar

on:
page_build: # Triggers the workflow on push events to gh-pages branch
workflow_dispatch: # Allows manual triggering
# 3:25 AM UTC every Sunday -- choose an uncommon time to avoid
# periods of heavy GitHub Actions usage
schedule:
- cron: '0 0 * * 0' # Runs every week on Sunday at midnight (UTC)
- cron: '25 3 * * 0'
# Whenever needed
workflow_dispatch:

permissions:
contents: write

jobs:
add-navbar:
update-navbar:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout gh-pages
uses: actions/checkout@v4
- name: Checkout gh-pages branch
uses: actions/checkout@v6
with:
ref: gh-pages
fetch-depth: 0

- name: Download insert_navbar.sh
run: |
curl -O https://raw.githubusercontent.com/TuringLang/turinglang.github.io/main/assets/scripts/insert_navbar.sh
chmod +x insert_navbar.sh
- name: Insert navbar
uses: TuringLang/actions/DocsNav@main
with:
doc-path: '.'
navbar-url: https://raw.githubusercontent.com/JuliaGaussianProcesses/.github/refs/heads/main/DocumenterNavbar/JuliaGPNavbar.html

- name: Update Navbar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit and push changes
run: |
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com

# Define the URL of the navbar to be used
NAVBAR_URL="https://raw.githubusercontent.com/TuringLang/turinglang.github.io/main/assets/scripts/JuliaGPNavbar.html"

# Update all HTML files in the current directory (gh-pages root)
./insert_navbar.sh . $NAVBAR_URL

# Remove the insert_navbar.sh file
rm insert_navbar.sh

# Check if there are any changes
if [[ -n $(git status -s) ]]; then
git add .
git commit -m "Added navbar and removed insert_navbar.sh"
git push "https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" gh-pages
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com
git add -A
git commit -m "Update navbar (automated)"
git push
else
echo "No changes to commit"
fi
30 changes: 18 additions & 12 deletions .github/workflows/Docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,27 @@ on:
- master
tags: '*'
pull_request:
workflow_dispatch:

concurrency:
# Skip intermediate builds: always.
# Cancel intermediate builds: only if it is a pull request build.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}

permissions:
contents: write
pull-requests: write

jobs:
build:
docs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: '1.6'
- name: Install dependencies
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
- name: Build and deploy
- name: Build and deploy Documenter.jl docs
env:
GKSwstype: nul # turn off GR's interactive plotting for notebooks
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # If authenticating with GitHub Actions token
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # If authenticating with SSH deploy key
JULIA_DEBUG: Documenter # Print `@debug` statements (https://github.com/JuliaDocs/Documenter.jl/issues/955)
run: julia --project=docs/ docs/make.jl
uses: TuringLang/actions/DocsDocumenter@main
with:
julia-version: '1'
navbar-url: https://raw.githubusercontent.com/JuliaGaussianProcesses/.github/refs/heads/main/DocumenterNavbar/JuliaGPNavbar.html
2 changes: 1 addition & 1 deletion .github/workflows/DocsPreviewCleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v2
uses: actions/checkout@v6
with:
ref: gh-pages
- name: Delete preview and history + push changes
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/Format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v6
- uses: julia-actions/setup-julia@latest
with:
version: 1
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ PDMats = "0.11"
Reexport = "1"
SpecialFunctions = "1, 2"
StatsBase = "0.33, 0.34"
julia = "1.6"
julia = "1"
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"

[compat]
ApproximateGPs = "0.3,0.4"
Documenter = "0.27"
Documenter = "1"
15 changes: 8 additions & 7 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ using JuliaGPsDocs

using ApproximateGPs

JuliaGPsDocs.generate_examples(ApproximateGPs)
JuliaGPsDocs.generate_examples(ApproximateGPs; ntasks=1)

### Build documentation
using Documenter
Expand All @@ -23,19 +23,20 @@ DocMeta.setdocmeta!(

makedocs(;
sitename="ApproximateGPs.jl",
format=Documenter.HTML(),
format=Documenter.HTML(;
size_threshold_ignore=[
"examples/a-regression/index.md",
"examples/b-classification/index.md",
"examples/c-comparisons/index.md",
],
),
modules=[ApproximateGPs],
pages=[
"Home" => "index.md",
"userguide.md",
"API" => joinpath.(Ref("api"), ["index.md", "sparsevariational.md", "laplace.md"]),
"Examples" => JuliaGPsDocs.find_generated_examples(ApproximateGPs),
],
strict=true,
checkdocs=:exports,
doctestfilters=JuliaGPsDocs.DOCTEST_FILTERS,
)

deploydocs(;
repo="github.com/JuliaGaussianProcesses/ApproximateGPs.jl.git", push_preview=true
)
3 changes: 3 additions & 0 deletions examples/a-regression/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"

[compat]
Flux = "0.14, 0.15, 0.16"
10 changes: 5 additions & 5 deletions examples/a-regression/script.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ struct SVGPModel
A # square-root of variational covariance
end

Flux.@functor SVGPModel (k, z, m, A);
Flux.@layer SVGPModel trainable=(k, z, m, A)

# Set the observation noise for our model, along with a `jitter` term
# to help with numerical stability.
Expand Down Expand Up @@ -167,15 +167,14 @@ plot!(-1:0.001:1, init_post; label="Initial Posterior", color=4)
#
# Training the model now simply proceeds with the usual `Flux.jl` training loop.

opt = ADAM(0.001) # Define the optimiser
params = Flux.params(model); # Extract the model parameters
opt = Flux.Adam(0.001)

# One of the major advantages of the SVGP model is that it allows stochastic
# estimation of the ELBO by using minibatching of the training data. This is
# very straightforward to achieve with `Flux.jl`'s utilities:

b = 100 # minibatch size
data_loader = Flux.Data.DataLoader((x, y); batchsize=b)
data_loader = Flux.DataLoader((x, y); batchsize=b)

# The loss (negative ELBO) before training

Expand All @@ -186,12 +185,13 @@ loss(model, x, y)

using IterTools: ncycle

params = Flux.params(model)
Flux.train!(
(x, y) -> loss(model, x, y; num_data=N),
params,
ncycle(data_loader, 300), # Train for 300 epochs
opt,
);
)

# Negative ELBO after training

Expand Down
37 changes: 20 additions & 17 deletions src/LaplaceApproximationModule.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,18 +183,19 @@ struct LaplaceCache{
Tv1<:AbstractVector,
Tv2<:AbstractVector,
Tv3<:AbstractVector,
Td<:Diagonal,
Tv4<:AbstractVector,
Tv5<:AbstractVector,
Tf<:Real,
Tc<:Cholesky,
}
K::Tm # kernel matrix
f::Tv1 # mode of posterior p(f | y)
W::Td # diagonal matrix of ∂²/∂fᵢ² loglik
Wsqrt::Td # sqrt(W)
W::Tv2 # diagonal of -∂²/∂fᵢ² loglik
Wsqrt::Tv3 # sqrt.(W)
loglik::Tf # ∑ᵢlog p(yᵢ|fᵢ)
d_loglik::Tv2 # ∂/∂fᵢloglik
B_ch::Tc # cholesky(I + Wsqrt * K * Wsqrt)
a::Tv3 # K⁻¹ f
d_loglik::Tv4 # ∂/∂fᵢloglik
B_ch::Tc # cholesky(I + Diagonal(Wsqrt) * K * Diagonal(Wsqrt))
a::Tv5 # K⁻¹ f
end

function _laplace_train_intermediates(dist_y_given_f, ys, K, f)
Expand All @@ -209,12 +210,12 @@ function _laplace_train_intermediates(dist_y_given_f, ys, K, f)
ll, d_ll, d2_ll = loglik_and_derivs(dist_y_given_f, ys, f)

# inner loop iteration of RW Algorithm 3.1, lines 4-7
W = -Diagonal(d2_ll)
Wsqrt = sqrt(W)
B = I + Wsqrt * K * Wsqrt
W = -d2_ll
Wsqrt = sqrt.(W)
B = I + (Wsqrt .* K) .* Wsqrt'
B_ch = cholesky(Symmetric(B))
b = W * f + d_ll
a = b - Wsqrt * (B_ch \ (Wsqrt * K * b))
b = W .* f .+ d_ll
a = b - Wsqrt .* (B_ch \ (Wsqrt .* (K * b)))

#return (; K, f, W, Wsqrt, loglik=ll, d_loglik=d_ll, B_ch, a)
return LaplaceCache(K, f, W, Wsqrt, ll, d_ll, B_ch, a)
Expand Down Expand Up @@ -321,7 +322,7 @@ function ChainRulesCore.frule(
# fdot = (I - K grad2_log_p_y_given_f(f))⁻¹ Kdot grad_log_p_y_given_f(f)
# (I - K grad2_log_p_y_given_f(f)) = (I + K W) = (√W)⁻¹ (I + √W K √W) √W = (√W)⁻¹ B √W
# fdot = (√W)⁻¹ B⁻¹ √W Kdot grad_log_p_y_given_f(f)
∂f_opt = cache.Wsqrt \ (cache.B_ch \ (cache.Wsqrt * (ΔK * cache.d_loglik)))
∂f_opt = (cache.B_ch \ (cache.Wsqrt .* (ΔK * cache.d_loglik))) ./ cache.Wsqrt

return f_opt, ∂f_opt
end
Expand Down Expand Up @@ -357,7 +358,9 @@ function ChainRulesCore.rrule(::typeof(newton_inner_loop), dist_y_given_f, ys, K
)

# ∂K = df/dK Δf
∂K = @thunk(cache.Wsqrt * (cache.B_ch \ (cache.Wsqrt \ Δf_opt)) * cache.d_loglik')
∂K = @thunk(
(cache.Wsqrt .* (cache.B_ch \ (Δf_opt ./ cache.Wsqrt))) * cache.d_loglik'
)

return (∂self, ∂dist_y_given_f, ∂ys, ∂K)
end
Expand All @@ -379,7 +382,7 @@ function laplace_f_cov(cache)
# = (√W⁻¹) (I - (I + √W K √W)⁻¹) (√W⁻¹)
# = (√W⁻¹) (I - B⁻¹) (√W⁻¹)
B_ch = cache.B_ch
Wsqrt_inv = inv(cache.Wsqrt)
Wsqrt_inv = Diagonal(inv.(cache.Wsqrt))
return Wsqrt_inv * (I - inv(B_ch)) * Wsqrt_inv
end

Expand Down Expand Up @@ -423,7 +426,7 @@ function _laplace_predict_intermediates(cache, prior_at_x, xnew)
k_x_xnew = cov(prior_at_x.f, prior_at_x.x, xnew)
f_mean = mean(prior_at_x.f, xnew) + k_x_xnew' * cache.d_loglik # RW (3.21)
L = cache.B_ch.L
v = L \ (cache.Wsqrt * k_x_xnew) # RW (3.29)
v = L \ (cache.Wsqrt .* k_x_xnew) # RW (3.29)
return f_mean, v
end

Expand Down Expand Up @@ -454,8 +457,8 @@ end

function Statistics.cov(f::LaplacePosteriorGP, x::AbstractVector, y::AbstractVector)
L = f.data.B_ch.L
vx = L \ (f.data.Wsqrt * cov(f.prior.f, f.prior.x, x))
vy = L \ (f.data.Wsqrt * cov(f.prior.f, f.prior.x, y))
vx = L \ (f.data.Wsqrt .* cov(f.prior.f, f.prior.x, x))
vy = L \ (f.data.Wsqrt .* cov(f.prior.f, f.prior.x, y))
return cov(f.prior.f, x, y) - vx' * vy
end

Expand Down
3 changes: 2 additions & 1 deletion src/TestUtils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ using ApproximateGPs

function generate_data()
X = range(0, 23.5; length=48)
# The random number generator changed in 1.6->1.7. The following vector was generated in Julia 1.6.
# The random number generator changed across older Julia releases. The following vector
# was generated before that change to keep this test stable across supported versions.
# The generating code below is only kept for illustrative purposes.
#! format: off
Y = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
Expand Down
Loading
Loading