EnzymeAD / Enzyme.jl

Julia bindings for the Enzyme automatic differentiator
https://enzyme.mit.edu
MIT License
437 stars 62 forks source link

Unexpected result when function doesn't return nothing #1363

Closed jbrea closed 3 months ago

jbrea commented 5 months ago
julia> function f1!(res, x)
           res[1] = sum(abs2, x)
       end
f1! (generic function with 1 method)

julia> function f2!(res, x)
           res[1] = sum(abs2, x)
           nothing
       end
f2! (generic function with 1 method)

julia> x = rand(3)
3-element Vector{Float64}:
 0.25636315689588907
 0.36803540982615546
 0.4789773718050756

julia> dx1 = zero(x);

julia> dx2 = zero(x);

julia> autodiff(Reverse, f1!, Duplicated([0.], [1.]), Duplicated(x, dx1))
((nothing, nothing),)

julia> autodiff(Reverse, f2!, Duplicated([0.], [1.]), Duplicated(x, dx2))
((nothing, nothing),)

julia> [dx1 dx2]
3×2 Matrix{Float64}:
 1.02545  0.512726
 1.47214  0.736071
 1.91591  0.957955

julia> dx1 == 2dx2
true

dx2 is the correct result. Is there a way to warn the user. if the function doesn't return nothing?

This is with Enzyme v0.11.19 and julia 1.10.2.

vchuravy commented 5 months ago

Enzyme is trying to automatically determine the activity of the return argument. Since you are returning a Float64 the return is set to Active, and an automatic 1.0 is used as the differential return.

You can set the activity of the return to Const instead.

jbrea commented 5 months ago

Thanks. Yes,

autodiff(Reverse, f1!, Const, Duplicated([0.], [1.]), Duplicated(x, dx1))

gives the expected result. Wouldn't it be better if

autodiff(Reverse, f1!, Duplicated([0.], [1.]), Duplicated(x, dx1))

wouldn't exist, such that the user always has to specify, if the return is active or not?

wsmoses commented 5 months ago

This is a design decision. The automatic activity deduction makes it easier for folks to use autodiff (e.g. just using on sin), which already gets complaints about it being more difficult than other utilities so I'm hesitant to do so.

wsmoses commented 4 months ago

cc @gdalle for design thoughts

gdalle commented 4 months ago

Yeah it's a tough one. Ultimately it's about understanding which adjoints get propagated where. I have wanted to add something like https://discourse.julialang.org/t/do-i-understand-enzyme-properly/97760 to the docs for a while, maybe it would help?

wsmoses commented 4 months ago

Yeah I think more docs are definitely needed/helpful

wsmoses commented 3 months ago

In any case closing as nothing inside enzyme was erring