# 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)
``````

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?

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() do