Zygote.jl icon indicating copy to clipboard operation
Zygote.jl copied to clipboard

Error from second derivative with non-const global

Open NiklasGustafsson opened this issue 3 years ago • 4 comments

Should I expect this to work?

julia> b = 5
5

julia> Zygote.refresh()

julia> f(x) = 4*x^2 + b*x + 10

julia> f'(25)
210.0

julia> g = f'
#59 (generic function with 1 method)

julia> g'(25)
ERROR: Can't differentiate foreigncall expression
Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:33
  [2] Pullback
    @ .\iddict.jl:102 [inlined]
  [3] (::typeof(∂(get)))(Δ::Nothing)
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface2.jl:0
  [4] Pullback
    @ C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\lib\lib.jl:68 [inlined]
  [5] (::typeof(∂(accum_global)))(Δ::Nothing)
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface2.jl:0
  [6] Pullback
    @ C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\lib\lib.jl:79 [inlined]
  [7] (::typeof(∂(λ)))(Δ::Nothing)
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface2.jl:0
  [8] Pullback
    @ C:\Users\niklasg\.julia\packages\ZygoteRules\AIbCs\src\adjoint.jl:67 [inlined]
  [9] (::typeof(∂(λ)))(Δ::Nothing)
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface2.jl:0
 [10] Pullback
    @ .\REPL[2]:1 [inlined]
 [11] (::typeof(∂(λ)))(Δ::Tuple{Nothing, Float64})
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface2.jl:0
 [12] Pullback
    @ C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface.jl:41 [inlined]
 [13] (::typeof(∂(λ)))(Δ::Tuple{Float64})
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface2.jl:0
 [14] Pullback
    @ C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface.jl:83 [inlined]
 [15] (::typeof(∂(#59)))(Δ::Float64)
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface2.jl:0
 [16] (::Zygote.var"#57#58"{typeof(∂(#59))})(Δ::Float64)
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface.jl:41
 [17] (::Zygote.var"#59#60"{Zygote.var"#59#60"{typeof(f)}})(x::Int64)
    @ Zygote C:\Users\niklasg\.julia\packages\Zygote\cCyLF\src\compiler\interface.jl:83
 [18] top-level scope
    @ REPL[7]:1

NiklasGustafsson avatar Mar 09 '22 00:03 NiklasGustafsson

In principle, yes. In reality, less reliably than first derivatives.

Can you post the stack trace?

mcabbott avatar Mar 09 '22 05:03 mcabbott

I edited the original post to include the stack trace.

NiklasGustafsson avatar Mar 09 '22 13:03 NiklasGustafsson

For some reason it's tripping over the non-const global b. If you avoid that (which you probably should anyway -- which may be why nobody saw the bug) then it works:

julia> f2(x, b2=5) = 4*x^2 + b2*x + 10
f2 (generic function with 2 methods)

julia> g2 = f2'; g2'(25)
8.0

julia> const bc = 5; f3(x) = 4*x^2 + bc*x + 10
f3 (generic function with 1 method)

julia> g3 = f3'; g3'(25)
8.0

Notice that the gradient is (Δ::Nothing) in the stack trace. So it knows it doesn't need to go down this path, but somehow does? \src\lib\lib.jl:79 is https://github.com/FluxML/Zygote.jl/blob/master/src/lib/lib.jl#L79 accum_global(__context__, ref, x̄), which looks like it should call https://github.com/FluxML/Zygote.jl/blob/master/src/lib/lib.jl#L66 which tests x̄ === nothing. But doesn't?

mcabbott avatar Mar 09 '22 16:03 mcabbott

@mcabbott: Yes, the non-const 'b' was actually why I asked whether it was expected to work.

NiklasGustafsson avatar Mar 09 '22 16:03 NiklasGustafsson