Hi,
to get into Julia I started implementing different machine learning algorithms.
Last night i implemented a GP just to see how that would work.
Here’s the code so far:
using LinearAlgebra, Random, Distributions
using Zygote
using PyPlot
mutable struct GP
θ::Dict
X::Array{Float64}
y::Array{Float64}
end
function rbf_kernel(x::Array{Float64}, y::Array{Float64}, lengthscale::Float64)
@assert lengthscale>0.
x = x[:, [CartesianIndex()],:]
y = y[[CartesianIndex()],:,:]
diff = (x .- y).^2
diff = sum(diff,dims=3)[:,:]
kernel = exp.(-1/lengthscale*diff)
end
function predictive_dist(Xs::Array{Float64,1}, gp::GP)
lengthscale = softplus.(gp.θ[:log_lengthscale])
noise = softplus.(gp.θ[:log_noise])
kxx = rbf_kernel(gp.X, gp.X, lengthscale) + 0.00001*I(size(X)[1])
kxxs = rbf_kernel(gp.X, Xs, lengthscale)
kxsxs = rbf_kernel(Xs, Xs, lengthscale)
μ = transpose(kxxs)*inv(kxx+noise*I(size(X)[1]))*y
Σ = kxsxs - transpose(kxxs)*inv(kxx+noise*I(size(X)[1]))*kxxs #+ θ[:noise_std]*I(size(Xs)[1])
return μ, diag(Σ)
end
function generate_data(_num_samples::Int64=75, _plot::Bool=false)
x = LinRange(-0.35, 0.55, _num_samples)
x_noise = rand(Normal(0, 0.01), size(x))
y_noise = rand(Normal(0, 0.2), size(x))
y = x + 0.3sin.(2pi*(x+x_noise)) + 0.3sin.(4pi*(x+x_noise)) + y_noise
if _plot
scatter(y)
end
return collect(x), collect(y)
end
function plot_predictive_dist(Xs::Array{Float64,1}, gp::GP)
μ, σ = predictive_dist(Xs, gp)
fig = figure(figsize=(10,10))
grid()
plot(Xs, μ, label="μ")
scatter(X, y, label="data points")
fill_between(Xs, μ.-3σ, μ.+3σ, alpha=0.3)
display(fig)
end
function softplus(in::Float64)
log.(1 .+ exp.(in)) + 0.01
end
function marginal_dist(gp::GP)
noise = softplus.(gp.θ[:log_noise])
lengthscale = softplus.(gp.θ[:log_lengthscale])
@show noise, lengthscale
kxx = rbf_kernel(gp.X, gp.X, lengthscale) + noise*I(size(X)[1])
kxx_inv = inv(kxx)
first = logdet(kxx)
second = gp.y'*kxx_inv*gp.y
loss = first + second #- 1/(2*noise^2)*tr(rbf_kernel(gp.X, gp.X, lengthscale))
end
Xs = collect(LinRange(-1., 1., 200))
X, y = generate_data()
θ = Dict(:log_lengthscale => log(0.1), :log_noise => log(1.1))
gp = GP(θ, X, y)
plot_predictive_dist(Xs, gp)
loss = marginal_dist(gp)
grad = gradient(gp -> marginal_dist(gp), gp)[1]
Unfortunately I’m getting a ‘Can’t differentiate foreigncall expression’ error when taking the gradient with Zygote and I have absolutely no idea what that’s supposed to mean.
Googling revealed close to zero information on this error.
Could anybody help me out?
Thank you in advance for your time. =)