I’m working on radio telescope imaging and am trying to do image reconstruction with an iterative, maximum entropy method. Many papers suggest using conjugate gradient, and have intricate derivations of gradients. I thought it would be neat to do the same thing, but pushing the model through some sort of Autodiff.
In this process, I am needing to take samples of an interpolated FFT and calculate a mean squared error to measured radio telescope data.
Something like this
function vis_res(image, vis_data, uv)
# Generate interpolated visibilities from the image
N = length(vis_data)
image_fft = fft(image) |> fftshift
freqs = fftfreq(size(image)[1]) |> fftshift
interpolation = LinearInterpolation((freqs, freqs), image_fft)
vis_interp = [interpolation(uv[:,i]...) for i ∈ 1:N]
# Calculate visibility residuals
return (abs.(vis_interp .- vis_data)).^2
end
However, Flux/Zygote doesn’t seem to be happy with the indexing of the interpolation. Throwing the error:
ERROR: ArgumentError: unable to check bounds for indices of type Interpolations.WeightedAdjIndex{2, Float64}
Any help in this regard would be greatly appreciated.
Funny, I just ran into the same error. I’m trying to differentiate through a likelihood function that uses an interpolation using Zygote.
I expect the incompatibility is within the Interpolations library rather than the indexing you show. My likelihood function also calls a manual bi-linear interpolation function I wrote, and it has no issue with that as far as I can tell.
Yeah I dug in deep to this - and it actually does work on the current master branch of Interpolations, as the release hasn’t been bumped in a few months. There is still a strange indexing problem, stemming from strangeness in the dimensionality of the gradient. I solved my specific example by just providing an explicit gradient.
It would help to have a full stacktrace as well. As-is (having no knowledge of how interpolations works), I have no idea which line is even causing the error.
Looks like Interpolations didn’t gain AD support until after the latest release, so that makes sense Edit: saw you commented already on a linked issue :). Worth reporting an issue if you’re getting incorrect gradient values.
For those finding your way here from Google, the following function gives a bilinear interpolation over the axes of a matrix and is easily auto differentiable with Zygote and others. You should generally prefer the battle-tested Interpolations.jl implementations where you can, but this one works in a pinch.
function bilininterp(data::AbstractMatrix, x, y)
x1 = floor(Int,x)
x2 = ceil(Int,x)
y1 = floor(Int,y)
y2 = ceil(Int,y)
# Handle case of perfect grid alignment
if x1 == x2
x2 = x1 + 1
end
if y1 == y2
y2 = y1 + 1
end
# Handle boundary conditions
if x1 == 0
x1 += 1
x2 += 1
end
if y1 == 0
y1 += 1
y2 += 1
end
if x1 == size(data,1)
x1 -= 1
x2 -= 1
end
if y1 == size(data,2)
y1 -= 1
y2 -= 1
end
mat = [
1 x1 y1 (x1 * y1)
1 x1 y2 (x1 * y2)
1 x2 y1 (x2 * y1)
1 x2 y2 (x2 * y2)
]
# Get surrounding pixels if finite (fallback to image median otherwise)
col = [
data[x1, y1]
data[x1, y2]
data[x2, y1]
data[x2, y2]
]
# Solve the system of equations without inverting
coeffs = mat \ col
interp =
coeffs[1] + coeffs[2] * x + coeffs[3] * y + coeffs[4] * x * y
return interp
end