I am currently evaluating Zygote. My “usecase” is maybe a bit different from what has driven Zygote’s development: I want to take the gradient of scalar-valued functions of 10 to 100 inputes, but I will compute millions of such gradients.
So my functions must not allocate [on the heap] and I am a keen user of StaticArrays. Here is a little benchmark:
using Zygote,StaticArrays,BenchmarkTools
struct MyType
a :: Float64
b :: SVector{2,Float64}
c :: Float64
d :: SVector{2,Int64}
end
function foo(o::MyType, δX,X,U,A, t)
δW = (δX[o.d]' * o.b) * (o.a + A[1])
δW += δX[3 ] * -(o.c+A[2])
return δW
end
el = MyType(3e3,SVector(10.,0), -1e4,SVector(1,2))
δX,X,U,A = SVector(1.,1,1), SVector(1.,2,3), SVector(), SVector(0.,0)
@btime foo($el, $δX,$X,$U,$A,0.)
> 1.300 ns (0 allocations: 0 bytes)
@btime Lδx,Lx,Lu,La = gradient(δX,X,U,A) do δX,X,U,A
foo($el, δX,X,U,A,0.)
end
> 2.444 μs (48 allocations: 7.27 KiB)
@show typeof.((Lδx,Lx,Lu,La))
> typeof.((Lδx, Lx, Lu, La)) = (SizedVector{3, Float64, Vector{Float64}}, Nothing, Nothing, SizedVector{2, Float64, Vector{Float64}})
I have several questions, quite possibly related.
-
While on a simple example (not included), I manage to get Zygote to provide me with
SVector
gradient, here I getSizedVector
- which as I understand it, go on the heap. (Nothing
is OK, the test includes edgecases). Why does “gradient(foo)” not return Static Arrays? -
Indeed the gradient computation does quite a bit of allocation, and is quite slow. Unfortunately, I find that also to be the case in my simpler example (not included). Is that a consequence of 1) and 2), or (I fear) just part of the deal with Zygote, which is efficient for larger numbers of parameters?