Zygote foreigncall expression error

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. =)

Ok found the problem: You can’t use @show inside a the function you’re taking the gradient of.
So just leave out the @show.

This is the relevant issue, BTW: https://github.com/FluxML/Zygote.jl/issues/386

1 Like

I think supporting @show is not as hard as supporting @info. For example, supporting @time was quite simple: https://github.com/FluxML/Zygote.jl/pull/351

Also, as a workaround, I think you can use something like

nograd(f) = f()
@nograd nograd

and then

nograd() do
    @show noise, lengthscale
end